gale/styles.dev.js
2025-02-12 08:00:45 -05:00

68 lines
2.1 KiB
JavaScript

// @ts-check
const KeyQuery = "@";
const KeyPseudo = ":";
const KeyChild = ".";
const KeyGroup = "^";
/**
* @typedef { Partial<CSSStyleDeclaration> & {
* [key: `${KeyQuery|KeyPseudo|KeyChild|KeyGroup}${string}`]: UserStyles;
* } & {
* [key in keyof CSSStyleDeclaration]?: CSSStyleDeclaration[key] | CSSStyleDeclaration[key][]
* }} UserStyles
*/
/** @typedef {Record<string, UserStyles> & { global?: UserStyles }} UserSheet */
/**
* @template {UserSheet} T
* @typedef {keyof T | (string & {})} ValidSelectors<T>
*/
/**
* @template {UserSheet} T
* @param {T} sheet
* @returns {((...selectors: (keyof T)[]) => string) & { css: string }}
*/
const createCss = (sheet) => {
let i = 0;
const id = i ? "_" + i : "";
i++;
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")}}`;
};
const css = Object.keys(sheet).map(key => Tier("." + key, sheet[key])).join("\n");
globalThis.document?.head.insertAdjacentHTML("beforeend", `<style data-sheet="${i}">${css}</style>`);
/** @type {(...args: (keyof T)[]) => string} */
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;
return classes;
};
export default createCss;