@chasemoskal/magical
Version:
web toolkit for lit apps
77 lines (56 loc) • 1.92 kB
text/typescript
export class TemplateSlots {
static readonly parentObservationOptions: MutationObserverInit = {
childList: true,
}
static readonly templateDeepObserverationOptions: MutationObserverInit = {
childList: true,
attributes: true,
characterData: true,
subtree: true,
}
static readonly templateAttributeObserverationOptions: MutationObserverInit = {
attributes: true,
}
#parent: HTMLElement
#templates = new Map<string | undefined, HTMLTemplateElement>()
#parentObserver: MutationObserver
#templateObservers = new Set<MutationObserver>
#onChange = () => {}
#refresh() {
for (const observer of this.#templateObservers)
observer.disconnect()
this.#templates.clear()
this.#templateObservers.clear()
const templates = Array.from(
this.#parent.querySelectorAll<HTMLTemplateElement>(":scope > template")
)
for (const template of templates) {
const name = template.getAttribute("slot") ?? undefined
this.#templates.set(name, template)
const deepObserver = new MutationObserver(this.#onChange)
const attributeObserver = new MutationObserver(() => {
this.#refresh()
this.#onChange()
})
deepObserver.observe(template.content, TemplateSlots.templateDeepObserverationOptions)
attributeObserver.observe(template, TemplateSlots.templateAttributeObserverationOptions)
this.#templateObservers.add(deepObserver)
}
}
constructor(parent: HTMLElement, onChange = () => {}) {
this.#parent = parent
this.#onChange = onChange
this.#parentObserver = new MutationObserver(() => this.#refresh())
this.#parentObserver.observe(parent, TemplateSlots.parentObservationOptions)
this.#refresh()
}
get(name?: string) {
const selector = name
? `:scope > template[slot="${name}"]`
: `:scope > template:not([slot])`
const template = this
.#parent
.querySelector<HTMLTemplateElement>(selector)
return template?.content.cloneNode(true)
}
}