gale/styles.dev.js

100 lines
3.0 KiB
JavaScript
Raw Normal View History

2025-02-12 08:00:45 -05:00
const KeyQuery = "@";
const KeyPseudo = ":";
const KeyChild = ".";
const KeyGroup = "^";
2025-02-12 16:09:59 -05:00
/** @typedef { Partial<CSSStyleDeclaration> & {[key: `${KeyQuery|KeyPseudo|KeyChild|KeyGroup}${string}`]: UserStyles } } UserStyles */
/** @typedef {Record<string, UserStyles>} UserSheet */
2025-02-12 08:00:45 -05:00
2025-02-12 16:09:59 -05:00
/**
* @template Obj
* @typedef { { [Key in keyof Obj]: Obj[Key] extends object ? Key | CollectKeys<Obj[Key]> : Key }[keyof Obj] } CollectKeys
2025-02-12 08:00:45 -05:00
*/
/**
2025-02-12 16:09:59 -05:00
* @template Keys
* @typedef { Keys extends `${KeyChild|KeyGroup}${infer Rest}` ? Keys : never } FilterKeys
2025-02-12 08:00:45 -05:00
*/
2025-02-12 16:09:59 -05:00
/**
* @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<K, FilterKeys<CollectKeys<Rec[K]>>> : 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 {<T extends UserSheet>(ref:T)=>Gale.Elemental<CrossMultiplyRecord<T>>} */
function MakeElemental(ref)
{
let pending = false;
let classes = [];
const collector = new Proxy(()=>{console.log("original func invoked!", pending, classes)},
{
get(target, prop, rec)
{
classes.push(prop);
return collector;
2025-02-12 08:00:45 -05:00
}
2025-02-12 16:09:59 -05:00
}
);
const obj = new Proxy({}, {get(target, prop, rec)
{
pending = prop;
classes = [];
return collector;
}
});
return obj;
}
let i = 0;
/** @type {<T extends UserSheet>(sheet:UserSheet&T)=> ((...args:CrossMultiplyRecord<T>[])=>string)&{css:string, dom:Gale.Elemental<CrossMultiplyRecord<T>>} } */
export default (sheet)=>
{
const id = i ? "_"+i : "";
i++;
const css = Object.keys(sheet).map(key=>Tier("."+key, sheet[key])).join(`\n`);
2025-02-12 08:00:45 -05:00
globalThis.document?.head.insertAdjacentHTML("beforeend", `<style data-sheet="${i}">${css}</style>`);
2025-02-12 16:09:59 -05:00
const classes =(...args)=>{
/** @type {(needle:string, str:string)=>string} */
const extractLast =(needle, str)=>{
const ind = str.lastIndexOf(needle)+needle.length;
2025-02-12 08:00:45 -05:00
return ind ? str.substring(ind) : str;
2025-02-12 16:09:59 -05:00
}
return args.map((arg)=>extractLast(KeyGroup, extractLast(KeyChild, arg))).join(id+" ")+id;
}
2025-02-12 08:00:45 -05:00
classes.css = css;
2025-02-12 16:09:59 -05:00
classes.dom = MakeElemental(sheet);
2025-02-12 08:00:45 -05:00
return classes;
2025-02-12 16:09:59 -05:00
}