@tamagui/theme-builder 1.79.4 → 1.79.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 (48) hide show
  1. package/dist/cjs/buildThemeSuite.js +309 -0
  2. package/dist/cjs/buildThemeSuite.js.map +6 -0
  3. package/dist/cjs/buildThemeSuite.native.js +310 -0
  4. package/dist/cjs/buildThemeSuite.native.js.map +6 -0
  5. package/dist/cjs/buildThemeSuitePalettes.js +56 -0
  6. package/dist/cjs/buildThemeSuitePalettes.js.map +6 -0
  7. package/dist/cjs/buildThemeSuitePalettes.native.js +57 -0
  8. package/dist/cjs/buildThemeSuitePalettes.native.js.map +6 -0
  9. package/dist/cjs/buildThemeSuiteScales.js +251 -0
  10. package/dist/cjs/buildThemeSuiteScales.js.map +6 -0
  11. package/dist/cjs/buildThemeSuiteScales.native.js +252 -0
  12. package/dist/cjs/buildThemeSuiteScales.native.js.map +6 -0
  13. package/dist/cjs/index.js +7 -1
  14. package/dist/cjs/index.js.map +1 -1
  15. package/dist/cjs/index.native.js +7 -1
  16. package/dist/cjs/index.native.js.map +1 -1
  17. package/dist/esm/buildThemeSuite.js +296 -0
  18. package/dist/esm/buildThemeSuite.js.map +6 -0
  19. package/dist/esm/buildThemeSuite.native.js +296 -0
  20. package/dist/esm/buildThemeSuite.native.js.map +6 -0
  21. package/dist/esm/buildThemeSuitePalettes.js +37 -0
  22. package/dist/esm/buildThemeSuitePalettes.js.map +6 -0
  23. package/dist/esm/buildThemeSuitePalettes.native.js +37 -0
  24. package/dist/esm/buildThemeSuitePalettes.native.js.map +6 -0
  25. package/dist/esm/buildThemeSuiteScales.js +230 -0
  26. package/dist/esm/buildThemeSuiteScales.js.map +6 -0
  27. package/dist/esm/buildThemeSuiteScales.native.js +230 -0
  28. package/dist/esm/buildThemeSuiteScales.native.js.map +6 -0
  29. package/dist/esm/index.js +3 -0
  30. package/dist/esm/index.js.map +1 -1
  31. package/dist/esm/index.native.js +3 -0
  32. package/dist/esm/index.native.js.map +1 -1
  33. package/package.json +4 -3
  34. package/src/buildThemeSuite.ts +376 -0
  35. package/src/buildThemeSuitePalettes.ts +91 -0
  36. package/src/buildThemeSuiteScales.ts +209 -0
  37. package/src/index.ts +5 -0
  38. package/src/types.ts +16 -2
  39. package/types/buildThemeSuite.d.ts +310 -0
  40. package/types/buildThemeSuite.d.ts.map +1 -0
  41. package/types/buildThemeSuitePalettes.d.ts +3 -0
  42. package/types/buildThemeSuitePalettes.d.ts.map +1 -0
  43. package/types/buildThemeSuiteScales.d.ts +16 -0
  44. package/types/buildThemeSuiteScales.d.ts.map +1 -0
  45. package/types/index.d.ts +3 -0
  46. package/types/index.d.ts.map +1 -1
  47. package/types/types.d.ts +15 -2
  48. package/types/types.d.ts.map +1 -1
