@hanzogui/theme-builder 2.0.0-rc.41-hanzoai.5

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.
Files changed (124) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/ThemeBuilder.cjs +248 -0
  3. package/dist/cjs/ThemeBuilder.native.js +338 -0
  4. package/dist/cjs/ThemeBuilder.native.js.map +1 -0
  5. package/dist/cjs/createStudioThemes.cjs +42 -0
  6. package/dist/cjs/createStudioThemes.native.js +45 -0
  7. package/dist/cjs/createStudioThemes.native.js.map +1 -0
  8. package/dist/cjs/createThemes.cjs +395 -0
  9. package/dist/cjs/createThemes.native.js +405 -0
  10. package/dist/cjs/createThemes.native.js.map +1 -0
  11. package/dist/cjs/defaultComponentThemes.cjs +86 -0
  12. package/dist/cjs/defaultComponentThemes.native.js +89 -0
  13. package/dist/cjs/defaultComponentThemes.native.js.map +1 -0
  14. package/dist/cjs/defaultTemplates.cjs +154 -0
  15. package/dist/cjs/defaultTemplates.native.js +162 -0
  16. package/dist/cjs/defaultTemplates.native.js.map +1 -0
  17. package/dist/cjs/defaultTemplatesStronger.cjs +152 -0
  18. package/dist/cjs/defaultTemplatesStronger.native.js +160 -0
  19. package/dist/cjs/defaultTemplatesStronger.native.js.map +1 -0
  20. package/dist/cjs/defaultTemplatesStrongest.cjs +152 -0
  21. package/dist/cjs/defaultTemplatesStrongest.native.js +160 -0
  22. package/dist/cjs/defaultTemplatesStrongest.native.js.map +1 -0
  23. package/dist/cjs/getThemeSuitePalettes.cjs +92 -0
  24. package/dist/cjs/getThemeSuitePalettes.native.js +117 -0
  25. package/dist/cjs/getThemeSuitePalettes.native.js.map +1 -0
  26. package/dist/cjs/helpers.cjs +36 -0
  27. package/dist/cjs/helpers.native.js +41 -0
  28. package/dist/cjs/helpers.native.js.map +1 -0
  29. package/dist/cjs/index.cjs +45 -0
  30. package/dist/cjs/index.native.js +48 -0
  31. package/dist/cjs/index.native.js.map +1 -0
  32. package/dist/cjs/masks.cjs +117 -0
  33. package/dist/cjs/masks.native.js +120 -0
  34. package/dist/cjs/masks.native.js.map +1 -0
  35. package/dist/cjs/types.cjs +18 -0
  36. package/dist/cjs/types.native.js +21 -0
  37. package/dist/cjs/types.native.js.map +1 -0
  38. package/dist/esm/ThemeBuilder.mjs +222 -0
  39. package/dist/esm/ThemeBuilder.mjs.map +1 -0
  40. package/dist/esm/ThemeBuilder.native.js +309 -0
  41. package/dist/esm/ThemeBuilder.native.js.map +1 -0
  42. package/dist/esm/createStudioThemes.mjs +17 -0
  43. package/dist/esm/createStudioThemes.mjs.map +1 -0
  44. package/dist/esm/createStudioThemes.native.js +17 -0
  45. package/dist/esm/createStudioThemes.native.js.map +1 -0
  46. package/dist/esm/createThemes.mjs +364 -0
  47. package/dist/esm/createThemes.mjs.map +1 -0
  48. package/dist/esm/createThemes.native.js +371 -0
  49. package/dist/esm/createThemes.native.js.map +1 -0
  50. package/dist/esm/defaultComponentThemes.mjs +61 -0
  51. package/dist/esm/defaultComponentThemes.mjs.map +1 -0
  52. package/dist/esm/defaultComponentThemes.native.js +61 -0
  53. package/dist/esm/defaultComponentThemes.native.js.map +1 -0
  54. package/dist/esm/defaultTemplates.mjs +129 -0
  55. package/dist/esm/defaultTemplates.mjs.map +1 -0
  56. package/dist/esm/defaultTemplates.native.js +134 -0
  57. package/dist/esm/defaultTemplates.native.js.map +1 -0
  58. package/dist/esm/defaultTemplatesStronger.mjs +127 -0
  59. package/dist/esm/defaultTemplatesStronger.mjs.map +1 -0
  60. package/dist/esm/defaultTemplatesStronger.native.js +132 -0
  61. package/dist/esm/defaultTemplatesStronger.native.js.map +1 -0
  62. package/dist/esm/defaultTemplatesStrongest.mjs +127 -0
  63. package/dist/esm/defaultTemplatesStrongest.mjs.map +1 -0
  64. package/dist/esm/defaultTemplatesStrongest.native.js +132 -0
  65. package/dist/esm/defaultTemplatesStrongest.native.js.map +1 -0
  66. package/dist/esm/getThemeSuitePalettes.mjs +66 -0
  67. package/dist/esm/getThemeSuitePalettes.mjs.map +1 -0
  68. package/dist/esm/getThemeSuitePalettes.native.js +88 -0
  69. package/dist/esm/getThemeSuitePalettes.native.js.map +1 -0
  70. package/dist/esm/helpers.mjs +9 -0
  71. package/dist/esm/helpers.mjs.map +1 -0
  72. package/dist/esm/helpers.native.js +11 -0
  73. package/dist/esm/helpers.native.js.map +1 -0
  74. package/dist/esm/index.js +10 -0
  75. package/dist/esm/index.js.map +1 -0
  76. package/dist/esm/index.mjs +10 -0
  77. package/dist/esm/index.mjs.map +1 -0
  78. package/dist/esm/index.native.js +10 -0
  79. package/dist/esm/index.native.js.map +1 -0
  80. package/dist/esm/masks.mjs +92 -0
  81. package/dist/esm/masks.mjs.map +1 -0
  82. package/dist/esm/masks.native.js +92 -0
  83. package/dist/esm/masks.native.js.map +1 -0
  84. package/dist/esm/types.mjs +2 -0
  85. package/dist/esm/types.mjs.map +1 -0
  86. package/dist/esm/types.native.js +2 -0
  87. package/dist/esm/types.native.js.map +1 -0
  88. package/package.json +48 -0
  89. package/src/ThemeBuilder.ts +514 -0
  90. package/src/createStudioThemes.ts +28 -0
  91. package/src/createThemes.ts +794 -0
  92. package/src/defaultComponentThemes.ts +26 -0
  93. package/src/defaultTemplates.ts +157 -0
  94. package/src/defaultTemplatesStronger.ts +152 -0
  95. package/src/defaultTemplatesStrongest.ts +152 -0
  96. package/src/getThemeSuitePalettes.ts +101 -0
  97. package/src/helpers.ts +44 -0
  98. package/src/index.ts +22 -0
  99. package/src/masks.tsx +83 -0
  100. package/src/types.ts +97 -0
  101. package/types/ThemeBuilder.d.ts +80 -0
  102. package/types/ThemeBuilder.d.ts.map +1 -0
  103. package/types/createStudioThemes.d.ts +8 -0
  104. package/types/createStudioThemes.d.ts.map +1 -0
  105. package/types/createThemes.d.ts +141 -0
  106. package/types/createThemes.d.ts.map +1 -0
  107. package/types/defaultComponentThemes.d.ts +63 -0
  108. package/types/defaultComponentThemes.d.ts.map +1 -0
  109. package/types/defaultTemplates.d.ts +42 -0
  110. package/types/defaultTemplates.d.ts.map +1 -0
  111. package/types/defaultTemplatesStronger.d.ts +42 -0
  112. package/types/defaultTemplatesStronger.d.ts.map +1 -0
  113. package/types/defaultTemplatesStrongest.d.ts +42 -0
  114. package/types/defaultTemplatesStrongest.d.ts.map +1 -0
  115. package/types/getThemeSuitePalettes.d.ts +7 -0
  116. package/types/getThemeSuitePalettes.d.ts.map +1 -0
  117. package/types/helpers.d.ts +24 -0
  118. package/types/helpers.d.ts.map +1 -0
  119. package/types/index.d.ts +11 -0
  120. package/types/index.d.ts.map +1 -0
  121. package/types/masks.d.ts +18 -0
  122. package/types/masks.d.ts.map +1 -0
  123. package/types/types.d.ts +76 -0
  124. package/types/types.d.ts.map +1 -0
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@hanzogui/theme-builder",
3
+ "version": "2.0.0-rc.41-hanzoai.5",
4
+ "source": "src/index.ts",
5
+ "files": [
6
+ "src",
7
+ "types",
8
+ "dist"
9
+ ],
10
+ "type": "module",
11
+ "sideEffects": false,
12
+ "main": "dist/cjs",
13
+ "module": "dist/esm",
14
+ "types": "./types/index.d.ts",
15
+ "exports": {
16
+ "./package.json": "./package.json",
17
+ ".": {
18
+ "types": "./types/index.d.ts",
19
+ "react-native": "./dist/esm/index.native.js",
20
+ "browser": "./dist/esm/index.mjs",
21
+ "module": "./dist/esm/index.mjs",
22
+ "import": "./dist/esm/index.mjs",
23
+ "require": "./dist/cjs/index.cjs",
24
+ "default": "./dist/esm/index.mjs"
25
+ }
26
+ },
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "scripts": {
31
+ "build": "hanzogui-build",
32
+ "watch": "hanzogui-build --watch",
33
+ "clean": "hanzogui-build clean",
34
+ "clean:build": "hanzogui-build clean:build",
35
+ "test": "vitest --run",
36
+ "test:web": "bun run test",
37
+ "test:watch": "vitest"
38
+ },
39
+ "dependencies": {
40
+ "@hanzogui/create-theme": "2.0.0-rc.41-hanzoai.5",
41
+ "@hanzogui/web": "2.0.0-rc.41-hanzoai.5",
42
+ "color2k": "^2.0.2"
43
+ },
44
+ "devDependencies": {
45
+ "@hanzogui/build": "2.0.0-rc.41-hanzoai.5",
46
+ "vitest": "4.0.4"
47
+ }
48
+ }
@@ -0,0 +1,514 @@
1
+ import type {
2
+ MaskDefinitions,
3
+ PaletteDefinitions,
4
+ Template,
5
+ TemplateDefinitions,
6
+ ThemeDefinitions,
7
+ ThemeUsingMask,
8
+ } from '@hanzogui/create-theme'
9
+ import {
10
+ applyMask,
11
+ createMask,
12
+ createThemeWithPalettes,
13
+ objectEntries,
14
+ objectFromEntries,
15
+ } from '@hanzogui/create-theme'
16
+ import type { Narrow } from '@hanzogui/web'
17
+ import type { GetThemeFn } from './types'
18
+
19
+ export type ThemeBuilderInternalState = {
20
+ palettes?: PaletteDefinitions
21
+ templates?: TemplateDefinitions
22
+ themes?: ThemeDefinitions
23
+ masks?: MaskDefinitions
24
+ }
25
+
26
+ type ObjectStringKeys<A extends object | undefined> = A extends object
27
+ ? Exclude<keyof A, symbol | number>
28
+ : never
29
+
30
+ type GetGeneratedThemeFromTemplate<Template, TD> = {
31
+ [key in keyof Template]: string
32
+ }
33
+
34
+ type GetParentTheme<P, Themes extends ThemeDefinitions | undefined> = P extends string
35
+ ? P extends keyof Themes
36
+ ? Themes[P]
37
+ : GetParentName<P> extends keyof Themes
38
+ ? Themes[GetParentName<P>]
39
+ : GetParentName<GetParentName<P>> extends keyof Themes
40
+ ? Themes[GetParentName<GetParentName<P>>]
41
+ : GetParentName<GetParentName<GetParentName<P>>> extends keyof Themes
42
+ ? Themes[GetParentName<GetParentName<GetParentName<P>>>]
43
+ : never
44
+ : never
45
+
46
+ type GetGeneratedTheme<TD, S extends ThemeBuilderInternalState> = TD extends {
47
+ theme: infer T
48
+ }
49
+ ? T
50
+ : TD extends { parent: infer P }
51
+ ? GetGeneratedTheme<GetParentTheme<P, S['themes']>, S>
52
+ : TD extends { template: infer T }
53
+ ? T extends keyof S['templates']
54
+ ? GetGeneratedThemeFromTemplate<S['templates'][T], TD>
55
+ : TD
56
+ : TD
57
+
58
+ type ThemeBuilderBuildResult<
59
+ S extends ThemeBuilderInternalState,
60
+ FinalTheme extends Record<string, string | number> = Record<string, string>,
61
+ > =
62
+ Record<string, string> extends FinalTheme
63
+ ? FinalTheme extends Record<string, string>
64
+ ? {
65
+ [Key in keyof S['themes']]: GetGeneratedTheme<S['themes'][Key], S>
66
+ }
67
+ : {
68
+ [Key in keyof S['themes']]: FinalTheme
69
+ }
70
+ : {
71
+ [Key in keyof S['themes']]: FinalTheme
72
+ }
73
+
74
+ type GetParentName<N extends string> =
75
+ N extends `${infer A}_${infer B}_${infer C}_${infer D}_${string}`
76
+ ? `${A}_${B}_${C}_${D}`
77
+ : N extends `${infer A}_${infer B}_${infer C}_${string}`
78
+ ? `${A}_${B}_${C}`
79
+ : N extends `${infer A}_${infer B}_${string}`
80
+ ? `${A}_${B}`
81
+ : N extends `${infer A}_${string}`
82
+ ? `${A}`
83
+ : never
84
+
85
+ // Flatten union types into a single object with optional properties
86
+ type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
87
+ k: infer I
88
+ ) => void
89
+ ? I
90
+ : never
91
+
92
+ type Prettify<T> = {
93
+ [K in keyof T]: T[K]
94
+ } & {}
95
+
96
+ type FlattenUnion<T extends Record<string, string | number>> =
97
+ Prettify<{
98
+ [K in keyof UnionToIntersection<T>]: UnionToIntersection<T>[K]
99
+ }> extends infer R extends Record<string, string | number>
100
+ ? R
101
+ : never
102
+
103
+ export class ThemeBuilder<
104
+ State extends ThemeBuilderInternalState = ThemeBuilderInternalState,
105
+ FinalTheme extends Record<string, string | number> = Record<string, string>,
106
+ > {
107
+ private _getThemeFn?: GetThemeFn<FinalTheme>
108
+
109
+ constructor(public state: State) {}
110
+
111
+ addPalettes<const P extends PaletteDefinitions>(palettes: P) {
112
+ this.state.palettes = {
113
+ // as {} prevents generic string key merge messing up types
114
+ ...(this.state.palettes as {}),
115
+ ...palettes,
116
+ }
117
+ return this as any as ThemeBuilder<
118
+ State & {
119
+ palettes: P
120
+ },
121
+ FinalTheme
122
+ >
123
+ }
124
+
125
+ addTemplates<const T extends TemplateDefinitions>(templates: T) {
126
+ this.state.templates = {
127
+ // as {} prevents generic string key merge messing up types
128
+ ...(this.state.templates as {}),
129
+ ...templates,
130
+ }
131
+ return this as any as ThemeBuilder<
132
+ State & {
133
+ templates: T
134
+ },
135
+ FinalTheme
136
+ >
137
+ }
138
+
139
+ addMasks<const M extends MaskDefinitions>(masks: M) {
140
+ this.state.masks = {
141
+ // as {} prevents generic string key merge messing up types
142
+ ...(this.state.masks as {}),
143
+ ...(objectFromEntries(
144
+ objectEntries(masks).map(([key, val]) => [key, createMask(val)])
145
+ ) as M),
146
+ }
147
+ return this as any as ThemeBuilder<
148
+ State & {
149
+ masks: M
150
+ },
151
+ FinalTheme
152
+ >
153
+ }
154
+
155
+ // for dev mode only really
156
+ _addedThemes: { type: 'themes' | 'childThemes'; args: any }[] = []
157
+
158
+ addThemes<const T extends ThemeDefinitions<ObjectStringKeys<State['masks']>>>(
159
+ themes: T
160
+ ) {
161
+ this._addedThemes.push({ type: 'themes', args: [themes] })
162
+
163
+ this.state.themes = {
164
+ // as {} prevents generic string key merge messing up types
165
+ ...(this.state.themes as {}),
166
+ ...themes,
167
+ }
168
+
169
+ // type TemplateToTheme<X> = State['templates'] extends {}
170
+ // ? X extends { template: infer Y; nonInheritedValues: infer Z }
171
+ // ? Y extends keyof State['templates']
172
+ // ? { theme: Record<keyof State['templates'][Y] | keyof Z, string> }
173
+ // : X
174
+ // : X
175
+ // : X
176
+
177
+ return this as any as ThemeBuilder<
178
+ Omit<State, 'themes'> & {
179
+ // lets infer template themes directly onto here to avoid some type nesting issues later one
180
+ // themes: {
181
+ // [Key in keyof T]: TemplateToTheme<T[Key]>
182
+ // } & State['themes']
183
+ themes: T
184
+ },
185
+ FinalTheme
186
+ >
187
+ }
188
+
189
+ // these wont be typed to save some complexity and because they don't need to be typed!
190
+ addComponentThemes<
191
+ CTD extends Narrow<ThemeDefinitions<ObjectStringKeys<State['masks']>>>,
192
+ >(
193
+ childThemeDefinition: CTD,
194
+ options?: {
195
+ avoidNestingWithin?: string[]
196
+ }
197
+ ) {
198
+ void this.addChildThemes(childThemeDefinition, options)
199
+ return this
200
+ }
201
+
202
+ addChildThemes<
203
+ CTD extends Narrow<ThemeDefinitions<ObjectStringKeys<State['masks']>>>,
204
+ const AvoidNestingWithin extends string[] = [],
205
+ >(
206
+ childThemeDefinition: CTD,
207
+ options?: {
208
+ avoidNestingWithin?: AvoidNestingWithin
209
+ }
210
+ ) {
211
+ const currentThemes = this.state.themes as State['themes']
212
+ if (!currentThemes) {
213
+ throw new Error(
214
+ `No themes defined yet, use addThemes first to set your base themes`
215
+ )
216
+ }
217
+
218
+ this._addedThemes.push({ type: 'childThemes', args: [childThemeDefinition, options] })
219
+
220
+ // AvoidNestingWithin[number] exclude isn't working here...
221
+ type CurrentNames = Exclude<keyof typeof currentThemes, symbol | number>
222
+ type ChildNames = Exclude<keyof CTD, symbol | number>
223
+
224
+ const currentThemeNames = Object.keys(currentThemes) as CurrentNames[]
225
+ const incomingThemeNames = Object.keys(childThemeDefinition) as ChildNames[]
226
+
227
+ const namesWithDefinitions = currentThemeNames.flatMap((prefix) => {
228
+ const avoidNestingWithin = options?.avoidNestingWithin
229
+ if (avoidNestingWithin) {
230
+ if (
231
+ avoidNestingWithin.some(
232
+ (avoidName) => prefix.startsWith(avoidName) || prefix.endsWith(avoidName)
233
+ )
234
+ ) {
235
+ return []
236
+ }
237
+ }
238
+
239
+ return incomingThemeNames
240
+ .map((subName) => {
241
+ const fullName = `${prefix}_${subName}`
242
+ const definition = childThemeDefinition[subName]
243
+
244
+ if ('avoidNestingWithin' in definition) {
245
+ const avoidNest = definition.avoidNestingWithin as string[]
246
+ if (
247
+ avoidNest.some((name) => {
248
+ // For base scheme names (light/dark), use exact match to avoid matching derivatives
249
+ if ((name === 'light' || name === 'dark') && prefix.includes('_')) {
250
+ return false
251
+ }
252
+ return prefix.startsWith(name) || prefix.endsWith(name)
253
+ })
254
+ ) {
255
+ return null as never
256
+ }
257
+ }
258
+
259
+ // Avoid double-nesting: don't add a child theme to a parent that already ends with that child
260
+ // e.g., don't create light_blue_accent_accent from light_blue_accent + accent
261
+ if (prefix.endsWith(`_${subName}`)) {
262
+ return null as never
263
+ }
264
+
265
+ // Don't overwrite existing themes (e.g., a grandchild "accent" template
266
+ // should not overwrite a dedicated "accent" child theme with its own palette)
267
+ if (fullName in currentThemes) {
268
+ return null as never
269
+ }
270
+
271
+ return [fullName, definition] as const
272
+ })
273
+ .filter(Boolean)
274
+ })
275
+
276
+ type ChildThemes = {
277
+ [key in `${CurrentNames}_${ChildNames}`]: CTD & {
278
+ parent: GetParentName<key>
279
+ }
280
+ }
281
+
282
+ const childThemes = Object.fromEntries(namesWithDefinitions) as any as ChildThemes
283
+
284
+ const next = {
285
+ // as {} prevents generic string key merge messing up types
286
+ ...(this.state.themes as {}),
287
+ ...childThemes,
288
+ }
289
+
290
+ // @ts-ignore
291
+ this.state.themes = next
292
+
293
+ return this as any as ThemeBuilder<
294
+ State & {
295
+ themes: ChildThemes
296
+ },
297
+ FinalTheme
298
+ >
299
+ }
300
+
301
+ getTheme<NewTheme extends Record<string, string | number>>(
302
+ fn: (props: {
303
+ name: string
304
+ theme: GetGeneratedTheme<State['themes'][keyof State['themes']], State>
305
+ scheme?: 'light' | 'dark'
306
+ parentName: string
307
+ parentNames: string[]
308
+ level: number
309
+ palette?: string[]
310
+ template?: Template
311
+ }) => NewTheme
312
+ ) {
313
+ this._getThemeFn = fn as any
314
+ return this as any as ThemeBuilder<State, FlattenUnion<NewTheme>>
315
+ }
316
+
317
+ build(): ThemeBuilderBuildResult<State, FinalTheme> {
318
+ if (!this.state.themes) {
319
+ return {} as any
320
+ }
321
+
322
+ const out = {}
323
+ const maskedThemes: {
324
+ parentName: string
325
+ themeName: string
326
+ mask: ThemeUsingMask
327
+ }[] = []
328
+
329
+ for (const themeName in this.state.themes) {
330
+ const nameParts = themeName.split('_')
331
+ const parentName = nameParts.slice(0, nameParts.length - 1).join('_')
332
+
333
+ const definitions = this.state.themes[themeName]
334
+ const themeDefinition = Array.isArray(definitions)
335
+ ? (() => {
336
+ const found = definitions.find(
337
+ // endWith match stronger than startsWith
338
+ (d) =>
339
+ d.parent
340
+ ? parentName.endsWith(d.parent!) || parentName.startsWith(d.parent!)
341
+ : true
342
+ )
343
+ if (!found) {
344
+ return null
345
+ }
346
+ return found
347
+ })()
348
+ : definitions
349
+
350
+ if (!themeDefinition) {
351
+ // `No parent for ${themeName}: ${parentName} - Continuing...`
352
+ continue
353
+ }
354
+
355
+ if ('theme' in themeDefinition) {
356
+ out[themeName] = themeDefinition.theme
357
+ } else if ('mask' in themeDefinition) {
358
+ maskedThemes.push({ parentName, themeName, mask: themeDefinition })
359
+ } else {
360
+ let {
361
+ palette: paletteName = '',
362
+ template: templateName,
363
+ ...options
364
+ } = themeDefinition
365
+
366
+ const parentDefinition = this.state.themes[parentName]
367
+
368
+ if (!this.state.palettes) {
369
+ throw new Error(
370
+ `No palettes defined for theme with palette expected: ${themeName}`
371
+ )
372
+ }
373
+
374
+ let palette = this.state.palettes[paletteName || '']
375
+ let attemptParentName = `${parentName}_${paletteName}`
376
+
377
+ while (!palette && attemptParentName) {
378
+ if (attemptParentName in this.state.palettes) {
379
+ palette = this.state.palettes[attemptParentName]
380
+ paletteName = attemptParentName
381
+ } else {
382
+ attemptParentName = attemptParentName.split('_').slice(0, -1).join('_')
383
+ }
384
+ }
385
+
386
+ if (!palette) {
387
+ const msg =
388
+ process.env.NODE_ENV !== 'production'
389
+ ? `: ${themeName}: ${paletteName}
390
+ Definition: ${JSON.stringify(themeDefinition)}
391
+ Parent: ${JSON.stringify(parentDefinition)}
392
+ Potential: (${Object.keys(this.state.palettes).join(', ')})`
393
+ : ``
394
+ throw new Error(`No palette for theme${msg}`)
395
+ }
396
+
397
+ const template =
398
+ this.state.templates?.[templateName] ??
399
+ // fall back to finding the scheme specific on if it exists
400
+ this.state.templates?.[`${nameParts[0]}_${templateName}`]
401
+
402
+ if (!template) {
403
+ throw new Error(
404
+ `No template for theme ${themeName}: ${templateName} in templates:\n- ${Object.keys(this.state.templates || {}).join('\n - ')}`
405
+ )
406
+ }
407
+
408
+ const theme = createThemeWithPalettes(
409
+ this.state.palettes,
410
+ paletteName,
411
+ template,
412
+ options,
413
+ themeName,
414
+ true
415
+ )
416
+
417
+ out[themeName] = this._getThemeFn
418
+ ? {
419
+ ...theme,
420
+ ...this._getThemeFn({
421
+ theme,
422
+ name: themeName,
423
+ level: nameParts.length,
424
+ parentName,
425
+ scheme: /^(light|dark)$/.test(nameParts[0])
426
+ ? (nameParts[0] as 'light' | 'dark')
427
+ : undefined,
428
+ parentNames: nameParts.slice(0, -1),
429
+ palette,
430
+ template,
431
+ }),
432
+ }
433
+ : theme
434
+ }
435
+ }
436
+
437
+ for (const { mask, themeName, parentName } of maskedThemes) {
438
+ const parent = out[parentName]
439
+
440
+ if (!parent) {
441
+ // `No parent theme found with name ${parentName} for theme ${themeName} to use as a mask target - Continuing...`
442
+ continue
443
+ }
444
+
445
+ const { mask: maskName, ...options } = mask
446
+ let maskFunction = this.state.masks?.[maskName]
447
+
448
+ if (!maskFunction) {
449
+ throw new Error(`No mask ${maskName}`)
450
+ }
451
+
452
+ const parentTheme = this.state.themes[parentName]
453
+
454
+ if (parentTheme && 'childOptions' in parentTheme) {
455
+ const { mask, ...childOpts } = parentTheme.childOptions as any
456
+ if (mask) {
457
+ maskFunction = this.state.masks?.[mask]
458
+ }
459
+ Object.assign(options, childOpts)
460
+ }
461
+
462
+ out[themeName] = applyMask(
463
+ parent,
464
+ maskFunction as any,
465
+ options,
466
+ parentName,
467
+ themeName
468
+ )
469
+ }
470
+
471
+ return out as any
472
+ }
473
+ }
474
+
475
+ export function createThemeBuilder() {
476
+ return new ThemeBuilder({})
477
+ }
478
+
479
+ // // test types
480
+ // let x = createThemeBuilder()
481
+ // .addMasks({
482
+ // test: {
483
+ // name: 'mask',
484
+ // mask: (() => {}) as any,
485
+ // },
486
+ // })
487
+ // .addThemes({
488
+ // light: {
489
+ // template: '',
490
+ // palette: '',
491
+ // },
492
+ // dark: {
493
+ // mask: 'test',
494
+ // },
495
+ // })
496
+ // .addChildThemes({
497
+ // List: [
498
+ // {
499
+ // parent: '',
500
+ // mask: 'test',
501
+ // },
502
+ // ],
503
+ // })
504
+
505
+ // x
506
+
507
+ // x.state.themes
508
+ // x.state.masks
509
+
510
+ // let y = x.addChildThemes({
511
+ // blue: {
512
+ // mask: 'ok',
513
+ // },
514
+ // })
@@ -0,0 +1,28 @@
1
+ import { createPalettes, createSimpleThemeBuilder } from './createThemes'
2
+ import { defaultComponentThemes } from './defaultComponentThemes'
3
+ import { defaultTemplates } from './defaultTemplates'
4
+ import { defaultTemplatesStronger } from './defaultTemplatesStronger'
5
+ import { defaultTemplatesStrongest } from './defaultTemplatesStrongest'
6
+ import type { BuildThemeSuiteProps } from './types'
7
+
8
+ // for studio
9
+ // allows more detailed configuration, used by studio
10
+ // eventually we should merge this down into simple and have it handle what we need
11
+
12
+ export function createStudioThemes(props: BuildThemeSuiteProps) {
13
+ const palettes = createPalettes(props.palettes)
14
+
15
+ const templates =
16
+ props.templateStrategy === 'stronger'
17
+ ? defaultTemplatesStronger
18
+ : props.templateStrategy === 'strongest'
19
+ ? defaultTemplatesStrongest
20
+ : defaultTemplates
21
+
22
+ return createSimpleThemeBuilder({
23
+ palettes,
24
+ templates,
25
+ componentThemes: defaultComponentThemes,
26
+ accentTheme: !!props.palettes.accent,
27
+ })
28
+ }