Skip to content

Instantly share code, notes, and snippets.

@milesj
Created February 10, 2020 18:15
Show Gist options
  • Save milesj/65007601ad6c5634024c64216d21b135 to your computer and use it in GitHub Desktop.
Save milesj/65007601ad6c5634024c64216d21b135 to your computer and use it in GitHub Desktop.
Styles
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