UNPKG

lit-css-vars

Version:

For easily creating and sharing typed CSS vars for the lit.dev ecosystem.

127 lines (126 loc) 4.7 kB
import { check } from '@augment-vir/assert'; import { addPrefix, combineErrorMessages, mapObjectValues, stringify, } from '@augment-vir/common'; import { css, CSSResult, unsafeCSS } from 'lit'; import { cssPropertyRegistry } from './css-property-registry.js'; import { setCssVarValue } from './setters-and-getters.js'; import { CssVarSyntaxName } from './syntax.js'; /** * Creates an easy-to-use-in-lit mapping of the given CSS Var names and defaults. The input * determines the CSS var names and their default values. The output is a mapping of the CSS var * names to name and value objects that can be easily interpolated into lit's css keyed template * strings. * * @category Main * @example * * ```ts * import {defineCssVars} from 'lit-css-vars'; * * // creates a CSS var with name 'my-var' and default value of 50px. * const myVars = defineCssVars({'my-var': '50px'}); * // using the CSS var name: this will be '--my-var' * myVars['my-var'].name; * // accessing the CSS var value for CSS; this will be: 'var(--my-var, 50px)' * myVars['my-var'].value; * ``` */ export function defineCssVars( /** * The CSS var setup input. Keys of this input object become the CSS var names. Values of this * input become the default value of the CSS vars. */ setup) { const cssVarDefinitions = mapObjectValues(setup, (key, rawInputValue) => { assertValidCssVarName(key); const value = rawInputValue; const isCssPropertyDefinition = check.isObject(value) && !(value instanceof CSSResult) && /** Exclude {@link SingleCssVarDefinition}. */ check.lacksKey(value, 'name'); const defaultValue = check.isString(value) || check.isNumber(value) || value instanceof CSSResult ? String(value) : String(value.default); const initialValue = check.isString(value) || check.isNumber(value) || value instanceof CSSResult ? String(value) : String(('initialValue' in value && value.initialValue) || value.default); const cssVarNameCssResult = unsafeCSS(addPrefix({ value: key.replace(/^-+/, ''), prefix: '--', })); const finalDefinition = { name: cssVarNameCssResult, value: css `var(${cssVarNameCssResult}, ${unsafeCSS(defaultValue)})`, syntax: check.isString(value) || check.isNumber(value) || value instanceof CSSResult ? CssVarSyntaxName.Any : createSyntaxString('syntax' in value ? value.syntax : undefined), default: defaultValue, }; const cssPropertyName = String(finalDefinition.name); if (!initialValue) { throw new Error(`Initial value for CSS var ${cssPropertyName} cannot be empty.`); } if (isCssPropertyDefinition && cssPropertyRegistry.registerProperty({ inherits: true, name: cssPropertyName, initialValue, syntax: finalDefinition.syntax, })) { const documentElement = globalThis.document?.documentElement; if (documentElement) { setCssVarValue({ forCssVar: finalDefinition, onElement: globalThis.document.documentElement, toValue: defaultValue, }); } } return finalDefinition; }); return cssVarDefinitions; } /** * Asserts that the given string can be a valid CSS var name (excluding the `--` prefix). * * @category Internal */ export function assertValidCssVarName(value) { try { if (!check.isString(value)) { throw new TypeError('Must be string.'); } else if (!value.includes('-')) { throw new Error('Must have at least one dash (-).'); } else if (value.toLowerCase() !== value) { throw new Error('Must be lowercase.'); } } catch (error) { throw new Error(combineErrorMessages('Invalid CSS var name.', error, `Got '${stringify(value)}'`), { cause: error, }); } } /** * Create a CSS engine compatible syntax string. * * @category Internal */ export function createSyntaxString(syntax) { if (!syntax) { return CssVarSyntaxName.Any; } else if (check.isString(syntax)) { return syntax; } else if (syntax.union) { return syntax.union.map((innerSyntax) => createSyntaxString(innerSyntax)).join(' | '); } else if (syntax.list) { return `${createSyntaxString(syntax.list.values)}${syntax.list.separator}`; } else { return syntax.raw; } }