Skip to content

Instantly share code, notes, and snippets.

@barneycarroll
Last active Mar 31, 2021
Embed
What would you like to do?
Simple CSS-in-JS via speculative 'MFX' idiom. MFX inverts the typical convenience component interface for Mithril: 1) no opportunity to return virtual DOM; 2) completely flexible input signature; 3) executes on every render; 4) returns a lifecycle dictionary. The mechanism is a very simple wrapper for a lifecycled fragment which always produces …
import css from './css.js'
let color = 'red'
let fontFamily = 'sans-serif'
m.mount(document.body, {
view: () => [
m('p',
css`
color: ${ color };
`,
css`
font: 2em/1.5 ${ fontFamily };
`,
'Hi',
),
m('input', {
value: color,
oninput: e => {
color = e.target.value
},
}),
m('select', {
onchange: e => {
fontFamily = e.target.selectedOptions[0].value
},
},
['serif', 'sans-serif', 'monospace'].map(value =>
m('option', {
selected: value === fontFamily
}, value)
),
),
],
})
import mfx from './mfx.js'
import xet from 'xet'
const style = document.head.appendChild(
document.createElement('style')
)
const classes = new WeakMap
let count = 0
export default mfx((template, ...variables) => {
return {
oninit(){
this.name = xet(classes, template, () => {
const name = 'class' + count++
style.textContent += (
'.' + name + ' {' + variables.reduce(
(string, _, index) => string + 'var(--' + name + '-var' + index + ')' + template[index + 1],
template[0],
) + '}\n'
)
return name
})
},
oncreate({dom, attrs}){
dom.parentNode.classList.add(this.name)
attrs.onupdate.call(this, {dom})
},
onupdate({dom}){
variables.forEach((value, index) => {
dom.parentNode.style.setProperty('--' + this.name + '-var' + index, value)
})
}
}
})
export default function mfx(factory){
return function transform(){
return m.fragment(factory.apply(this, arguments), '')
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment