-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Add Imperative Slot API #5483
Add Imperative Slot API #5483
Conversation
As far as I know you want to track which nodes are manually assigned. You need some infrastructure for that which isn't provided/hooked into here. |
I updated the spec to include manuallyAssignedNodes concept. Please take a look, Thanks. |
Thanks for reviewing. I've updated the spec based on feedback. |
source
Outdated
<span>shadow root</span>'s <span>slot assignment</span> is not "manual", then throw <span>"<code>NotAllowedError</code>"</span> | ||
<code>DOMException</code>.</p></li> | ||
|
||
<li><p>For each <var>node</var> in <var>nodes</var>: if <var>node</var> is not a <span data-x="concept-tree-child">child</span> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if I change this after assignment? Per the current set of algorithms it seems like it would still be assigned, despite no longer being a child of the host. Is that correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right. The algorithms in corresponding DOM spec PR doesn't update manually assigned nodes when an assigned node or a slot is removed.
I looked at the #concept-node-remove to see how when "slot assignment' auto is handled.
Step 11 and 12 takes care of the assigned node case[1]. And step 14 takes care of the case[2] if the removed node is a slot or it contains a slot descendant.
So in theory, when "slot assignment" manual, it can use the same algorithm to make sure that slottables at the 3 of #assign-slotables are set back to manually assigned nodes. Thus, I updated the corresponding DOM spec to keep slot's assigned nodes and manually assigned nodes in sync.
Hopefully, this works. I also looked at the possibility of clearing out the manually assigned nodes during #concept-node-remove, but decided to go with a similar path for auto assignment.
I wonder if it wouldn't be easier if instead the children of a host had a reference to null or a slot. Then whenever you need the "assigned slottables" of a slot you can go through those children and if you need to update anything you can go through those children rather than traversing the entire shadow tree looking for slots. And if you compute the "assigned slottables" lazily I guess you only need to care for mutations to the host's children, potentially simplifying the changes in DOM. cc @smaug---- @rniwa |
Current DOM's https://dom.spec.whatwg.org/#find-a-slot is going through the tree. |
Anne@, Thanks. |
FWIW, what's being proposed here seems fine. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is good now, except for the nits. It does seem as defined assign()
is quite expensive, but also has lots of room for optimizations.
Thanks for reviewing. Thanks. |
@domenic @rniwa can either of you give this and the DOM PR at whatwg/dom#860 a review? I have some nits that I can address, but I'm worried about losing the plot given the amount of time that has passed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I pushed some tweaks. The only one of substance is that I made it explicit that you loop through descendants in tree order when removing them. I imagine the order might be observable using mutation observers?
I also tidied some nearby method definitions and IDL stuff to conform to modern conventions.
The HTML side of this seems relatively simple, so next up is the DOM side...
Hmm, I also changed "manually assigned nodes" from a set to a list, because I didn't see any protection against |
@domenic, |
OK, cool. So there's no problem with the algorithms if the same node appears twice in the manually assigned nodes list? Do we have test cases for the behavior in that scenario? |
</ol> | ||
</li> | ||
|
||
<li><p>Set <span>this</span>'s <span>manually assigned nodes</span> to <var>nodes</var>.</p></li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't quite right. We need to remove duplicates from the manually assigned nodes since "find slottables" in https://github.com/whatwg/dom/pull/860/files doesn't remove duplicates either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, that seems more correct to me, and seems to match the implementation in Chromium. https://source.chromium.org/chromium/chromium/src/+/master:third_party/blink/renderer/core/html/html_slot_element.cc;l=187;drc=510d6b8791a0e20c3470f9c0fcf1472d1bb71995
I will update the PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems slightly cleaner to make the set during the first iteration to avoid redundant descendant searches, but I think it should not be observable...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree here that we should unique the list here. The Chromium implementation also has some logic around ordering in the case of duplicates, which I think makes sense. I'll try to write that up here. domenic@, you mentioned you'd update the PR, that didn't happen, right? Just making sure I don't step on a change for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did update the PR; see commit fdc36ca
<p>The <code>slot</code> element has <dfn export for="HTMLSlotElement">manually assigned | ||
nodes</dfn>, which is an <span data-x="set">ordered set</span> of <span | ||
data-x="slottable">slottables</span> set by <code data-x="dom-slot-assign">assign()</code>. It is | ||
initially empty.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we move this up? Usually we describe "slots" before public members.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved this up above the assignedNodes
method steps. Let me know if that's what you were requesting here.
</ol> | ||
</li> | ||
|
||
<li><p>Set <span>this</span>'s <span>manually assigned nodes</span> to <var>nodes</var>.</p></li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems slightly cleaner to make the set during the first iteration to avoid redundant descendant searches, but I think it should not be observable...
<li><p><span data-x="list iterate">For each</span> <var>node</var> of <var>nodes</var>: if | ||
<var>node</var> is not a <span data-x="concept-tree-child">child</span> of <span>this</span>'s | ||
<span>root</span>'s <span>shadow host</span>, then throw a | ||
<span>"<code>NotAllowedError</code>"</span> <code>DOMException</code>.</p></li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to leave this whole thing here - it seems reasonable to me to throw an exception if, at assign()
call time, the provided children aren't in the right place. If they're later removed from the shadow host, we will just pretend they're not there. If they're ever put back, we'll start using them again. But I don't know what the use case would be for assigning nodes that aren't present yet (perhaps not even in the same document). Does that sound ok?
For this reason, I don't think there are any changes needed to this PR to incorporate the proposed changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm... what if you wanted to assign nodes then add them as children of the shadow host? The one of main use cases of manual assignment is so that custom element can have JS API which accepts a list of nodes to use, right? In that scenario, it's possible for the users of a custom element to create a bunch of nodes, call JS API, then add them as children of the host instead of adding them first and then giving them to the JS API. At least, that was one of the use cases that came up during accessibility related discussion in the past which motivated the current design.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's a good point. Ok, sounds like we should probably remove the second <li>
here that throws an exception if node
isn't a child of the shadow host. I'll leave the first check that the <slot>
is within a shadow root and that it is in manual
mode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've opened another PR for this, with the changes requested: #6561
<li><p><span data-x="list iterate">For each</span> <var>node</var> of <var>nodes</var>: if | ||
<var>node</var> is not a <span data-x="concept-tree-child">child</span> of <span>this</span>'s | ||
<span>root</span>'s <span>shadow host</span>, then throw a | ||
<span>"<code>NotAllowedError</code>"</span> <code>DOMException</code>.</p></li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's a good point. Ok, sounds like we should probably remove the second <li>
here that throws an exception if node
isn't a child of the shadow host. I'll leave the first check that the <slot>
is within a shadow root and that it is in manual
mode.
</ol> | ||
</li> | ||
|
||
<li><p>Set <span>this</span>'s <span>manually assigned nodes</span> to <var>nodes</var>.</p></li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree here that we should unique the list here. The Chromium implementation also has some logic around ordering in the case of duplicates, which I think makes sense. I'll try to write that up here. domenic@, you mentioned you'd update the PR, that didn't happen, right? Just making sure I don't step on a change for that.
<p>The <code>slot</code> element has <dfn export for="HTMLSlotElement">manually assigned | ||
nodes</dfn>, which is an <span data-x="set">ordered set</span> of <span | ||
data-x="slottable">slottables</span> set by <code data-x="dom-slot-assign">assign()</code>. It is | ||
initially empty.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved this up above the assignedNodes
method steps. Let me know if that's what you were requesting here.
The explainer for this feature is here: https://github.com/w3c/webcomponents/blob/gh-pages/proposals/Imperative-Shadow-DOM-Distribution-API.md
The issue discussion is here: 3534
There is a corresponding Pull Request for the DOM spec that goes along with this PR.
At least two implementers are interested (and none opposed):
Tests are written and can be reviewed and commented upon at:
Implementation bugs are filed:
/acknowledgements.html ( diff )
/infrastructure.html ( diff )
/scripting.html ( diff )