Pauan / rust-dominator

Zero-cost ultra-high-performance declarative DOM library using FRP signals for Rust!
MIT License
967 stars 62 forks source link

Macros to make working with existing elements and web components easier #23

Closed dakom closed 2 years ago

dakom commented 4 years ago

Consider the following... there's these CustomElements that are pre-registered and created via something like lit-element:

Some of them are setup to have meaningful properties that should be set from the outside (for example, sticker-frame might play an animation and let its step be driven from an external clock)

dominator wants to mount sticker-book to the top-level body. So far so good. But the problem is that the other elements are actually inside of sticker-book's shadow dom. It may look like this:

<div>
  <sticker-menu id="menu" activeSticker="2" />
  <ul id="list">
    <li><sticker-image id="1" /></li>
    <li><sticker-image id="2" active="true" /></li>
  </ul>
</div>

And lets say sticker-image is setup to react on its active property change such that it will render either:

<sticker-frame step={step}>
  <img src="..." />
</sticker-frame>

or

null

So dominator should be able to:

  1. Append/Remove sticker-image items in the list (at id="list")
  2. Set properties of these nested elements
  3. Set properties on those nested elements' nested elements - but after mounting

In other words, through dominator, with the above setup it should be possible to easily drive the final step property on sticker-frame. However, if the top level active sticker is changed, then it must switch to set the step property on the new sticker-frame

@Pauan noted that it is currently possible, but may require some ugly workarounds, and that macros will make this much more elegant. Also that since it fundamentally boils down to working with pre-existing nodes, it will help with server-side rendering as well.

dakom commented 4 years ago

fwiw - potential showstopper for this particular use-case (but not the general idea)

lit-element does its own batching of updates and rendering, so even if an element theoretically has some child - there's no guarantee that it's actually rendered until after lit-element's promises settle. Specifically a promise from updateComplete.

For example (using JS and assuming my-container renders some element with id="child-id"):

const element = document.createElement("my-container");
document.body.appendChild(element);

console.log(element.shadowRoot.getElementById("child-id")); //null

element.updateComplete.then(() => {
    console.log(element.shadowRoot.getElementById("child-id")); //okay
});
dakom commented 2 years ago

Closing this for now, it's a bit too generic and I can't remember what I had in mind at the time.

Realistically, Dominator renders custom elements just fine, and all that's needed is to carefully plan out slots for placing children.

There's other utilities specific to web components which are useful, of course, but imho those should be opened as specific issues if/when they come up.