Skip to content

Instantly share code, notes, and snippets.

@tomhodgins
Last active February 22, 2020 00:37
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 tomhodgins/e1b3e41f348545f58fe0c188fc0f4ed6 to your computer and use it in GitHub Desktop.
Save tomhodgins/e1b3e41f348545f58fe0c188fc0f4ed6 to your computer and use it in GitHub Desktop.
// 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