@@ -0,0 +1,376 @@
1
+ import {
2
+ MaskOptions,
3
+ ThemeDefinitions,
4
+ createMask,
5
+ createSoftenMask,
6
+ } from '@tamagui/create-theme'
7
+ import { masks as defaultMasks, maskOptions } from '@tamagui/themes'
8
+
9
+ import { buildMask } from './buildMask'
10
+ import { getThemeSuitePalettes } from './buildThemeSuitePalettes'
11
+ import { createThemeBuilder } from './ThemeBuilder'
12
+ import { BuildThemeMask, BuildThemeSuiteProps } from './types'
13
+
14
+ export function buildThemeSuite({ baseTheme, subThemes }: BuildThemeSuiteProps) {
15
+ const theme = baseTheme
16
+
17
+ const maskThemes = (subThemes || []).filter(
18
+ (x) => x.type === 'mask'
19
+ ) as BuildThemeMask[]
20
+
21
+ const customMasks = Object.fromEntries(
22
+ maskThemes.map((maskTheme) => {
23
+ return [maskTheme.name, buildMask(maskTheme.masks)]
24
+ })
25
+ )
26
+
27
+ // base palletes need to add in sub theme palettes if customized
28
+ const palettes = getThemeSuitePalettes(theme as any)
29
+
30
+ const max = palettes.dark.length - 1
31
+ const min = 1
32
+
33
+ const componentMask = {
34
+ ...maskOptions.component,
35
+ max,
36
+ min,
37
+ overrideSwap: {
38
+ accentBackground: 0,
39
+ accentColor: -0,
40
+ },
41
+ overrideShift: {
42
+ ...maskOptions.component.override,
43
+ },
44
+ skip: {
45
+ ...maskOptions.component.skip,
46
+ },
47
+ } satisfies MaskOptions
48
+
49
+ const customMaskOptions = {
50
+ alt: {
51
+ ...maskOptions.alt,
52
+ max,
53
+ min,
54
+ overrideSwap: {
55
+ accentBackground: 0,
56
+ accentColor: -0,
57
+ },
58
+ overrideShift: {
59
+ ...maskOptions.alt.override,
60
+ },
61
+ skip: {
62
+ ...maskOptions.alt.skip,
63
+ },
64
+ },
65
+ component: componentMask,
66
+ componentInverse: {
67
+ ...componentMask,
68
+ },
69
+ } satisfies Record<string, MaskOptions>
70
+
71
+ const baseTemplate = {
72
+ accentBackground: 0,
73
+ accentColor: -0,
74
+
75
+ background0: 1,
76
+ background025: 2,
77
+ background05: 3,
78
+ background075: 4,
79
+
80
+ color0: -4,
81
+ color025: -3,
82
+ color05: -2,
83
+ color075: -1,
84
+
85
+ background: 5,
86
+ backgroundHover: 6,
87
+ backgroundPress: 7,
88
+ backgroundFocus: 8,
89
+
90
+ color: -5,
91
+ colorHover: -6,
92
+ colorPress: -5,
93
+ colorFocus: -6,
94
+
95
+ placeholderColor: -6,
96
+
97
+ borderColor: 7,
98
+ borderColorHover: 8,
99
+ borderColorFocus: 9,
100
+ borderColorPress: 8,
101
+ }
102
+
103
+ function createTemplates() {
104
+ const template = {
105
+ color1: 5,
106
+ color2: 6,
107
+ color3: 7,
108
+ color4: 8,
109
+ color5: 9,
110
+ color6: 10,
111
+ color7: 11,
112
+ color8: 12,
113
+ color9: 13,
114
+ color10: 14,
115
+ color11: 15,
116
+ color12: 16,
117
+ ...baseTemplate,
118
+ }
119
+
120
+ const accentTemplateLight = {
121
+ background: 0,
122
+ backgroundHover: baseTemplate.backgroundHover + 4,
123
+ backgroundPress: baseTemplate.backgroundPress + 4,
124
+ backgroundFocus: baseTemplate.backgroundFocus + 4,
125
+ borderColor: baseTemplate.borderColor + 2,
126
+ borderColorHover: baseTemplate.borderColorHover + 2,
127
+ borderColorFocus: baseTemplate.borderColorFocus + 2,
128
+ borderColorPress: baseTemplate.borderColorPress + 2,
129
+ color: -5,
130
+ colorHover: -6,
131
+ colorPress: -7,
132
+ colorFocus: -5,
133
+ }
134
+
135
+ const accentTemplateDark = {
136
+ background: baseTemplate.backgroundHover + 4,
137
+ backgroundHover: baseTemplate.backgroundHover + 5,
138
+ backgroundPress: baseTemplate.backgroundPress + 3,
139
+ backgroundFocus: baseTemplate.backgroundFocus + 5,
140
+ borderColor: baseTemplate.borderColor + 2,
141
+ borderColorHover: baseTemplate.borderColorHover + 2,
142
+ borderColorFocus: baseTemplate.borderColorFocus + 2,
143
+ borderColorPress: baseTemplate.borderColorPress + 2,
144
+ color: -5,
145
+ colorHover: -6,
146
+ colorPress: -7,
147
+ colorFocus: -5,
148
+ }
149
+
150
+ return {
151
+ base: template,
152
+ accentLight: accentTemplateLight,
153
+ accentDark: accentTemplateDark,
154
+ }
155
+ }
156
+
157
+ const templates = createTemplates()
158
+
159
+ function getComponentThemeDefinitions() {
160
+ const overlayThemes = {
161
+ light: {
162
+ background: 'rgba(0,0,0,0.5)',
163
+ },
164
+ dark: {
165
+ background: 'rgba(0,0,0,0.9)',
166
+ },
167
+ }
168
+
169
+ const overlayThemeDefinitions = [
170
+ {
171
+ parent: 'light',
172
+ theme: overlayThemes.light,
173
+ },
174
+ {
175
+ parent: 'dark',
176
+ theme: overlayThemes.dark,
177
+ },
178
+ ]
179
+
180
+ const componentTheme = [
181
+ {
182
+ parent: 'light_accent',
183
+ template: 'accentLight',
184
+ palette: 'lightAccent',
185
+ },
186
+
187
+ {
188
+ parent: 'dark_accent',
189
+ template: 'accentDark',
190
+ palette: 'darkAccent',
191
+ },
192
+
193
+ {
194
+ parent: 'light',
195
+ mask: 'soften2',
196
+ ...customMaskOptions.component,
197
+ },
198
+
199
+ {
200
+ parent: 'dark',
201
+ mask: 'soften2',
202
+ ...customMaskOptions.component,
203
+ },
204
+ ]
205
+
206
+ const componentThemeDefinitions = {
207
+ Card: {
208
+ mask: 'soften',
209
+ ...customMaskOptions.component,
210
+ },
211
+
212
+ Button: componentTheme,
213
+
214
+ Checkbox: {
215
+ mask: 'softenBorder2',
216
+ ...customMaskOptions.component,
217
+ },
218
+
219
+ Switch: {
220
+ mask: 'soften2',
221
+ ...customMaskOptions.component,
222
+ },
223
+
224
+ SwitchThumb: {
225
+ mask: 'inverse',
226
+ ...customMaskOptions.componentInverse,
227
+ },
228
+
229
+ TooltipContent: {
230
+ mask: 'soften2',
231
+ ...customMaskOptions.component,
232
+ },
233
+
234
+ DrawerFrame: {
235
+ mask: 'soften',
236
+ ...customMaskOptions.component,
237
+ },
238
+
239
+ Progress: {
240
+ mask: 'soften',
241
+ ...customMaskOptions.component,
242
+ },
243
+
244
+ RadioGroupItem: {
245
+ mask: 'softenBorder2',
246
+ ...customMaskOptions.component,
247
+ },
248
+
249
+ TooltipArrow: {
250
+ mask: 'soften',
251
+ ...customMaskOptions.component,
252
+ },
253
+
254
+ SliderTrackActive: {
255
+ mask: 'inverseSoften',
256
+ ...customMaskOptions.component,
257
+ },
258
+
259
+ SliderTrack: {
260
+ mask: 'soften2',
261
+ ...customMaskOptions.component,
262
+ },
263
+
264
+ SliderThumb: {
265
+ mask: 'inverse',
266
+ ...customMaskOptions.componentInverse,
267
+ },
268
+
269
+ Tooltip: {
270
+ mask: 'inverse',
271
+ ...customMaskOptions.component,
272
+ },
273
+
274
+ ProgressIndicator: {
275
+ mask: 'inverse',
276
+ ...customMaskOptions.componentInverse,
277
+ },
278
+
279
+ SheetOverlay: overlayThemeDefinitions,
280
+ DialogOverlay: overlayThemeDefinitions,
281
+ ModalOverlay: overlayThemeDefinitions,
282
+
283
+ Input: {
284
+ mask: 'softenBorder2',
285
+ ...customMaskOptions.component,
286
+ },
287
+
288
+ TextArea: {
289
+ mask: 'softenBorder2',
290
+ ...customMaskOptions.component,
291
+ },
292
+ } satisfies ThemeDefinitions<keyof typeof defaultMasks>
293
+
294
+ return componentThemeDefinitions
295
+ }
296
+
297
+ const builder = createThemeBuilder()
298
+ .addPalettes(palettes)
299
+ .addMasks({
300
+ ...defaultMasks,
301
+ soften3Border2: createMask((template, options) => {
302
+ const softer2 = createSoftenMask({ strength: 3 }).mask(template, options)
303
+ const softer1 = createSoftenMask({ strength: 2 }).mask(template, options)
304
+ return {
305
+ ...softer2,
306
+ borderColor: softer1.borderColor,
307
+ borderColorHover: softer1.borderColorHover,
308
+ borderColorPress: softer1.borderColorPress,
309
+ borderColorFocus: softer1.borderColorFocus,
310
+ }
311
+ }),
312
+ ...customMasks,
313
+ })
314
+ .addTemplates(templates)
315
+ .addThemes({
316
+ light: {
317
+ template: 'base',
318
+ palette: 'light',
319
+ },
320
+ dark: {
321
+ template: 'base',
322
+ palette: 'dark',
323
+ },
324
+ })
325
+ .addChildThemes(
326
+ Object.fromEntries(
327
+ maskThemes.map((theme) => {
328
+ return [
329
+ theme.name,
330
+ {
331
+ mask: theme.name,
332
+ },
333
+ ]
334
+ })
335
+ )
336
+ )
337
+ .addChildThemes({
338
+ // disabling as we don't need to preview these
339
+ alt1: {
340
+ mask: 'soften2Border1',
341
+ ...maskOptions.alt,
342
+ },
343
+ alt2: {
344
+ mask: 'soften3Border2',
345
+ ...maskOptions.alt,
346
+ },
347
+ })
348
+ .addChildThemes(
349
+ palettes.lightAccent
350
+ ? {
351
+ accent: [
352
+ {
353
+ parent: 'light',
354
+ template: 'base',
355
+ palette: 'lightAccent',
356
+ },
357
+ {
358
+ parent: 'dark',
359
+ template: 'base',
360
+ palette: 'darkAccent',
361
+ },
362
+ ],
363
+ }
364
+ : {}
365
+ )
366
+ .addChildThemes(getComponentThemeDefinitions())
367
+
368
+ const built = builder.build()
369
+
370
+ return {
371
+ built,
372
+ palettes,
373
+ }
374
+ }
375
+
376
+ export type BuildBaseThemesResult = ReturnType<typeof buildThemeSuite>
@@ -0,0 +1,91 @@
1
+ import { hsla, parseToHsla, toHex } from 'color2k'
2
+
3
+ import { getThemeSuiteScale } from './buildThemeSuiteScales'
4
+ import { BuildTheme, BuildThemeSuitePalettes } from './types'
5
+
6
+ /**
7
+ * palette generally is:
8
+ *
9
+ * [constrastBackground, backgroundTransparent, ...background, ...foreground, foregroundTransparent, accentForeground]
10
+ */
11
+
12
+ const generateColorPalette = ({
13
+ theme,
14
+ scheme,
15
+ forAccent,
16
+ }: {
17
+ theme: BuildTheme
18
+ scheme: 'light' | 'dark'
19
+ forAccent?: boolean
20
+ }) => {
21
+ // const { color, scale, accent, accentColor, accentScale } = theme
22
+
23
+ const color = forAccent ? theme.accent || theme.color : theme.color
24
+ const scale = forAccent ? theme.accentScale || theme.scale : theme.scale
25
+
26
+ const { lumScale, satScale } = getThemeSuiteScale(theme, forAccent)
27
+ const [hue, sat, lum] = parseToHsla(color)
28
+ const isDark = scheme === 'dark'
29
+
30
+ const lumValues = isDark ? lumScale.dark : lumScale.light
31
+
32
+ let palette: string[] = lumValues.map((lum, idx) => {
33
+ if (sat > 0) {
34
+ if (satScale) {
35
+ return hsla(hue, satScale[scheme][idx], lum, 1)
36
+ }
37
+ return hsla(hue, sat, lum, 1)
38
+ }
39
+ return hsla(0, 0, lum, 1)
40
+ })
41
+
42
+ const [background] = palette
43
+ const foreground = palette[palette.length - 1]
44
+
45
+ const transparentValues = [background, foreground].map((color) => {
46
+ const [h, s, l] = parseToHsla(color)
47
+ // fully transparent to partially
48
+ return [
49
+ hsla(h, s, l, 0),
50
+ hsla(h, s, l, 0.25),
51
+ hsla(h, s, l, 0.5),
52
+ hsla(h, s, l, 0.75),
53
+ ] as const
54
+ })
55
+ const reverseForeground = [...transparentValues[1]].reverse()
56
+ palette = [...transparentValues[0], ...palette, ...reverseForeground]
57
+
58
+ if (theme.accent) {
59
+ const baseAccent = forAccent ? theme.color : theme.accent
60
+ const accentHsla = parseToHsla(baseAccent)
61
+ const accentLum = accentHsla[2]
62
+ const isAccentLight = accentLum > 0.5
63
+
64
+ const oppositeLightnessAccent = isAccentLight
65
+ ? toHex(hsla(accentHsla[0], accentHsla[1], 1 - accentLum, 1))
66
+ : theme.accent
67
+
68
+ const fg = isAccentLight && !isDark ? oppositeLightnessAccent : baseAccent
69
+ const bg = fg === baseAccent ? oppositeLightnessAccent : baseAccent
70
+
71
+ // unshift bg
72
+ palette.unshift(bg)
73
+ // push color
74
+ palette.push(fg)
75
+ } else {
76
+ // were keeping the palettes the same length with or without accent to avoid headache
77
+ palette.unshift('rgba(0,0,0,0)')
78
+ palette.push('rgba(0,0,0,0)')
79
+ }
80
+
81
+ return palette
82
+ }
83
+
84
+ export function getThemeSuitePalettes(theme: BuildTheme): BuildThemeSuitePalettes {
85
+ return {
86
+ light: generateColorPalette({ theme, scheme: 'light' }),
87
+ lightAccent: generateColorPalette({ theme, scheme: 'light', forAccent: true }),
88
+ dark: generateColorPalette({ theme, scheme: 'dark' }),
89
+ darkAccent: generateColorPalette({ theme, scheme: 'dark', forAccent: true }),
90
+ }
91
+ }
@@ -0,0 +1,209 @@
1
+ import { parseToHsla } from 'color2k'
2
+
3
+ import { BuildTheme, ScaleTypeName } from './types'
4
+
5
+ export const getThemeSuiteScale = (theme: BuildTheme, accent?: boolean): ScaleType => {
6
+ const color = accent ? theme.accent || theme.color : theme.color
7
+ const scale = accent ? theme.accentScale || theme.scale : theme.scale
8
+
9
+ let base = scaleTypes[theme.scale || '']
10
+
11
+ if (!color) {
12
+ return base
13
+ }
14
+
15
+ const [h, s, l] = parseToHsla(color)
16
+ // const isColorBright = l > 0.5
17
+
18
+ return {
19
+ ...base,
20
+ lumScale: {
21
+ light: adjustScale(theme, base.lumScale.light, l, true),
22
+ dark: adjustScale(theme, base.lumScale.dark, 1 - l),
23
+ },
24
+ ...(base.satScale && {
25
+ satScale: {
26
+ light: adjustScale(theme, base.satScale.light, s, true),
27
+ dark: adjustScale(theme, base.satScale.dark, s),
28
+ },
29
+ }),
30
+ }
31
+ }
32
+
33
+ export type ScaleType<A extends ScaleTypeName = ScaleTypeName> = {
34
+ name: string
35
+ createdFrom?: A // we copy the scale values - keeping this helps us refer back to the scale. also helpful if we change scales in the future
36
+ lumScale: {
37
+ light: Array<number>
38
+ dark: Array<number>
39
+ }
40
+ satScale?: {
41
+ light: Array<number>
42
+ dark: Array<number>
43
+ }
44
+ }
45
+
46
+ export const scaleTypes: Record<ScaleTypeName, ScaleType> = {
47
+ radix: {
48
+ name: 'Radius',
49
+ createdFrom: 'radix',
50
+ lumScale: {
51
+ light: [
52
+ 0.992, 0.95, 0.92, 0.868, 0.832, 0.804, 0.747, 0.659, 0.541, 0.453, 0.27, 0.086,
53
+ ],
54
+ dark: [
55
+ 0.07, 0.11, 0.136, 0.158, 0.179, 0.205, 0.243, 0.313, 0.439, 0.52, 0.61, 0.93,
56
+ ],
57
+ },
58
+ satScale: {
59
+ light: [0.65, 0.55, 0.4, 0.4, 0.35, 0.35, 0.35, 0.35, 0.4, 0.4, 0.3, 0.2],
60
+ dark: [0.65, 0.55, 0.4, 0.4, 0.35, 0.35, 0.35, 0.35, 0.4, 0.4, 0.3, 0.2],
61
+ },
62
+ },
63
+
64
+ 'radix-b': {
65
+ name: 'Radius B',
66
+ createdFrom: 'radix-b',
67
+ lumScale: {
68
+ light: [
69
+ 0.92, 0.868, 0.832, 0.804, 0.747, 0.7, 0.659, 0.541, 0.453, 0.36, 0.32, 0.27,
70
+ ],
71
+ dark: [
72
+ 0.11, 0.136, 0.158, 0.179, 0.205, 0.243, 0.313, 0.439, 0.47, 0.52, 0.56, 0.61,
73
+ ],
74
+ },
75
+ },
76
+
77
+ 'radius-bright': {
78
+ name: 'Radius Bright',
79
+ createdFrom: 'radius-bright',
80
+ lumScale: {
81
+ light: [1, 0.954, 0.94, 0.9, 0.85, 0.804, 0.747, 0.659, 0.541, 0.453, 0.27, 0.086],
82
+ dark: [0, 0.1, 0.16, 0.2, 0.24, 0.36, 0.42, 0.46, 0.5, 0.54, 0.84, 0.97],
83
+ },
84
+ },
85
+
86
+ 'radius-bold': {
87
+ name: 'Radius Bold',
88
+ createdFrom: 'radius-bold',
89
+ lumScale: {
90
+ light: [1, 0.9, 0.885, 0.82, 0.77, 0.54, 0.32, 0.25, 0.16, 0.12, 0.075, 0],
91
+ dark: [0, 0.13, 0.2, 0.24, 0.3, 0.34, 0.45, 0.55, 0.65, 0.885, 0.9, 1],
92
+ },
93
+ },
94
+
95
+ linear: {
96
+ name: 'Linear',
97
+ createdFrom: 'linear',
98
+ lumScale: {
99
+ light: [1, 0.925, 0.9, 0.85, 0.75, 0.6, 0.4, 0.3, 0.25, 0.15, 0.125, 0],
100
+ dark: [0, 0.075, 0.125, 0.15, 0.25, 0.4, 0.6, 0.75, 0.85, 0.9, 0.925, 1],
101
+ },
102
+ },
103
+
104
+ neon: {
105
+ name: 'Neon',
106
+ createdFrom: 'neon',
107
+ lumScale: {
108
+ light: [
109
+ 0.978, 0.938, 0.902, 0.868, 0.832, 0.804, 0.747, 0.659, 0.541, 0.453, 0.27, 0.086,
110
+ ],
111
+ dark: [
112
+ 0.07, 0.11, 0.136, 0.158, 0.179, 0.205, 0.243, 0.313, 0.439, 0.52, 0.61, 0.93,
113
+ ],
114
+ },
115
+ },
116
+
117
+ 'neon-bright': {
118
+ name: 'Neon B',
119
+ createdFrom: 'neon-bright',
120
+ lumScale: {
121
+ light: [0.45, 0.475, 0.5, 0.525, 0.55, 0.575, 0.6, 0.625, 0.65, 0.2, 0.1, 0],
122
+ dark: [0.45, 0.475, 0.5, 0.525, 0.55, 0.575, 0.6, 0.625, 0.65, 0.2, 0.1, 0],
123
+ },
124
+ },
125
+
126
+ 'neon-c': {
127
+ name: 'Neon C',
128
+ createdFrom: 'neon-c',
129
+ lumScale: {
130
+ light: [0.45, 0.475, 0.5, 0.525, 0.55, 0.575, 0.6, 0.625, 0.65, 0.2, 0.1, 0],
131
+ dark: [0.45, 0.475, 0.5, 0.525, 0.55, 0.575, 0.6, 0.625, 0.65, 0.2, 0.1, 0],
132
+ },
133
+ satScale: {
134
+ light: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
135
+ dark: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
136
+ },
137
+ },
138
+
139
+ pastel: {
140
+ name: 'Pastel',
141
+ createdFrom: 'pastel',
142
+ lumScale: {
143
+ light: [
144
+ 0.978, 0.938, 0.902, 0.868, 0.832, 0.804, 0.747, 0.659, 0.541, 0.453, 0.36, 0.2,
145
+ ],
146
+ dark: [0.07, 0.15, 0.176, 0.198, 0.2, 0.225, 0.243, 0.313, 0.439, 0.52, 0.61, 0.9],
147
+ },
148
+ satScale: {
149
+ light: [0.5, 0.45, 0.4, 0.4, 0.35, 0.35, 0.35, 0.35, 0.4, 0.4, 0.3, 0.2],
150
+ dark: [0.5, 0.45, 0.4, 0.4, 0.35, 0.35, 0.35, 0.35, 0.4, 0.4, 0.3, 0.2],
151
+ },
152
+ },
153
+
154
+ 'pastel-desaturating': {
155
+ name: 'Pastel D',
156
+ createdFrom: 'pastel-desaturating',
157
+ lumScale: {
158
+ light: [
159
+ 0.935, 0.838, 0.802, 0.768, 0.732, 0.704, 0.647, 0.559, 0.441, 0.353, 0.17, 0,
160
+ ],
161
+ dark: [0.085, 0.1, 0.12, 0.14, 0.17, 0.22, 0.27, 0.35, 0.409, 0.49, 0.58, 0.9],
162
+ },
163
+ satScale: {
164
+ light: [0.6, 0.5, 0.4, 0.35, 0.3, 0.3, 0.3, 0.3, 0.4, 0.35, 0.25, 0.15],
165
+ dark: [0.6, 0.5, 0.4, 0.35, 0.3, 0.3, 0.3, 0.3, 0.4, 0.35, 0.25, 0.15],
166
+ },
167
+ },
168
+ }
169
+
170
+ const adjustScale = (
171
+ theme: BuildTheme,
172
+ scale: number[],
173
+ userVal: number,
174
+ isLight = false
175
+ ) => {
176
+ const scaleMin = scale.reduce((acc, cur) => Math.min(cur, acc), Infinity)
177
+ const scaleMax = scale.reduce((acc, cur) => Math.max(cur, acc), 0)
178
+
179
+ if (scaleMin === scaleMax) {
180
+ return scale.map(() => userVal)
181
+ }
182
+
183
+ const res = scale.map((val, i) => {
184
+ if (userVal > 0.5) {
185
+ return val + (userVal - 0.5) * (1 - val)
186
+ } else {
187
+ return val * (1 / (1.5 - userVal))
188
+ }
189
+
190
+ // // goes from 0 - 1 where 0 = closest to edge, 1 = furthest
191
+ // const distanceFromEdge = 2 * (userVal < 0.5 ? userVal : 1 - userVal)
192
+
193
+ // // goes from 0 - 1 where 0 = furthest from edge, 1 = closest
194
+ // const strengthOfUserVal = 1 - distanceFromEdge
195
+
196
+ // // gets stronger as we get closer to edges
197
+ // const next = userVal * strengthOfUserVal + val * (1 - strengthOfUserVal)
198
+
199
+ // return clamp(
200
+ // val < 0
201
+ // ? // TODO
202
+ // val
203
+ // : next,
204
+ // [0, 1]
205
+ // )
206
+ })
207
+
208
+ return res
209
+ }
package/src/index.ts CHANGED
@@ -2,3 +2,8 @@ export * from './ThemeBuilder'
2
2
  export * from '@tamagui/create-theme'
