Last active
February 22, 2020 00:37
-
-
Save tomhodgins/e1b3e41f348545f58fe0c188fc0f4ed6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// import {filter, all, stringify} from 'https://unpkg.com/cssomtools' | |
// import {parseACommaSeparatedListOfComponentValues} from 'https://tomhodgins.github.io/parse-css/index.js' | |
import('https://unpkg.com/cssomtools').then(({process, all, stringify}) => { | |
import('https://tomhodgins.github.io/parse-css/index.js').then(({parseACommaSeparatedListOfComponentValues}) => { | |
function transplant(target = ':root') { | |
let output = { | |
html: '', | |
css: '' | |
} | |
let root = document.querySelector(target) | |
let elements = [root, ...Array.from(root.children)] | |
output.html = root.outerHTML | |
output.css = elements | |
// For each tag | |
.reduce( | |
// Stylesheet will be our accumulated CSS as a string | |
// Tag is the current DOM element we're processing | |
(stylesheet, element) => { | |
// Process CSS rules | |
process( | |
all(), | |
// …and process them with this function | |
rule => { | |
// Function for processing a style rule | |
function processRule(rule, existing) { | |
// If the rule is a regular style rule | |
// and the tag we're processing matches the selector of this rule | |
// and our output does not already contain this particular rule | |
if ( | |
rule.selectorText | |
&& element.matches(rule.selectorText) | |
&& existing.includes(rule.cssText) === false | |
) { | |
// return the CSS text of this rule as a string | |
return rule.cssText.replace( | |
rule.selectorText, | |
parseACommaSeparatedListOfComponentValues(rule.selectorText) | |
.map(selector => selector.map(token => token.toSource()).join('')) | |
.filter(selector => element.matches(selector)).join(', ') | |
) | |
} else { | |
// In all other cases return nothing | |
return '' | |
} | |
} | |
// For style rules | |
if (rule.selectorText) { | |
let output = processRule(rule, stylesheet) | |
// Add the processed text | |
stylesheet += output.length ? processRule(rule, stylesheet) + '\n' : '' | |
// Otherwise, if the rule is a media rule | |
} else if (rule.media) { | |
// We'll keep track of the matching child rules | |
let children = '' | |
// Process every rule in the group body rule | |
Array.from(rule.cssRules || []).forEach(child => | |
// Remember all matching rules | |
children += processRule(child, children) | |
) | |
// If there were any rules with selectors matching the current tag | |
if (children.length) { | |
// Output an equivalent media rule with matching child rules | |
stylesheet += `@media ${rule.media.mediaText} { ${children} }\n` | |
} | |
} | |
} | |
) | |
return stylesheet | |
}, | |
'' | |
) | |
return `${output.html}\n<style>${output.css}</style>` | |
} | |
window.transplant = transplant | |
}) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment