a post-component library for building user-interfaces on the web.
at main 50 lines 1.4 kB view raw
1const class_names = new WeakMap() 2const adopted = new WeakSet() 3const stylesheet = new CSSStyleSheet() 4let next_id = 0 5const cache = new Map() 6 7/** 8 * @param {TemplateStringsArray} strings 9 * @param {unknown[]} dynamics 10 * @returns {import('dhtml/client').Directive} 11 */ 12export function css(strings, ...dynamics) { 13 let class_name = class_names.get(strings) 14 if (!class_name) { 15 class_names.set(strings, (class_name = `gen-${next_id++}`)) 16 stylesheet.insertRule( 17 `.${class_name}{${strings.reduce((acc, value, index) => acc + `var(--${class_name}-${index - 1})` + value)}}`, 18 ) 19 } 20 21 const cache_key = `${class_name}\0${dynamics.map(v => String(v)).join('\0')}` 22 const cached = cache.get(cache_key) 23 if (cached) return cached 24 25 /** @type {import('dhtml/client').Directive} */ 26 const directive = element => { 27 const root = /** @type {Document | ShadowRoot} */ (element.getRootNode()) 28 if (!adopted.has(root)) { 29 root.adoptedStyleSheets.push(stylesheet) 30 adopted.add(root) 31 } 32 33 const { style, classList } = /** @type {HTMLElement} */ (element) 34 35 classList.add(class_name) 36 for (let i = 0; i < dynamics.length; i++) { 37 style.setProperty(`--${class_name}-${i}`, String(dynamics[i])) 38 } 39 40 return () => { 41 classList.remove(class_name) 42 for (let i = 0; i < dynamics.length; i++) { 43 style.setProperty(`--${class_name}-${i}`, null) 44 } 45 } 46 } 47 48 cache.set(cache_key, directive) 49 return directive 50}