const KeyQuery = "@"; const KeyPseudo = ":"; const KeyChild = "."; const KeyGroup = "^"; /** @typedef { Partial & {[key: `${KeyQuery|KeyPseudo|KeyChild|KeyGroup}${string}`]: UserStyles } } UserStyles */ /** @typedef {Record} UserSheet */ /** * @template Obj * @typedef { { [Key in keyof Obj]: Obj[Key] extends object ? Key | CollectKeys : Key }[keyof Obj] } CollectKeys */ /** * @template Keys * @typedef { Keys extends `${KeyChild|KeyGroup}${infer Rest}` ? Keys : never } FilterKeys */ /** * @template A * @template B * @typedef {A extends string ? B extends string ? `${A}${B}` : never : never } CrossMultiply */ /** * @template Rec * @typedef { keyof Rec | { [K in keyof Rec]: K extends string ? CrossMultiply>> : never }[keyof Rec] } CrossMultiplyRecord */ /** @type {(selector:string, obj:UserStyles)=>string} */ const Tier=(selector, obj)=> { const styles = Object.keys(obj).map((key)=> { const value = obj[key]; switch(key[0]) { case KeyQuery : return Tier(`@media(max-width:${key.substring(KeyQuery.length)})`, value); case KeyPseudo : return Tier(`&${key}`, value); case KeyChild : return Tier(`${key}`, value); case KeyGroup : return Tier(`&:hover .${key.substring(KeyGroup.length)}`, value); } return `${ key.replace(/([a-z])([A-Z])/g, '$1-$2') }: ${value};` }); return `${selector}{${styles.join("\n")}}`; } /** @type {(ref:T)=>Gale.Elemental>} */ function MakeElemental(ref) { let pending = false; let classes = []; const collector = new Proxy((...args)=>{ console.log("original func invoked!", pending, classes); const element = van.tags[pending](...args); element.className = classes.join(" "); return element }, { get(target, prop, rec) { classes.push(prop); return collector; } } ); const obj = new Proxy({}, {get(target, prop, rec) { pending = prop; classes = []; return collector; } }); return obj; } let i = 0; /** @type {(sheet:UserSheet&T)=> ((...args:CrossMultiplyRecord[])=>string)&{css:string, dom:Gale.Elemental>} } */ export default (sheet)=> { const id = i ? "_"+i : ""; i++; const css = Object.keys(sheet).map(key=>Tier("."+key, sheet[key])).join(`\n`); globalThis.document?.head.insertAdjacentHTML("beforeend", ``); const classes =(...args)=>{ /** @type {(needle:string, str:string)=>string} */ const extractLast =(needle, str)=>{ const ind = str.lastIndexOf(needle)+needle.length; return ind ? str.substring(ind) : str; } return args.map((arg)=>extractLast(KeyGroup, extractLast(KeyChild, arg))).join(id+" ")+id; } classes.css = css; classes.dom = MakeElemental(sheet); return classes; }