devpunks / snuggsi

snuggsi ツ - Easy Custom Elements in ~1kB
https://snuggsi.com
MIT License
398 stars 17 forks source link

Named <template> <slot>s not translated during HTMLLinkElement.import #56

Closed icyc9 closed 7 years ago

icyc9 commented 7 years ago

It appears that imported templates are not delegated an initial render call. This leaves the elements within the template to explicitly execute the initial render.

The structures below when executed will display the element in its initial token representation.

<template>
  <hello-world>
   Hello {planet}
  </hello-world>
</template

<script src=https://unpkg.com/snuggsi></script>
<script defer>

// Element Definition -----------------------------

Element `hello-world`

// Class Description ------------------------------

(class extends HTMLElement {

  onclick ()
    // "automagic" event registration
    { alert (this.textContent) }

  get planet ()
    // "automagic" token binding
    { return 'world 🌎' }
})

</script>
<script nomodule src=//unpkg.com/snuggsi/snuggsi.min.js></script>
<link rel=import href=hello-world.html>

Explicit delegation to the render method within the initialize method will render the tokens, as expected. For example:

...
initialize () {
   this.render()
}
...
snuggs commented 7 years ago

INTERESTING!!!!!!!!!! Nice pick up @RobertChristopher we can pair on this. I been looking for that bug. I thought those headers looked a little funny. We probably have to make changes around the HTMLLinkElement.import It's a little funky thanks to Firefox which forces us to depend on the polyfill import unfortunately. We NEED that for imports for sure. /cc @brandondees

snuggs commented 7 years ago

@RobertChristopher Following chain is not being called. Probably the hairiest part of the spec. Thank @brandondees for that one but well worth it.

https://github.com/devpunks/snuggsi/blob/master/elements/component.es#L27-L29 https://github.com/devpunks/snuggsi/blob/master/elements/global-event-handlers.es#L31-L40 https://github.com/devpunks/snuggsi/blob/master/elements/html-link-element.es

brandondees commented 7 years ago

don't "thank" me, i didn't implement anything but a demo! i'm starting to think it's time to be investing in unit tests for these kinds of things though

snuggs commented 7 years ago

Well you know i'm a religious tester @brandondees. However I'm feeling build them as they come. Me 2 years ago would have still been working on the test suite. no features.

That said this is the most intricate process so perhaps a valid point. Irony is if you remove the polyfill everything works. SMH.

brandondees commented 7 years ago

if that's the case, might be time to start thinking about crafting your own minimal polyfill that does just what's needed

snuggs commented 7 years ago

@brandondees @RobertChristopher @janz93 I believe a convention should be to keep snuggsi declaration to the consumer's choosing. I just know we COULD let them define <script src=//snuggsi> within imported <template>s However if had to make a choice i'd say keep the <script...> within master document.

Please advise as this is just a pattern to abide by.

snuggs commented 7 years ago

Also @brandondees what I like is I didn't even let @RobertChristopher know about the HTML <link rel=import>.import feature. He discovered it all on his own. And found this 🐛 That's a testament to us having readable examples/source code. 🏆

snuggs commented 7 years ago

@RobertChristopher i've deduced the 🐛 down to the Component.parse () API. PR coming soon. I actually didn't like this feature at first until @brandondees showed me some use cases of <slot> replacement. Basically we ARE importing the templates (and the attributes) into each clone. However the slots are not being replaced. This should be an easy fix and we actually dodge many bullets while the ShadowDom spec is maturing throughout the rest of 2017. In our usage of <slot> it gets people used to seeing the new element conventions. However we actually don't use the shadow dom. We use the imported <template> as our "Shadow". Therefore even ancient browsers see <slot> just as any old HTMLElement. All we are doing is hot replacing the slot=name's immediately after component "connects" to the DOM and BEFORE rendering (hence how we can use {token}s within the named slots. A VERY clever trick if ya ask me.

<!-- header-group.html -->
<template>

<header-group>
  <slot name=foo><h1>Token {bar} &amp; default content from imported component</h1></slot>
</header-group>

</template>
<!-- index.html -->
<link rel=import href=header-group.html>

<header-group>
  <h1 slot=foo>This content replaces default slot content.</h1>
</header-group>

In retrospect I ❤️ the <slot> feature. And will be VERY familiar to those who love Vue.js. By us leaning on the platform we were able to use <slot>s within less than 20LOC. Vue's <slot> implementation is about 340LOC. https://vuejs.org/v2/guide/components.html#What-are-Components

/cc @btakita @mrbernnz @scottmacdowell @janz93

Location of Bug

https://github.com/devpunks/snuggsi/blob/master/elements/component.es#L58-L96

Other Links

MDN <slot> - https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot MDN GlobalAttributes.slot - https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/slot MDN Element.slot (Same as GlobalAttributes.slot) - https://developer.mozilla.org/en-US/docs/Web/API/Element/slot