import { useCSSVariable } from 'uniwind'; /** * Unique brand symbol used to prevent accidental array destructuring of a * single theme color value returned from `useThemeColor`. */ declare const _colorValueBrand: unique symbol; /** * A resolved theme color string. * * This type intentionally removes `[Symbol.iterator]` so that TypeScript * surfaces a `never`-typed element when the value is array-destructured, * making the misuse visible in the IDE immediately. * * @example * // ✅ Correct – single value * const color = useThemeColor('muted'); * * @example * // ✅ Correct – multiple values * const [primary, bg] = useThemeColor(['accent', 'background']); * * @example * // ❌ Wrong – destructuring a single-color result yields `never` * const [color] = useThemeColor('muted'); */ export type ThemeColorValue = string & { readonly [_colorValueBrand]: void; /** Removed to prevent accidental array destructuring. */ readonly [Symbol.iterator]: never; }; /** * Theme colors as const array for efficient mapping * Ordered to match the order in src/styles/theme.css */ const THEME_COLORS = [ 'background', 'foreground', 'surface', 'surface-foreground', 'surface-hover', 'surface-secondary', 'surface-secondary-foreground', 'surface-tertiary', 'surface-tertiary-foreground', 'overlay', 'overlay-foreground', 'backdrop', 'muted', 'accent', 'accent-foreground', 'segment', 'segment-foreground', 'border', 'separator', 'focus', 'link', 'default', 'default-foreground', 'success', 'success-foreground', 'warning', 'warning-foreground', 'danger', 'danger-foreground', 'field', 'field-foreground', 'field-placeholder', 'field-border', 'background-secondary', 'background-tertiary', 'background-inverse', 'default-hover', 'accent-hover', 'success-hover', 'warning-hover', 'danger-hover', 'field-hover', 'field-focus', 'field-border-hover', 'field-border-focus', 'default-soft', 'default-soft-foreground', 'default-soft-hover', 'accent-soft', 'accent-soft-foreground', 'accent-soft-hover', 'danger-soft', 'danger-soft-foreground', 'danger-soft-hover', 'warning-soft', 'warning-soft-foreground', 'warning-soft-hover', 'success-soft', 'success-soft-foreground', 'success-soft-hover', 'separator-secondary', 'separator-tertiary', 'border-secondary', 'border-tertiary', ] as const; /** * Theme colors type derived from THEME_COLORS array */ export type ThemeColor = (typeof THEME_COLORS)[number]; /** * Helper type to create a tuple of strings with the same length as the input array */ type CreateStringTuple< N extends number, TAcc extends string[] = [], > = TAcc['length'] extends N ? TAcc : CreateStringTuple; /** * Hook to retrieve theme color values from CSS variables. * Supports both single color and multiple colors for efficient batch retrieval. * * @param themeColor - Single theme color name or array of theme color names * @returns `ThemeColorValue` for a single name, or a string tuple/array for multiple names. * * @example * // Single color – returns `ThemeColorValue` (not destructurable) * const primaryColor = useThemeColor('accent'); * * @example * // Multiple colors – returns a typed string tuple (destructurable) * const [primaryColor, backgroundColor] = useThemeColor(['accent', 'background']); */ export function useThemeColor(themeColor: ThemeColor): ThemeColorValue; export function useThemeColor( themeColor: T ): CreateStringTuple; export function useThemeColor(themeColor: ThemeColor[]): string[]; export function useThemeColor( themeColor: ThemeColor | ThemeColor[] ): ThemeColorValue | string[] { const isArray = Array.isArray(themeColor); const cssVariables = isArray ? themeColor.map((color) => `--color-${color}`) : [`--color-${themeColor}`]; const resolvedColors = useCSSVariable(cssVariables); const processedColors: string[] = resolvedColors.map((color) => { if (typeof color === 'string') { return color; } if (typeof color === 'number') { return String(color); } return 'invalid'; }); if (isArray) { return processedColors; } /** `cssVariables` always contains one entry when `isArray` is false, so index 0 is always defined. */ return (processedColors[0] ?? 'invalid') as ThemeColorValue; }