UNPKG

theme-vir

Version:
151 lines (150 loc) 7.31 kB
import { check } from '@augment-vir/assert'; import { getObjectTypedEntries, kebabCaseToCamelCase, } from '@augment-vir/common'; import { CSSResult } from 'element-vir'; /** * Convert a color theme into code to define that color theme. * * @category Color Theme */ export function generateThemeCode(theme, options) { const paletteVarName = options?.paletteVarName; const defaultInitCode = colorInitToCode(theme.init.default, 1, undefined, paletteVarName); const colorsInitCode = colorThemeInitToCode(theme.init.colors, 1, theme.init.default, paletteVarName); const themeCode = `export const theme = defineColorTheme(\n${defaultInitCode},\n${colorsInitCode},\n);`; const overridesCodes = (options?.overrides || []).map((override) => { return generateOverrideCode(override, paletteVarName); }); return [ themeCode, ...overridesCodes, ].join('\n\n'); } function generateOverrideCode(override, paletteVarName) { const parts = []; // Check if default colors differ const defaultOverrideEntries = []; if (!colorInitValuesEqual(override.asTheme.init.default.foreground, override.originalTheme.init.default.foreground)) { defaultOverrideEntries.push(`${tab(3)}foreground: ${colorInitValueToCode(override.asTheme.init.default.foreground, 3, paletteVarName)},`); } if (!colorInitValuesEqual(override.asTheme.init.default.background, override.originalTheme.init.default.background)) { defaultOverrideEntries.push(`${tab(3)}background: ${colorInitValueToCode(override.asTheme.init.default.background, 3, paletteVarName)},`); } if (defaultOverrideEntries.length > 0) { parts.push(`${tab(2)}defaultOverride: {\n${defaultOverrideEntries.join('\n')}\n${tab(2)}},`); } // Check for color overrides const colorOverrideEntries = []; getObjectTypedEntries(override.asTheme.init.colors).forEach(([colorName, colorInit,]) => { const originalColorInit = override.originalTheme.init.colors[colorName]; if (!originalColorInit) { return; } const colorEntries = []; if ('foreground' in colorInit && (!('foreground' in originalColorInit) || !colorInitValuesEqual(colorInit.foreground, originalColorInit.foreground))) { colorEntries.push(`${tab(4)}foreground: ${colorInitValueToCode(colorInit.foreground, 4, paletteVarName)},`); } if ('background' in colorInit && (!('background' in originalColorInit) || !colorInitValuesEqual(colorInit.background, originalColorInit.background))) { colorEntries.push(`${tab(4)}background: ${colorInitValueToCode(colorInit.background, 4, paletteVarName)},`); } if (colorEntries.length > 0) { colorOverrideEntries.push(`${tab(3)}'${colorName}': {\n${colorEntries.join('\n')}\n${tab(3)}},`); } }); if (colorOverrideEntries.length > 0) { parts.push(`${tab(2)}colorOverrides: {\n${colorOverrideEntries.join('\n')}\n${tab(2)}},`); } const camelCaseName = kebabCaseToCamelCase(override.name); return `export const ${camelCaseName}Override = defineColorThemeOverride(\n${tab(1)}theme,\n${tab(1)}'${override.name}',\n${tab(1)}{\n${parts.join('\n')}\n${tab(1)}},\n);`; } function tab(level) { return ' '.repeat(level); } function colorInitValuesEqual(a, b) { if (typeof a !== typeof b) { return false; } const aString = check.isString(a) || a instanceof CSSResult ? String(a) : JSON.stringify(a); const bString = check.isString(b) || b instanceof CSSResult ? String(b) : JSON.stringify(b); return aString === bString; } function extractCssVarName(cssValue) { const match = cssValue.match(/^var\(--([^,)]+)/); return match ? match[1] : undefined; } function colorInitValueToCode(value, indentLevel, paletteVarName) { if (typeof value === 'string') { return `'${value}'`; } else if (typeof value === 'number') { return String(value); } else if (value instanceof CSSResult) { const cssText = String(value); if (paletteVarName) { const varName = extractCssVarName(cssText); if (varName) { return `${paletteVarName}['${varName}']`; } } return `css\`${cssText}\``; } else if ('refBackground' in value || 'refForeground' in value || 'refDefaultBackground' in value || 'refDefaultForeground' in value) { const entries = []; if ('refForeground' in value) { entries.push(`${tab(indentLevel + 1)}refForeground: '${value.refForeground}',`); } if ('refBackground' in value) { entries.push(`${tab(indentLevel + 1)}refBackground: '${value.refBackground}',`); } if ('refDefaultForeground' in value) { entries.push(`${tab(indentLevel + 1)}refDefaultForeground: true,`); } if ('refDefaultBackground' in value) { entries.push(`${tab(indentLevel + 1)}refDefaultBackground: true,`); } return `{\n${entries.join('\n')}\n${tab(indentLevel)}}`; } else { // SingleCssVarDefinition return `'${value.default}'`; } } function colorInitToCode(colorInit, indentLevel, defaultInit, paletteVarName) { const entries = []; if ('foreground' in colorInit && (!defaultInit || !colorInitValuesEqual(colorInit.foreground, defaultInit.foreground)) && !check.hasKey(colorInit.foreground, 'refDefaultForeground')) { // Check if foreground matches default background (use refDefaultBackground) if (defaultInit && colorInitValuesEqual(colorInit.foreground, defaultInit.background)) { entries.push(`${tab(indentLevel + 1)}foreground: {\n${tab(indentLevel + 2)}refDefaultBackground: true,\n${tab(indentLevel + 1)}},`); } else { entries.push(`${tab(indentLevel + 1)}foreground: ${colorInitValueToCode(colorInit.foreground, indentLevel + 1, paletteVarName)},`); } } if ('background' in colorInit && (!defaultInit || !colorInitValuesEqual(colorInit.background, defaultInit.background)) && !check.hasKey(colorInit.background, 'refDefaultBackground')) { // Check if background matches default foreground (use refDefaultForeground) if (defaultInit && colorInitValuesEqual(colorInit.background, defaultInit.foreground)) { entries.push(`${tab(indentLevel + 1)}background: {\n${tab(indentLevel + 2)}refDefaultForeground: true,\n${tab(indentLevel + 1)}},`); } else { entries.push(`${tab(indentLevel + 1)}background: ${colorInitValueToCode(colorInit.background, indentLevel + 1, paletteVarName)},`); } } return `${tab(indentLevel)}{\n${entries.join('\n')}\n${tab(indentLevel)}}`; } function colorThemeInitToCode(colorsInit, indentLevel, defaultInit, paletteVarName) { const entries = getObjectTypedEntries(colorsInit).map(([colorName, colorInit,]) => { return `${tab(indentLevel + 1)}'${colorName}': ${colorInitToCode(colorInit, indentLevel + 1, defaultInit, paletteVarName).trimStart()},`; }); return `${tab(indentLevel)}{\n${entries.join('\n')}\n${tab(indentLevel)}}`; }