Skip to content

Instantly share code, notes, and snippets.

@jonathantneal
Created September 8, 2020 01:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jonathantneal/6c36e0129bfed53fcc824969a232304d to your computer and use it in GitHub Desktop.
Save jonathantneal/6c36e0129bfed53fcc824969a232304d to your computer and use it in GitHub Desktop.
Selector Slot Element

Selector Slot

The Selector Slot element slots the children of its host that match a given selector.

Usage

<!-- within the shadow dom of `<some-element>` -->
<selector-slot part="title" matches="h1,h2,h3,h4,h5,h6" style="background:yellow"></qsa-slot>
<selector-slot part="content"></qsa-slot>
<some-element>
  <h1>This is slotted into "title"</h1>
  <p>This is slotted into "content".</p>
  This is also slotted into "content".
</some-element>
HTMLSelectorSlotElement = ((internal, filter) => class HTMLSelectorSlotElement extends HTMLElement {
constructor() {
internal.set(super(), [
this.attachShadow({ mode: 'open' }),
document.createElement('slot'),
document.createElement('slot'),
new MutationObserver(HTMLSelectorSlotElement.prototype.connectedCallback.bind(this)),
[]
])
}
attributeChangedCallback(name, prev, next) {
const [ , liteSlot ] = internal.get(this)
liteSlot.name = next ? `slot${URL.createObjectURL(new Blob).slice(4)}` : ``
HTMLSelectorSlotElement.prototype.connectedCallback.call(this)
}
connectedCallback() {
HTMLSelectorSlotElement.prototype.disconnectedCallback.call(this)
const { host } = this.getRootNode()
if (this.isConnected && host) {
const match = this.getAttribute('matches')
const nodes = filter(host.children, match ? node => node.matches(match) : node => !node.slot)
const [ dark, liteSlot, darkSlot, observer ] = internal.get(this)
internal.set(this, [ dark, liteSlot, darkSlot, observer, nodes ])
this.append(liteSlot)
dark.append(darkSlot)
nodes.forEach(node => node.slot = liteSlot.name)
requestAnimationFrame(() => observer.observe(host, { childList: true }))
}
}
disconnectedCallback() {
const [ , liteSlot, darkSlot, observer, nodes ] = internal.get(this)
observer.disconnect()
liteSlot.remove()
darkSlot.remove()
nodes.forEach(node => {
node.removeAttribute('slot')
node.replaceWith(node)
})
}
static define(tag = HTMLSelectorSlotElement.tagName) {
if (typeof tag === 'string' && tag) customElements.define(HTMLSelectorSlotElement.tagName = tag, HTMLSelectorSlotElement)
}
static get observedAttributes() {
return ['matches']
}
})(new WeakMap, Function.call.bind(Array.prototype.filter)), HTMLSelectorSlotElement.tagName = 'selector-slot', HTMLSelectorSlotElement.define(JSON.parse(document.currentScript && document.currentScript.textContent || `"${HTMLSelectorSlotElement.tagName}"`))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment