Implement automatic updating of styles

This commit is contained in:
Talia 2024-03-06 10:38:33 +01:00
parent f6b0d6d004
commit 25fbfeebfd
3 changed files with 48 additions and 3 deletions

View file

@ -1,3 +1,35 @@
class StylesEvent extends Event {
constructor() {
super("styles", { bubbles: true })
}
}
const styleSelector = `style, link[rel="stylesheet"]`
/** @param {Element} node */
const isStyleNode = node => node.matches(styleSelector) || node.querySelector(styleSelector)
/** @param {MutationRecord} mutation */
const isStyleMutation = mutation =>
(mutation.target instanceof Element) && isStyleNode(mutation.target)
|| (mutation.target instanceof Text) && isStyleNode(mutation.target.parentElement)
|| [...mutation.removedNodes].find(isStyleNode)
const StylesObserver = new MutationObserver(mutations => {
[...mutations].forEach(console.log)
for (const {target} of [...mutations].filter(isStyleMutation)) {
target.dispatchEvent(new StylesEvent())
}
})
StylesObserver.observe(document.head, {
subtree: true,
characterData: true,
childList: true,
attributes: true,
attributeFilter: ["rel", "href"],
})
/** /**
* @param {string} href * @param {string} href
* @param {string} layer * @param {string} layer
@ -58,18 +90,18 @@ function collectStyles(sheet, target) {
} }
} }
export default class PullStyles extends HTMLElement { export default class AdoptStyles extends HTMLElement {
static observedAttributes = ["adopt", "layer"] static observedAttributes = ["adopt", "layer"]
attributeChangedCallback() { attributeChangedCallback() {
this.pullStyles() this.adoptStyles()
} }
/** /**
* @param {string} adopt What to adopt * @param {string} adopt What to adopt
* @param {string|undefined} layer What CSS layer to wrap the external styles in * @param {string|undefined} layer What CSS layer to wrap the external styles in
*/ */
pullStyles(adopt=this.adopt, layer=this.layer) { adoptStyles(adopt=this.adopt, layer=this.layer) {
if (adopt == "all") { if (adopt == "all") {
this.replaceChildren(document.createElement("style")) this.replaceChildren(document.createElement("style"))
const rules = new RuleCollection(layer) const rules = new RuleCollection(layer)
@ -86,4 +118,15 @@ export default class PullStyles extends HTMLElement {
get sheet() { return this.querySelector("style") } get sheet() { return this.querySelector("style") }
get adopt() { return this.getAttribute("adopt") } get adopt() { return this.getAttribute("adopt") }
get layer() { return this.getAttribute("layer") } get layer() { return this.getAttribute("layer") }
connectedCallback() {
this.abortController = new AbortController()
document.addEventListener("styles", () => {
this.adoptStyles()
})
}
disconnectedCallback() {
this.abortController.abort()
}
} }

View file

@ -16,6 +16,7 @@
<template shadowrootmode="open"> <template shadowrootmode="open">
<adopt-styles adopt="all"></adopt-styles> <adopt-styles adopt="all"></adopt-styles>
<p class="inline">Inline</p> <p class="inline">Inline</p>
<p class="layer">Layer</p>
<p class="linked">Linked</p> <p class="linked">Linked</p>
</template> </template>
</my-component> </my-component>

View file

@ -9,3 +9,4 @@ into a Shadow-DOM.
- [x] Import `<style>` tags - [x] Import `<style>` tags
- [x] Import into layer - [x] Import into layer
- [ ] Import from layer - [ ] Import from layer
- [x] Automatic updating