3
3
  export * from './buildMask'
4
4
  export * from './types'
5
+
6
+ // theme suite builders
7
+ export * from './buildThemeSuite'
8
+ export * from './buildThemeSuitePalettes'
9
+ export * from './buildThemeSuiteScales'
package/src/types.ts CHANGED
@@ -1,10 +1,23 @@
1
1
  // only used by the studio theme builder generated:
2
2
 
3
- import { Template } from '@tamagui/create-theme'
3
+ import { MaskOptions, Template } from '@tamagui/create-theme'
4
4
 
5
5
  export type BuildThemeSuiteProps = {
6
6
  baseTheme: BuildTheme
7
7
  subThemes?: (BuildTheme | BuildThemeMask)[]
8
+ componentMask?: MaskOptions
9
+ templates?: {
10
+ base: Template
11
+ accentLight: Template
12
+ accentDark: Template
13
+ }
14
+ }
15
+
16
+ export type BuildThemeSuitePalettes = {
17
+ light: string[]
18
+ dark: string[]
19
+ lightAccent?: string[]
20
+ darkAccent?: string[]
8
21
  }
9
22
 
10
23
  export type ScaleTypeName =
@@ -29,7 +42,8 @@ export type BuildTheme = BuildThemeBase & {
29
42
  type: 'theme'
30
43
  color: string
31
44
  scale: ScaleTypeName
32
- scaleContrast?: number
45
+ spreadLuminance?: number
46
+ spreadSaturation?: number
33
47
  template?: Template
34
48
  accent?: string
35
49
  accentColor?: string