@tamagui/create-theme 3.0.0-beta.1402.1 → 3.0.0-beta.1407.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tamagui/create-theme",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.1407.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"files": [
|
|
6
6
|
"src",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"clean:build": "tamagui-build clean:build"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@tamagui/build": "3.0.0-beta.
|
|
39
|
+
"@tamagui/build": "3.0.0-beta.1407.1",
|
|
40
40
|
"vitest": "4.1.0"
|
|
41
41
|
},
|
|
42
42
|
"repository": {
|
package/src/createThemes.tsx
CHANGED
|
@@ -30,7 +30,7 @@ export type ThemeTree = {
|
|
|
30
30
|
|
|
31
31
|
type ColorLiteral = `#${string}` | `rgb${string}` | `hsl${string}` | 'transparent'
|
|
32
32
|
|
|
33
|
-
type ThemeInputValue<Tokens extends ThemeTokens> =
|
|
33
|
+
export type ThemeInputValue<Tokens extends ThemeTokens> =
|
|
34
34
|
| Extract<keyof Tokens['color'], string>
|
|
35
35
|
| ColorLiteral
|
|
36
36
|
|
package/types/createThemes.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export type ThemeTree = {
|
|
|
19
19
|
children?: ThemeChildren;
|
|
20
20
|
};
|
|
21
21
|
type ColorLiteral = `#${string}` | `rgb${string}` | `hsl${string}` | "transparent";
|
|
22
|
-
type ThemeInputValue<Tokens extends ThemeTokens> = Extract<keyof Tokens["color"], string> | ColorLiteral;
|
|
22
|
+
export type ThemeInputValue<Tokens extends ThemeTokens> = Extract<keyof Tokens["color"], string> | ColorLiteral;
|
|
23
23
|
type ResolvedDefinition<Definition> = Definition extends (...args: any[]) => infer Result ? Exclude<Result, null> : Definition;
|
|
24
24
|
type DefinitionChildren<Definition> = ResolvedDefinition<Definition> extends {
|
|
25
25
|
children?: infer Children;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"mappings": "AAAA,YAAY;AAEZ,YAAY,cAAc;CACxB,OAAO,eAAe;;AAGxB,YAAY,cAAc;AAE1B,YAAY,uBAAuB,eAAe,cAAc,eAAe;CAC7E,QAAQ;;AAGV,YAAY,wBAAwB;CAClC,SAAS,eAAe;CACxB,WAAW;;;AAIb,YAAY,oBAAoB,eAAe,cAAc,eACzD,0BACE,SAAS,uBAAuB,YAAY;AAElD,YAAY,gBAAgB,eAAe;AAE3C,YAAY,YAAY;CACtB,OAAO;CACP,MAAM;CACN,WAAW;;KAGR,gEAAgE;
|
|
2
|
+
"mappings": "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",
|
|
3
3
|
"names": [],
|
|
4
4
|
"sources": [
|
|
5
5
|
"src/createThemes.tsx"
|
|
6
6
|
],
|
|
7
7
|
"version": 3,
|
|
8
8
|
"sourcesContent": [
|
|
9
|
-
"export type ThemeValue = string\n\nexport type ThemeTokens = {\n color: Record<string, ThemeValue>\n}\n\nexport type ThemeRecipe = Record<string, unknown>\n\nexport type ThemeDefinitionContext<Parent extends ThemeRecipe = ThemeRecipe> = {\n parent: Parent\n}\n\nexport type ThemeDefinitionObject = {\n values?: Record<string, ThemeValue>\n children?: ThemeChildren\n [key: string]: unknown\n}\n\nexport type ThemeTreeDefinition<Parent extends ThemeRecipe = ThemeRecipe> =\n | ThemeDefinitionObject\n | ((context: ThemeDefinitionContext<Parent>) => ThemeDefinitionObject | null)\n\nexport type ThemeChildren = Record<string, ThemeTreeDefinition>\n\nexport type ThemeTree = {\n light: ThemeTreeDefinition\n dark: ThemeTreeDefinition\n children?: ThemeChildren\n}\n\ntype ColorLiteral = `#${string}` | `rgb${string}` | `hsl${string}` | 'transparent'\n\ntype ThemeInputValue<Tokens extends ThemeTokens> =\n | Extract<keyof Tokens['color'], string>\n | ColorLiteral\n\ntype ResolvedDefinition<Definition> = Definition extends (...args: any[]) => infer Result\n ? Exclude<Result, null>\n : Definition\n\ntype DefinitionChildren<Definition> =\n ResolvedDefinition<Definition> extends {\n children?: infer Children\n }\n ? Children\n : never\n\ntype ChildThemeNames<Parent extends string, Children> =\n Children extends Record<string, unknown>\n ? {\n [Name in Extract<keyof Children, string>]:\n | `${Parent}_${Name}`\n | ChildThemeNames<`${Parent}_${Name}`, DefinitionChildren<Children[Name]>>\n }[Extract<keyof Children, string>]\n : never\n\nexport type ThemeNames<Tree extends ThemeTree> =\n | 'light'\n | 'dark'\n | ChildThemeNames<'light', Tree['children']>\n | ChildThemeNames<'dark', Tree['children']>\n | ChildThemeNames<'light', DefinitionChildren<Tree['light']>>\n | ChildThemeNames<'dark', DefinitionChildren<Tree['dark']>>\n\ntype RecipeFields<Definition> = Omit<\n ResolvedDefinition<Definition>,\n 'children' | 'values'\n>\n\ntype ChildDefinitions<\n Children,\n Depth extends readonly unknown[],\n> = Depth extends readonly [unknown, ...infer Rest]\n ? Children extends Record<string, unknown>\n ? Children[keyof Children] | DefinitionsWithin<Children[keyof Children], Rest>\n : never\n : never\n\ntype DefinitionsWithin<Definition, Depth extends readonly unknown[]> =\n | Definition\n | ChildDefinitions<DefinitionChildren<Definition>, Depth>\n\ntype DefinitionsInTree<Tree extends ThemeTree> =\n | DefinitionsWithin<Tree['light'], [1, 1, 1, 1, 1, 1]>\n | DefinitionsWithin<Tree['dark'], [1, 1, 1, 1, 1, 1]>\n | ChildDefinitions<Tree['children'], [1, 1, 1, 1, 1, 1]>\n\ntype KeysOfUnion<Union> = Union extends Union ? keyof Union : never\n\ntype ValueOfUnion<Union, Key extends PropertyKey> = Union extends Union\n ? Key extends keyof Union\n ? Union[Key]\n : never\n : never\n\ntype MergeRecipeUnion<Union> = {\n [Key in KeysOfUnion<Union>]: ValueOfUnion<Union, Key>\n}\n\ntype RootRecipe<Tree extends ThemeTree> =\n | RecipeFields<Tree['light']>\n | RecipeFields<Tree['dark']>\n\ntype RecipeForTree<Tree extends ThemeTree> = {\n [Key in keyof RootRecipe<Tree>]: ValueOfUnion<RootRecipe<Tree>, Key>\n} & Partial<MergeRecipeUnion<RecipeFields<DefinitionsInTree<Tree>>>>\n\nexport type GetThemeContext<\n Tokens extends ThemeTokens = ThemeTokens,\n Recipe extends ThemeRecipe = ThemeRecipe,\n> = {\n recipe: Recipe\n name: string\n tokens: Tokens\n}\n\ntype InvalidValueKeys<Values, Theme> = Exclude<keyof Values, keyof Theme>\n\ntype ValidatedValues<Values, Theme, Tokens extends ThemeTokens> =\n Values extends Record<string, unknown>\n ? Values & {\n [Key in InvalidValueKeys<Values, Theme>]: never\n } & {\n [Key in keyof Values]: Values[Key] extends ThemeInputValue<Tokens>\n ? Values[Key]\n : never\n }\n : never\n\ntype ValidatedChildren<Children, Theme, Tokens extends ThemeTokens> =\n Children extends Record<string, unknown>\n ? {\n [Name in keyof Children]: ValidatedDefinition<Children[Name], Theme, Tokens>\n }\n : never\n\ntype ValidatedDefinition<\n Definition,\n Theme,\n Tokens extends ThemeTokens,\n> = Definition extends (...args: infer Args) => infer Result\n ? (\n ...args: Args\n ) => Result extends null ? null : ValidatedDefinitionObject<Result, Theme, Tokens>\n : ValidatedDefinitionObject<Definition, Theme, Tokens>\n\ntype ValidatedDefinitionObject<Definition, Theme, Tokens extends ThemeTokens> =\n Definition extends Record<string, unknown>\n ? Definition &\n ('values' extends keyof Definition\n ? {\n values: ValidatedValues<Definition['values'], Theme, Tokens>\n }\n : unknown) &\n ('children' extends keyof Definition\n ? {\n children: ValidatedChildren<Definition['children'], Theme, Tokens>\n }\n : unknown)\n : never\n\ntype ValidatedTree<Tree extends ThemeTree, Theme, Tokens extends ThemeTokens> = Tree & {\n light: ValidatedDefinition<Tree['light'], Theme, Tokens>\n dark: ValidatedDefinition<Tree['dark'], Theme, Tokens>\n children?: ValidatedChildren<Tree['children'], Theme, Tokens>\n}\n\ntype ValuesInDefinition<Definition> =\n ResolvedDefinition<Definition> extends {\n values?: infer Values\n }\n ? Values\n : never\n\ntype ValueDefinitionsWithin<Definition, Depth extends readonly unknown[]> =\n | ValuesInDefinition<Definition>\n | (Depth extends readonly [unknown, ...infer Rest]\n ? DefinitionChildren<Definition> extends infer Children\n ? Children extends Record<string, unknown>\n ? ValueDefinitionsWithin<Children[keyof Children], Rest>\n : never\n : never\n : never)\n\ntype ExplicitTheme<Tree extends ThemeTree> = MergeRecipeUnion<\n | ValueDefinitionsWithin<Tree['light'], [1, 1, 1, 1, 1, 1]>\n | ValueDefinitionsWithin<Tree['dark'], [1, 1, 1, 1, 1, 1]>\n | (Tree['children'] extends infer Children\n ? Children extends Record<string, unknown>\n ? ValueDefinitionsWithin<Children[keyof Children], [1, 1, 1, 1, 1, 1]>\n : never\n : never)\n>\n\nexport type CreatedThemes<Names extends string, Theme extends Record<string, string>> = {\n [Name in Names]: { [Key in keyof Theme]: string }\n}\n\nexport function createThemes<\n const Tokens extends ThemeTokens,\n const Tree extends ThemeTree,\n const Theme extends Record<string, ThemeInputValue<Tokens>>,\n>(\n tokens: Tokens,\n tree: ValidatedTree<Tree, Theme, Tokens>,\n options: {\n getTheme: (context: GetThemeContext<Tokens, RecipeForTree<Tree>>) => Theme\n }\n): CreatedThemes<ThemeNames<Tree>, Theme>\n\nexport function createThemes<\n const Tokens extends ThemeTokens,\n const Tree extends ThemeTree,\n>(\n tokens: Tokens,\n tree: ValidatedTree<Tree, Record<string, string>, Tokens>,\n options?: { getTheme?: undefined }\n): CreatedThemes<ThemeNames<Tree>, ExplicitTheme<Tree>>\n\nexport function createThemes(\n tokens: ThemeTokens,\n tree: ThemeTree,\n options?: {\n getTheme?: (context: GetThemeContext) => Record<string, string>\n }\n): Record<string, Record<string, string>> {\n const rootKeys = Object.keys(tree).filter((key) => key !== 'children')\n if (rootKeys.length !== 2 || !('light' in tree) || !('dark' in tree)) {\n throw new Error('createThemes tree must have exactly the roots \"light\" and \"dark\"')\n }\n\n const themes: Record<string, Record<string, string>> = {}\n const deduped = new Map<string, Record<string, string>>()\n\n const add = (\n name: string,\n definition: ThemeTreeDefinition,\n parent: ThemeRecipe,\n inheritedChildren?: ThemeChildren\n ): void => {\n const resolvedDefinition =\n typeof definition === 'function' ? definition({ parent }) : definition\n if (resolvedDefinition === null) return\n\n const { values, children, ...recipeFields } = resolvedDefinition\n const recipe = { ...parent, ...recipeFields }\n const unresolved = {\n ...options?.getTheme?.({ recipe, name, tokens }),\n ...values,\n }\n const resolved: Record<string, string> = {}\n\n for (const key in unresolved) {\n const value = unresolved[key]\n const token = tokens.color[value]\n if (token !== undefined) {\n resolved[key] = token\n continue\n }\n\n const isColor =\n value === 'transparent' ||\n /^#(?:[\\da-f]{3,4}|[\\da-f]{6}|[\\da-f]{8})$/i.test(value) ||\n /^(?:rgb|rgba|hsl|hsla)\\(\\s*[^)]+\\)$/i.test(value)\n if (isColor) {\n resolved[key] = value\n continue\n }\n\n let nearest = ''\n let nearestDistance = Number.POSITIVE_INFINITY\n for (const tokenName in tokens.color) {\n const previous = Array.from({ length: tokenName.length + 1 }, (_, index) => index)\n for (let valueIndex = 0; valueIndex < value.length; valueIndex++) {\n let diagonal = previous[0]!\n previous[0] = valueIndex + 1\n for (let tokenIndex = 0; tokenIndex < tokenName.length; tokenIndex++) {\n const above = previous[tokenIndex + 1]!\n previous[tokenIndex + 1] = Math.min(\n previous[tokenIndex]! + 1,\n above + 1,\n diagonal + (value[valueIndex] === tokenName[tokenIndex] ? 0 : 1)\n )\n diagonal = above\n }\n }\n const distance = previous[tokenName.length]!\n if (distance < nearestDistance) {\n nearest = tokenName\n nearestDistance = distance\n }\n }\n\n throw new Error(\n `Invalid color value \"${value}\" for theme \"${name}\" key \"${key}\".${nearest ? ` Did you mean token \"${nearest}\"?` : ''}`\n )\n }\n\n const identity = JSON.stringify(\n Object.keys(resolved)\n .sort()\n .map((key) => [key, resolved[key]])\n )\n themes[name] = deduped.get(identity) || resolved\n deduped.set(identity, themes[name]!)\n\n const childSets = [inheritedChildren, children]\n for (const childSet of childSets) {\n if (!childSet) continue\n for (const childName in childSet) {\n const fullName = `${name}_${childName}`\n if (fullName in themes) {\n throw new Error(`Duplicate generated theme name \"${fullName}\"`)\n }\n add(fullName, childSet[childName]!, recipe)\n }\n }\n }\n\n add('light', tree.light, {}, tree.children)\n add('dark', tree.dark, {}, tree.children)\n\n return themes\n}\n"
|
|
9
|
+
"export type ThemeValue = string\n\nexport type ThemeTokens = {\n color: Record<string, ThemeValue>\n}\n\nexport type ThemeRecipe = Record<string, unknown>\n\nexport type ThemeDefinitionContext<Parent extends ThemeRecipe = ThemeRecipe> = {\n parent: Parent\n}\n\nexport type ThemeDefinitionObject = {\n values?: Record<string, ThemeValue>\n children?: ThemeChildren\n [key: string]: unknown\n}\n\nexport type ThemeTreeDefinition<Parent extends ThemeRecipe = ThemeRecipe> =\n | ThemeDefinitionObject\n | ((context: ThemeDefinitionContext<Parent>) => ThemeDefinitionObject | null)\n\nexport type ThemeChildren = Record<string, ThemeTreeDefinition>\n\nexport type ThemeTree = {\n light: ThemeTreeDefinition\n dark: ThemeTreeDefinition\n children?: ThemeChildren\n}\n\ntype ColorLiteral = `#${string}` | `rgb${string}` | `hsl${string}` | 'transparent'\n\nexport type ThemeInputValue<Tokens extends ThemeTokens> =\n | Extract<keyof Tokens['color'], string>\n | ColorLiteral\n\ntype ResolvedDefinition<Definition> = Definition extends (...args: any[]) => infer Result\n ? Exclude<Result, null>\n : Definition\n\ntype DefinitionChildren<Definition> =\n ResolvedDefinition<Definition> extends {\n children?: infer Children\n }\n ? Children\n : never\n\ntype ChildThemeNames<Parent extends string, Children> =\n Children extends Record<string, unknown>\n ? {\n [Name in Extract<keyof Children, string>]:\n | `${Parent}_${Name}`\n | ChildThemeNames<`${Parent}_${Name}`, DefinitionChildren<Children[Name]>>\n }[Extract<keyof Children, string>]\n : never\n\nexport type ThemeNames<Tree extends ThemeTree> =\n | 'light'\n | 'dark'\n | ChildThemeNames<'light', Tree['children']>\n | ChildThemeNames<'dark', Tree['children']>\n | ChildThemeNames<'light', DefinitionChildren<Tree['light']>>\n | ChildThemeNames<'dark', DefinitionChildren<Tree['dark']>>\n\ntype RecipeFields<Definition> = Omit<\n ResolvedDefinition<Definition>,\n 'children' | 'values'\n>\n\ntype ChildDefinitions<\n Children,\n Depth extends readonly unknown[],\n> = Depth extends readonly [unknown, ...infer Rest]\n ? Children extends Record<string, unknown>\n ? Children[keyof Children] | DefinitionsWithin<Children[keyof Children], Rest>\n : never\n : never\n\ntype DefinitionsWithin<Definition, Depth extends readonly unknown[]> =\n | Definition\n | ChildDefinitions<DefinitionChildren<Definition>, Depth>\n\ntype DefinitionsInTree<Tree extends ThemeTree> =\n | DefinitionsWithin<Tree['light'], [1, 1, 1, 1, 1, 1]>\n | DefinitionsWithin<Tree['dark'], [1, 1, 1, 1, 1, 1]>\n | ChildDefinitions<Tree['children'], [1, 1, 1, 1, 1, 1]>\n\ntype KeysOfUnion<Union> = Union extends Union ? keyof Union : never\n\ntype ValueOfUnion<Union, Key extends PropertyKey> = Union extends Union\n ? Key extends keyof Union\n ? Union[Key]\n : never\n : never\n\ntype MergeRecipeUnion<Union> = {\n [Key in KeysOfUnion<Union>]: ValueOfUnion<Union, Key>\n}\n\ntype RootRecipe<Tree extends ThemeTree> =\n | RecipeFields<Tree['light']>\n | RecipeFields<Tree['dark']>\n\ntype RecipeForTree<Tree extends ThemeTree> = {\n [Key in keyof RootRecipe<Tree>]: ValueOfUnion<RootRecipe<Tree>, Key>\n} & Partial<MergeRecipeUnion<RecipeFields<DefinitionsInTree<Tree>>>>\n\nexport type GetThemeContext<\n Tokens extends ThemeTokens = ThemeTokens,\n Recipe extends ThemeRecipe = ThemeRecipe,\n> = {\n recipe: Recipe\n name: string\n tokens: Tokens\n}\n\ntype InvalidValueKeys<Values, Theme> = Exclude<keyof Values, keyof Theme>\n\ntype ValidatedValues<Values, Theme, Tokens extends ThemeTokens> =\n Values extends Record<string, unknown>\n ? Values & {\n [Key in InvalidValueKeys<Values, Theme>]: never\n } & {\n [Key in keyof Values]: Values[Key] extends ThemeInputValue<Tokens>\n ? Values[Key]\n : never\n }\n : never\n\ntype ValidatedChildren<Children, Theme, Tokens extends ThemeTokens> =\n Children extends Record<string, unknown>\n ? {\n [Name in keyof Children]: ValidatedDefinition<Children[Name], Theme, Tokens>\n }\n : never\n\ntype ValidatedDefinition<\n Definition,\n Theme,\n Tokens extends ThemeTokens,\n> = Definition extends (...args: infer Args) => infer Result\n ? (\n ...args: Args\n ) => Result extends null ? null : ValidatedDefinitionObject<Result, Theme, Tokens>\n : ValidatedDefinitionObject<Definition, Theme, Tokens>\n\ntype ValidatedDefinitionObject<Definition, Theme, Tokens extends ThemeTokens> =\n Definition extends Record<string, unknown>\n ? Definition &\n ('values' extends keyof Definition\n ? {\n values: ValidatedValues<Definition['values'], Theme, Tokens>\n }\n : unknown) &\n ('children' extends keyof Definition\n ? {\n children: ValidatedChildren<Definition['children'], Theme, Tokens>\n }\n : unknown)\n : never\n\ntype ValidatedTree<Tree extends ThemeTree, Theme, Tokens extends ThemeTokens> = Tree & {\n light: ValidatedDefinition<Tree['light'], Theme, Tokens>\n dark: ValidatedDefinition<Tree['dark'], Theme, Tokens>\n children?: ValidatedChildren<Tree['children'], Theme, Tokens>\n}\n\ntype ValuesInDefinition<Definition> =\n ResolvedDefinition<Definition> extends {\n values?: infer Values\n }\n ? Values\n : never\n\ntype ValueDefinitionsWithin<Definition, Depth extends readonly unknown[]> =\n | ValuesInDefinition<Definition>\n | (Depth extends readonly [unknown, ...infer Rest]\n ? DefinitionChildren<Definition> extends infer Children\n ? Children extends Record<string, unknown>\n ? ValueDefinitionsWithin<Children[keyof Children], Rest>\n : never\n : never\n : never)\n\ntype ExplicitTheme<Tree extends ThemeTree> = MergeRecipeUnion<\n | ValueDefinitionsWithin<Tree['light'], [1, 1, 1, 1, 1, 1]>\n | ValueDefinitionsWithin<Tree['dark'], [1, 1, 1, 1, 1, 1]>\n | (Tree['children'] extends infer Children\n ? Children extends Record<string, unknown>\n ? ValueDefinitionsWithin<Children[keyof Children], [1, 1, 1, 1, 1, 1]>\n : never\n : never)\n>\n\nexport type CreatedThemes<Names extends string, Theme extends Record<string, string>> = {\n [Name in Names]: { [Key in keyof Theme]: string }\n}\n\nexport function createThemes<\n const Tokens extends ThemeTokens,\n const Tree extends ThemeTree,\n const Theme extends Record<string, ThemeInputValue<Tokens>>,\n>(\n tokens: Tokens,\n tree: ValidatedTree<Tree, Theme, Tokens>,\n options: {\n getTheme: (context: GetThemeContext<Tokens, RecipeForTree<Tree>>) => Theme\n }\n): CreatedThemes<ThemeNames<Tree>, Theme>\n\nexport function createThemes<\n const Tokens extends ThemeTokens,\n const Tree extends ThemeTree,\n>(\n tokens: Tokens,\n tree: ValidatedTree<Tree, Record<string, string>, Tokens>,\n options?: { getTheme?: undefined }\n): CreatedThemes<ThemeNames<Tree>, ExplicitTheme<Tree>>\n\nexport function createThemes(\n tokens: ThemeTokens,\n tree: ThemeTree,\n options?: {\n getTheme?: (context: GetThemeContext) => Record<string, string>\n }\n): Record<string, Record<string, string>> {\n const rootKeys = Object.keys(tree).filter((key) => key !== 'children')\n if (rootKeys.length !== 2 || !('light' in tree) || !('dark' in tree)) {\n throw new Error('createThemes tree must have exactly the roots \"light\" and \"dark\"')\n }\n\n const themes: Record<string, Record<string, string>> = {}\n const deduped = new Map<string, Record<string, string>>()\n\n const add = (\n name: string,\n definition: ThemeTreeDefinition,\n parent: ThemeRecipe,\n inheritedChildren?: ThemeChildren\n ): void => {\n const resolvedDefinition =\n typeof definition === 'function' ? definition({ parent }) : definition\n if (resolvedDefinition === null) return\n\n const { values, children, ...recipeFields } = resolvedDefinition\n const recipe = { ...parent, ...recipeFields }\n const unresolved = {\n ...options?.getTheme?.({ recipe, name, tokens }),\n ...values,\n }\n const resolved: Record<string, string> = {}\n\n for (const key in unresolved) {\n const value = unresolved[key]\n const token = tokens.color[value]\n if (token !== undefined) {\n resolved[key] = token\n continue\n }\n\n const isColor =\n value === 'transparent' ||\n /^#(?:[\\da-f]{3,4}|[\\da-f]{6}|[\\da-f]{8})$/i.test(value) ||\n /^(?:rgb|rgba|hsl|hsla)\\(\\s*[^)]+\\)$/i.test(value)\n if (isColor) {\n resolved[key] = value\n continue\n }\n\n let nearest = ''\n let nearestDistance = Number.POSITIVE_INFINITY\n for (const tokenName in tokens.color) {\n const previous = Array.from({ length: tokenName.length + 1 }, (_, index) => index)\n for (let valueIndex = 0; valueIndex < value.length; valueIndex++) {\n let diagonal = previous[0]!\n previous[0] = valueIndex + 1\n for (let tokenIndex = 0; tokenIndex < tokenName.length; tokenIndex++) {\n const above = previous[tokenIndex + 1]!\n previous[tokenIndex + 1] = Math.min(\n previous[tokenIndex]! + 1,\n above + 1,\n diagonal + (value[valueIndex] === tokenName[tokenIndex] ? 0 : 1)\n )\n diagonal = above\n }\n }\n const distance = previous[tokenName.length]!\n if (distance < nearestDistance) {\n nearest = tokenName\n nearestDistance = distance\n }\n }\n\n throw new Error(\n `Invalid color value \"${value}\" for theme \"${name}\" key \"${key}\".${nearest ? ` Did you mean token \"${nearest}\"?` : ''}`\n )\n }\n\n const identity = JSON.stringify(\n Object.keys(resolved)\n .sort()\n .map((key) => [key, resolved[key]])\n )\n themes[name] = deduped.get(identity) || resolved\n deduped.set(identity, themes[name]!)\n\n const childSets = [inheritedChildren, children]\n for (const childSet of childSets) {\n if (!childSet) continue\n for (const childName in childSet) {\n const fullName = `${name}_${childName}`\n if (fullName in themes) {\n throw new Error(`Duplicate generated theme name \"${fullName}\"`)\n }\n add(fullName, childSet[childName]!, recipe)\n }\n }\n }\n\n add('light', tree.light, {}, tree.children)\n add('dark', tree.dark, {}, tree.children)\n\n return themes\n}\n"
|
|
10
10
|
]
|
|
11
11
|
}
|