Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom blocks w/ Children #3

Open
lukeed opened this issue Jul 10, 2021 · 0 comments
Open

Custom blocks w/ Children #3

lukeed opened this issue Jul 10, 2021 · 0 comments

Comments

@lukeed
Copy link
Owner

lukeed commented Jul 10, 2021

There are two ways to do this:

Option A

Rely on the options.blocks key name(s) to decide whether or not a custom directive is "stateful" / will have a closing tag:

{{#section title="About Me"}}
  <p>Paragraph text</p>

  {{! inline, no-child directive }}
  {{#partial src="other.hbs" }}

  <p>Another paragraph</p>
{{/section}}
// usage
tempura.compile('...', {
  blocks: {
    // section opener
    '#section': args => {
      let txt = '<section>';
      if (args.title) txt += `<h2>${args.title}</h2>`;
      return txt;
    },

    // section closer
    '/section': () => '</section>',

    // does NOT expect children
    // ~> no "/partial" key
    '#partial': async args => {
      // ...
      return 'something';
    }
  }
});

With this approach, the tempura parse will infer whether or not it should expect a {{/NAME}} based on /NAME's existence in the options.block dictionary. In other words, defining a "/partial": args => {} in this example – without modifying the template – would throw:

Expected to close "partial" block; closed "section" instead

Option B

Rely on the template tag itself to determine if this block should be stateful.
Additionally, any stateful blocks would have to return string[] instead of string:

{{#section title="About Me"}}
  <p>Paragraph text</p>

  {{! inline, no-child directive }}
  {{#/partial src="other.hbs" }}

  <p>Another paragraph</p>
{{/section}}
// usage
tempura.compile('...', {
  blocks: {
    // #section block
    // must return string[]
    section(args) {
      let open = '<section>';
      if (args.title) open += `<h2>${args.title}</h2>`;

      return [
        open, //=> #section
       '</section>' //=> /section
      ];
    },

    // #partial block
    // ~> does NOT have children
    // must return string
    async partial(args) {
      // ...
      return 'something';
    }
  }
});

Here, the {{#/partial}} syntax means that it's self-closing, just like a JSX or HTML <input /> element.


I think Option B is a bit sleeker, but both approaches have a potential authoring and/or usage issue. They both require that the author & user of a block are aware of its type, affecting both how it must be defined and how it must be used.

I intentionally don't want a block to work both ways. The rigidity here is fine, but just thinking about which approach may feel better.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant