commit a114e18dc6461aa64d512dd41a149e0dd1a50b35 Author: DarkWiiPlayer Date: Thu Feb 29 14:34:38 2024 +0100 Start implementing proof-of-concept diff --git a/PullStyles.js b/PullStyles.js new file mode 100644 index 0000000..2dc88d0 --- /dev/null +++ b/PullStyles.js @@ -0,0 +1,89 @@ +/** +* @param {string} href +* @param {string} layer +*/ +function importRule(href, layer) { + if (layer) + return `@import url("${href}") layer(${layer});` + else + return `@import url("${href}");` +} + +/** +* @param {string} css +* @param {string|undefined} layer +*/ +function wrapLayer(css, layer) { + if (layer) + return `@layer ${layer} { ${css} }` + else + return css +} + +class RuleCollection { + layer + /** @type {string[]} */ + imports = [] + /** @type {string[]} */ + inlined = [] + + /** @param {string} layer */ + constructor(layer) { this.layer = layer } + + /** @param {HTMLStyleElement} styleSheet */ + copyInto(styleSheet) { + for (const href of this.imports) + styleSheet.innerHTML += importRule(href, this.layer) + for (const block of this.inlined) + styleSheet.innerHTML += wrapLayer(block, this.layer) + } +} + +/** +* @param {CSSStyleSheet} sheet +* @param {RuleCollection} target +*/ +function collectStyles(sheet, target) { + if (sheet.ownerRule) { + // TODO + } else { + const node = sheet.ownerNode + if (node instanceof HTMLLinkElement) { + target.imports.push(node.href) + } else if (node instanceof HTMLStyleElement) { + target.inlined.push(node.innerHTML) + } else { + console.log(node) + } + } +} + +export default class PullStyles extends HTMLElement { + static observedAttributes = ["adopt", "layer"] + + attributeChangedCallback() { + this.pullStyles() + } + + /** + * @param {string} adopt What to adopt + * @param {string|undefined} layer What CSS layer to wrap the external styles in + */ + pullStyles(adopt=this.adopt, layer=this.layer) { + if (adopt == "all") { + this.replaceChildren(document.createElement("style")) + const rules = new RuleCollection(layer) + for (const sheet of document.styleSheets) { + collectStyles(sheet, rules) + } + rules.copyInto(this.sheet) + console.log(this.sheet.innerText) + } else if (adopt != undefined) { + throw new Error("Adopt must be empty or 'all'") + } + } + + get sheet() { return this.querySelector("style") } + get adopt() { return this.getAttribute("adopt") } + get layer() { return this.getAttribute("layer") } +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..55cd2e3 --- /dev/null +++ b/index.html @@ -0,0 +1,21 @@ + + + + + + + + + diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..dc95dc7 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1 @@ +{ "compilerOptions": { "checkJs": true, "target": "es2020" } } \ No newline at end of file diff --git a/linked.css b/linked.css new file mode 100644 index 0000000..a522e4b --- /dev/null +++ b/linked.css @@ -0,0 +1 @@ +.linked { color: blue }