11ty / webc

Single File Web Components
MIT License
1.32k stars 38 forks source link

Order of operations: slot content with WebC Transforms #103

Open cfjedimaster opened 1 year ago

cfjedimaster commented 1 year ago

So imagine a webc component named reverse. The idea is to take content from the default slot and reverse it. It would be used like so:

<reverse>
This is a test.
</reverse>

And the output would simply reverse that string. I tried doing this with Liquid, like so:

<template webc:type="11ty" 11ty:type="liquid">

  {% capture content %}
  <slot><p>Im the default slot.</p></slot>
  {% endcapture %}

  <p>
  Content: {{ content }}
  </p>

  <p>
  Content reversed: {{ content | split: "" | reverse | join: "" }}
  </p>
</template>

The output was... unusual:

Content: This is a test.

Im the default slot.

Content reversed: >tols/<>p/<.tols tluafed eht mI>p<>tols<

It correctly captured the default slot, but then output the default text as if I had not passed any in. And then - oddly - despite the content variable being correct, when the split/reverse/join is called, it used the raw HTML.

You can see this here:

https://glitch.com/edit/#!/determined-honorable-porch?path=src%2F_includes%2F_components%2Freverse.webc%3A18%3A0

kenmorechalfant commented 1 year ago

Just a guess: does the liquid template element get processed as Liquid before WebC? I think that's the issue. While rendering the WebC file it sees the Liquid element, processes it first as Liquid, then the Liquid output as WebC before returning execution to the rest of the file.

Does it help to capture only the inside of the <slot>?

<template webc:type="11ty" 11ty:type="liquid">

  <slot>
    {% capture content %}
    <p>Im the default slot.</p>
    {% endcapture %}
  </slot>

  <p>
  Content: {{ content }}
  </p>

  <p>
  Content reversed: {{ content | split: "" | reverse | join: "" }}
  </p>
</template>
cfjedimaster commented 1 year ago

Oh interesting - I'm going to try now - Glitch is being a bit slow. :\

cfjedimaster commented 1 year ago

No go, if you view the Glitch url, I built a new version, reverse2, to test that, and I end up with:

This is a test.
Content:

I'm the default slot.

Content reversed: >p/<.tols tluafed eht m'I>p<
zachleat commented 1 year ago

HMMMMMM, webc:type transforms do happen before WebC and slot resolution (as is by design).

So this:

{%- capture content %}<slot><p>Im the default slot.</p></slot>{%- endcapture %}

will capture <slot><p>Im the default slot.</p></slot>.

Unfortunately that also means that

<slot><p>{%- capture content %}Im the default slot.{%- endcapture %}</p></slot>

will capture Im the default slot.

Fortunately, the WebC data cascade does have access to (raw/unprocessed—read: not yet processed by WebC) slot content, so this will work:

<p>{%- capture content %}{{ slots.text.default | default: "Im the default slot." }}{%- endcapture %}</p>

(using liquid’s default filter to provide fallback content)

zachleat commented 1 year ago

We use the above approach in the provided syntax highlighter WebC component https://github.com/11ty/eleventy-plugin-syntaxhighlight/blob/ac92151c42996faef19650f34f54a77e4ac210f2/syntax-highlight.webc#L13

cfjedimaster commented 1 year ago

Zach, I was actually going to file an ER for this - slot.text.default. Does this mean I can access slots in my code? slot.text.NAMEOFSLOT?

zachleat commented 1 year ago

yeah, 100%. Just note that it is raw text content, not processed WebC

cfjedimaster commented 1 year ago

Hmm. So imagine in the parent I have stuff , and stuff included a block of Liquid code that output something dynamic. Does this mean the text would be raw code, or the result?

cfjedimaster commented 1 year ago

I can confirm my simpler, reverse-er webc works:

<template webc:type="11ty" 11ty:type="liquid">

  <slot><p>Im the default slot.</p></slot>

  <p>
  Content reversed: {{ slots.text.default | split: "" | reverse | join: "" }}
  </p>
</template>

However, if I do: <reverse3></reverse3> (see first post w/ link to glitch), the result is empty. Shouldn't it reverse the text I used as a default?