UNPKG

@suid/css

Version:

CSS render in JS.

98 lines (97 loc) 3.73 kB
import { isGlobalSelector, isKeyframes, isMediaQuery, isSelector, isVar, isPrivateVar, } from "./assert"; import { snakeCase } from "./utils/string"; function renderSelector(propKey, propValue, selectors = [], options = {}) { const subselectors = propKey.split(",").map((v) => { v = v.trim(); return v.includes("&") ? v : `& ${v}`; }); return render(propValue, (selectors.length ? selectors : [""]).flatMap((selector) => subselectors.map((v) => v.replace(/&/g, selector).trim())), { ...options, }); } function snakeCaseWithCache(name, cache) { if (!cache) return snakeCase(name); let result = cache.get(name); if (result) return result; cache.set(name, (result = snakeCase(name))); return result; } function render(css, selectors = [], options = {}) { const props = []; const rules = []; for (let propKey in css) { const propValue = css[propKey]; if (isPrivateVar(propKey)) { continue; } else if (isGlobalSelector(propKey)) { for (const selector in propValue) { rules.push(...renderSelector(selector, propValue[selector], [], options)); } } else if (isMediaQuery(propKey)) { rules.push(...render(propValue, selectors, { ...options, sublevel: true, }).map((v) => `${propKey} {\n${v}\n}`)); } else if (isVar(propKey)) { if (propValue !== undefined && propValue !== null) props.push(`${propKey}: ${propValue};`); } else if (isKeyframes(propKey)) { const keyframes = []; for (const k in propValue) { keyframes.push(...render(propValue[k], [/^\d+$/.test(k) ? `${k}%` : k], { ...options, sublevel: true, })); } rules.push(`${propKey} {\n${keyframes.join("\n")}\n}`); } else if (isSelector(propKey)) { rules.push(...renderSelector(propKey, propValue, selectors, options)); } else if (options.extraProperties && propKey in options.extraProperties) { const extraProps = options.extraProperties[propKey](propValue); for (const extraPropKey in extraProps) { const inValue = extraProps[extraPropKey]; const value = options.onPropertyValue ? options.onPropertyValue(extraPropKey, inValue) : inValue; if (value !== undefined && value !== null) props.push(`${snakeCaseWithCache(extraPropKey, options.propertyNameCache)}: ${value};`); } } else { propKey = snakeCaseWithCache(propKey, options.propertyNameCache); const value = options.onPropertyValue ? options.onPropertyValue(propKey, propValue) : propValue; if (value !== undefined && value !== null) props.push(`${propKey}: ${value};`); } } const renderProps = (level) => { const pad = "\t".repeat(level); return `${pad}${props.join(`\n${pad}`)}`; }; if (selectors.length) { const pad = options.sublevel ? `\t` : ``; const selectorStr = pad + selectors.join(`,\n${pad}`); return [ ...(props.length ? [ `${selectorStr} {\n${renderProps(options.sublevel ? 2 : 1)}\n${pad}}`, ] : []), ...rules, ]; } else { return [...(props.length ? [renderProps(0)] : []), ...rules]; } } export default render;