tss/main.ts

116 lines
3.3 KiB
TypeScript

type PseudoKeys = ["hover"|"before"|"after"] | ["hover", "after"|"before"];
type ValueSignature = (...args:number[])=>void
type EnumDefinition<Signature> = [property:string, options:Record<string, string>, values?:Signature];
type EnumBlock<Signature> = Record<string, EnumDefinition<Signature>>;
type RecursiveObject<Sig extends ValueSignature, Obj extends EnumBlock<Sig>> =
{
[F in keyof Obj]: Obj[F][2] extends Sig ? ((...args:Parameters<Obj[F][2]>)=> RecursiveObject<Sig, Obj>&((...args:PseudoKeys)=>RecursiveObject<Sig, Obj>)&Array<RecursiveObject<Sig, Obj>>)&{
[E in keyof Obj[F][1]]:RecursiveObject<Sig, Obj>&((...args:PseudoKeys)=>RecursiveObject<Sig, Obj>)&Array<RecursiveObject<Sig, Obj>>
} :
{
[E in keyof Obj[F][1]]:RecursiveObject<Sig, Obj>&((...args:PseudoKeys)=>RecursiveObject<Sig, Obj>)&Array<RecursiveObject<Sig, Obj>>
}
}
function Block<Signature extends ValueSignature, Fields extends EnumBlock<Signature>>(options:Fields):()=>RecursiveObject<Signature, Fields>
{
return ()=>{
let pseudo = false;
let query = false;
const list = [];
let fieldLookup = {};
const proxyOuter = new Proxy(
function(...args)
{
console.log("outer: core call", ...args)
if(args.length)
{
list.push(`${(pseudo||query) ? "}" : ""} &:${args.join("::")}{`);
pseudo = true;
query = false;
return proxyOuter;
}
pseudo && list.push("}");
query && list.push("}");
pseudo = false;
query = false;
return list;
},
{
get(_target, propName)
{
console.log("outer: reading property", propName);
const sizeCheck = parseInt(propName)
if(sizeCheck)
{
list.push(`${(query) ? "}" : ""} @media(min-width:${sizeCheck}px){`);
query = true;
return proxyOuter;
}
fieldLookup = options[propName];
if(fieldLookup)
{
list.push(fieldLookup[0]);
}
return proxyInner;
}
}
);
const proxyInner = new Proxy(
function(...args)
{
console.log("inner: core call", ...args)
list.push(`:${args.join(" ")};`);
return proxyOuter;
},
{
get(_target, valName)
{
console.log("inner: reading property", valName);
try
{
list.push(`:${fieldLookup[1][valName]};`);
return proxyOuter;
}
catch(e)
{
console.warn("someone is trying to stringify a style proxy");
return ()=>"[StyleProxy]";
}
}
}
);
return proxyOuter;
}
}
const styles = Block(
{
Pos:["position", { Abs:"absolute", Rel:"relative" }],
Display:[ "display", { Flex:"flex", Grid:"grid", None:"none", Block:"block", InlineBlock:"inline-block" }],
Left:[ "left", { Auto:"auto" }, (left)=>{}]
}
);
const userDeclaredStyleBlock =
(styles()
.Pos.Abs
("hover", "after")
.Pos.Rel
.Left(20)
[512]
.Left(100))
// internal stringification
console.log(userDeclaredStyleBlock().join(""));
function Sheet<UserClasses extends Record<string, ReturnType<typeof styles>>>(userClasses:UserClasses):{[Class in keyof UserClasses]:string}
{
return new Proxy({}, {get(_target, className){}});
}