@@ -2,6 +2,8 @@ import { camelCaseToKebabCase, kebabCaseToCamelCase } from '@/utils/text-case'
22
33import { setHSLA , shiftHSLA , parseColorToRGB , parseColorToHSL , rgbToString , hslToString , colorToString , type RGBObject , type HSLObject } from '@/utils/color'
44
5+ import type { Config , Palette } from './types'
6+
57export const isCSSVariable = ( strColor : string ) : boolean => / v a r \( - - .+ \) / . test ( strColor )
68export const cssVariableName = ( colorName : string ) => `--va-${ camelCaseToKebabCase ( colorName ) } `
79export const normalizeColorName = ( colorName : string ) => kebabCaseToCamelCase ( colorName )
@@ -122,63 +124,45 @@ export const isColorTransparent = (color: string) => {
122124
123125export { isColor } from './../../utils/color'
124126
125- type Palette = Record < string , string >
126-
127- // Values in a theme config can be:
128- // - a token string ("blue10")
129- // - a prioritized list of token strings (["redPaleDark","redSoftDark"])
130- // - a nested object (e.g., { brand: "...", danger: "..." })
131- type ConfigValue = string | string [ ] | Record < string , any >
132- type Config = Record < string , ConfigValue >
133-
134127/**
135- * resolveColors
128+ * Resolves color token references in config to actual color values from palette.
136129 *
137- * Replaces token references in a config using a palette. Behavior:
138- * - string: replace with palette[token] if present; otherwise keep as-is
139- * - string[]: treat as fallback list; return the first palette hit;
140- * if none hit, return the first element unchanged
141- * - object: recurse into properties
130+ * Handles three types:
131+ * - String: "blue10" → palette["blue10"] or unchanged if not found
132+ * - Array: ["redPaleDark", "redSoftDark"] → first match from palette, or first item if none match
133+ * - Object: Recursively resolves nested properties
142134 *
143- * Example:
144- * dangerPressed: ["redPaleDark", "redSoftDark"]
145- * -> resolves to palette["redPaleDark"] if it exists,
146- * otherwise palette["redSoftDark"] if it exists,
147- * otherwise "redPaleDark" (the first item) unchanged.
135+ * @example
136+ * resolveColors(
137+ * { danger: "red", fallback: ["custom", "red"] },
138+ * { red: "#ff0000" }
139+ * )
140+ * // Returns: { danger: "#ff0000", fallback: "#ff0000" }
148141 */
149142export function resolveColors ( config : Config , palette : Palette ) : Config {
150- const replaceValues = ( obj : any ) : any => {
151- // simple token string
152- if ( typeof obj === 'string' ) {
153- return palette [ obj ] ?? obj
143+ const resolve = ( value : any ) : any => {
144+ if ( typeof value === 'string' ) {
145+ return palette [ value ] ?? value
154146 }
155147
156- // arrays
157- if ( Array . isArray ( obj ) ) {
158- // If it's a list of strings, treat as fallback tokens
159- if ( obj . every ( ( x ) => typeof x === 'string' ) ) {
160- for ( const token of obj ) {
161- if ( palette [ token ] ) { return palette [ token ] }
162- }
163- // no token matched: return the first entry unchanged (best-effort fallback)
164- return obj [ 0 ]
148+ if ( Array . isArray ( value ) ) {
149+ // String array = fallback list (try each token until one matches)
150+ if ( value . every ( ( x ) => typeof x === 'string' ) ) {
151+ const match = value . find ( ( token ) => palette [ token ] )
152+ return match ? palette [ match ] : value [ 0 ]
165153 }
166- // Mixed array / non-strings: preserve previous behavior ( map recursively)
167- return obj . map ( replaceValues )
154+ // Non-string array = map recursively
155+ return value . map ( resolve )
168156 }
169157
170- // objects (recurse)
171- if ( obj && typeof obj === 'object' ) {
172- const result : Record < string , any > = { }
173- for ( const key of Object . keys ( obj ) ) {
174- result [ key ] = replaceValues ( obj [ key ] )
175- }
176- return result
158+ if ( value && typeof value === 'object' ) {
159+ return Object . fromEntries (
160+ Object . entries ( value ) . map ( ( [ key , val ] ) => [ key , resolve ( val ) ] ) ,
161+ )
177162 }
178163
179- // everything else (numbers, null, etc.)
180- return obj
164+ return value
181165 }
182166
183- return replaceValues ( config )
167+ return resolve ( config )
184168}
0 commit comments