UNPKG

@furystack/shades

Version:

A lightweight UI framework for FuryStack with JSX support

90 lines 3.06 kB
/** * @example * camelToKebab('backgroundColor') // 'background-color' */ export const camelToKebab = (str) => { return str.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`); }; export const isSelectorKey = (key) => { return key.startsWith('&'); }; /** * Serializes the non-selector entries of a {@link CSSProperties} object as * a CSS declaration body. Selector keys (`&...`) are skipped. */ export const propertiesToCSSString = (properties) => { const declarations = []; for (const key in properties) { if (Object.prototype.hasOwnProperty.call(properties, key) && !isSelectorKey(key)) { const value = properties[key]; if (value !== undefined && value !== null && value !== '' && typeof value === 'string') { declarations.push(`${camelToKebab(key)}: ${value}`); } } } return declarations.join('; '); }; /** Builds `selector { decls; }` from the non-selector entries. Empty when no decls. */ export const generateCSSRule = (selector, properties) => { const cssString = propertiesToCSSString(properties); if (!cssString) { return ''; } return `${selector} { ${cssString}; }`; }; /** * Renders a {@link CSSObject} as CSS rules. Base properties become a single * rule against `selector`; each `&...` selector key produces an additional * rule with `&` substituted for `selector`. * * @example * ```typescript * generateCSS('my-component', { * color: 'red', * '&:hover': { color: 'blue' }, * '& .inner': { fontWeight: 'bold' } * }) * // my-component { color: red; } * // my-component:hover { color: blue; } * // my-component .inner { font-weight: bold; } * ``` */ export const generateCSS = (selector, cssObject) => { const rules = []; // Extract base properties (non-selector keys) const baseProperties = {}; const selectorRules = []; for (const key in cssObject) { if (Object.prototype.hasOwnProperty.call(cssObject, key)) { if (isSelectorKey(key)) { const properties = cssObject[key]; if (properties && typeof properties === 'object') { selectorRules.push({ selectorKey: key, properties: properties }); } } else { const value = cssObject[key]; if (typeof value !== 'object') { ; baseProperties[key] = value; } } } } // Generate base rule const baseRule = generateCSSRule(selector, baseProperties); if (baseRule) { rules.push(baseRule); } // Generate selector rules for (const { selectorKey, properties } of selectorRules) { // Replace '&' with the base selector const fullSelector = selectorKey.replace(/&/g, selector); const rule = generateCSSRule(fullSelector, properties); if (rule) { rules.push(rule); } } return rules.join('\n'); }; //# sourceMappingURL=css-generator.js.map