Created
February 10, 2020 18:15
-
-
Save milesj/65007601ad6c5634024c64216d21b135 to your computer and use it in GitHub Desktop.
Styles
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 CSS from 'csstype'; | |
type SheetType = 'global' | 'low-pri' | 'high-pri'; | |
type Properties = CSS.Properties; | |
type Property = string; | |
type Value = string | number; | |
type Cache = { | |
className: string; | |
rank: number; | |
type: SheetType; | |
}; | |
const cache = new Map<Property, Map<Value, Cache[]>>(); | |
function getDocumentStyleSheet(type: SheetType): CSSStyleSheet { | |
const id = `aesthetic-${type}`; | |
let element = document.getElementById(id); | |
if (!element) { | |
const style = document.createElement('style'); | |
style.setAttribute('id', id); | |
style.setAttribute('media', 'screen'); | |
document.head.append(style); | |
element = style; | |
} | |
return (element as HTMLStyleElement).sheet as CSSStyleSheet; | |
} | |
function findInCache<K extends keyof Properties>( | |
property: K, | |
value: Properties[K], | |
type: SheetType, | |
): Cache | null { | |
const pc = cache.get(property); | |
if (!pc) { | |
return null; | |
} | |
const vc = pc.get(value!); | |
if (!vc || vc.length === 0) { | |
return null; | |
} | |
return vc.find(i => i.type === type) ?? null; | |
} | |
function addToCache<K extends keyof Properties>(property: K, value: Properties[K], item: Cache) { | |
let pc = cache.get(property); | |
if (!pc) { | |
pc = new Map(); | |
cache.set(property, pc); | |
} | |
let vc = pc.get(value!); | |
if (!vc) { | |
vc = []; | |
pc.set(value!, vc); | |
} | |
vc.push(item); | |
} | |
function compileDeclaration<K extends keyof Properties>( | |
property: K, | |
value: Properties[K], | |
type: SheetType, | |
): string { | |
const item = findInCache(property, value, type); | |
if (item) { | |
return item.className; | |
} | |
const sheet = getDocumentStyleSheet(type); | |
const rank = sheet.cssRules.length; | |
const className = rank.toString(36); // TODO deterministic | |
sheet.insertRule(`.${className} { ${property}: ${value} }`, rank); | |
addToCache(property, value, { | |
className, | |
rank, | |
type, | |
}); | |
return className; | |
} | |
function compile(props: Properties, type: SheetType): string { | |
return Object.keys(props) | |
.map(k => { | |
const key = k as keyof Properties; | |
const value = props[key]; | |
if (value === null || value === undefined) { | |
return ''; | |
} | |
return compileDeclaration(key, value, type); | |
}) | |
.join(' '); | |
} | |
export {}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment