@sanity/ui 2.0.0-alpha.13 → 2.0.0-alpha.14

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 (32) hide show
  1. package/dist/index.cjs.mjs +27 -0
  2. package/dist/index.d.ts +337 -7
  3. package/dist/index.esm.js +745 -58
  4. package/dist/index.esm.js.map +1 -1
  5. package/dist/index.js +772 -58
  6. package/dist/index.js.map +1 -1
  7. package/package.json +2 -2
  8. package/src/theme/_internal/__workshop__/build/story.tsx +178 -0
  9. package/src/theme/_internal/__workshop__/build/theme.ts +3 -0
  10. package/src/theme/_internal/__workshop__/index.ts +14 -0
  11. package/src/theme/_internal/build/buildTheme.test.ts +78 -0
  12. package/src/theme/_internal/build/buildTheme.ts +15 -0
  13. package/src/theme/_internal/build/colorTheme/buildColorTheme.test.ts +185 -0
  14. package/src/theme/_internal/build/colorTheme/buildColorTheme.ts +222 -0
  15. package/src/theme/_internal/build/colorTheme/renderColorTheme.ts +226 -0
  16. package/src/theme/_internal/build/defaults/colorPalette.ts +8 -0
  17. package/src/theme/_internal/build/defaults/colorTokens.ts +124 -0
  18. package/src/theme/_internal/build/helpers.ts +64 -0
  19. package/src/theme/_internal/build/index.ts +1 -0
  20. package/src/theme/_internal/config/helpers.ts +47 -0
  21. package/src/theme/_internal/config/index.ts +3 -0
  22. package/src/theme/_internal/config/token/index.ts +2 -0
  23. package/src/theme/_internal/config/token/parseTokenKey.test.ts +72 -0
  24. package/src/theme/_internal/config/token/parseTokenKey.ts +88 -0
  25. package/src/theme/_internal/config/token/parseTokenValue.test.ts +45 -0
  26. package/src/theme/_internal/config/token/parseTokenValue.ts +123 -0
  27. package/src/theme/_internal/config/types.ts +126 -0
  28. package/src/theme/_internal/constants.ts +48 -0
  29. package/src/theme/_internal/helpers.ts +19 -0
  30. package/src/theme/_internal/index.ts +5 -0
  31. package/src/theme/_internal/types.ts +72 -0
  32. package/src/theme/index.ts +1 -0
@@ -0,0 +1,222 @@
1
+ import {ThemeConfig} from '../../config'
2
+ import {COLOR_BUTTON_MODES, COLOR_STATE_TONES, COLOR_STATES} from '../../constants'
3
+ import {
4
+ ColorBaseTone,
5
+ ColorButtonMode,
6
+ ColorState,
7
+ ColorStateTone,
8
+ TMP_BaseColorTheme,
9
+ TMP_ButtonColorTheme,
10
+ TMP_ButtonModesColorTheme,
11
+ TMP_ButtonStatesColorTheme,
12
+ TMP_ColorTheme,
13
+ TMP_StateColorTheme,
14
+ } from '../../types'
15
+ import {defaultColorTokens} from '../defaults/colorTokens'
16
+ import {resolveColorTokenValue} from '../helpers'
17
+
18
+ export function buildColorTheme(
19
+ options: {scheme: 'light' | 'dark'},
20
+ config?: ThemeConfig,
21
+ ): TMP_ColorTheme {
22
+ const {scheme} = options
23
+
24
+ return {
25
+ transparent: buildBaseColorTheme({scheme, tone: 'transparent'}, config),
26
+ default: buildBaseColorTheme({scheme, tone: 'default'}, config),
27
+ primary: buildBaseColorTheme({scheme, tone: 'primary'}, config),
28
+ positive: buildBaseColorTheme({scheme, tone: 'positive'}, config),
29
+ caution: buildBaseColorTheme({scheme, tone: 'caution'}, config),
30
+ critical: buildBaseColorTheme({scheme, tone: 'critical'}, config),
31
+ }
32
+ }
33
+
34
+ export function buildBaseColorTheme(
35
+ options: {scheme: 'light' | 'dark'; tone: ColorBaseTone},
36
+ config?: ThemeConfig,
37
+ ): TMP_BaseColorTheme {
38
+ const {scheme, tone} = options
39
+ const tokens = config?.color?.tokens ?? defaultColorTokens
40
+ const any = tokens?.['*']
41
+ const toneTokens = tokens?.[tone]
42
+ const hue = toneTokens?._hue || any?._hue || 'gray'
43
+
44
+ const bg = resolveColorTokenValue({
45
+ hue,
46
+ scheme,
47
+ value: toneTokens?.bg || any?.bg || ['gray/50', 'black'],
48
+ })
49
+
50
+ const _blend = toneTokens?._blend || any?._blend || ['screen', 'multiply']
51
+
52
+ return {
53
+ _blend: _blend[scheme === 'light' ? 0 : 1],
54
+ dark: scheme === 'dark',
55
+ base: {
56
+ bg,
57
+ fg: resolveColorTokenValue({
58
+ hue,
59
+ scheme,
60
+ value: toneTokens?.fg || any?.fg || ['black', 'white'],
61
+ }),
62
+ border: resolveColorTokenValue({
63
+ hue,
64
+ scheme,
65
+ value: toneTokens?.border || any?.border || ['black', 'white'],
66
+ }),
67
+ },
68
+ button: buildButtonColorTheme({scheme}, config),
69
+ }
70
+ }
71
+
72
+ function buildButtonColorTheme(
73
+ options: {scheme: 'light' | 'dark'},
74
+ config?: ThemeConfig,
75
+ ): TMP_ButtonColorTheme {
76
+ const {scheme} = options
77
+
78
+ const tones = COLOR_STATE_TONES.map((tone): Partial<TMP_ButtonColorTheme> => {
79
+ return {
80
+ [tone]: buildButtonColorToneTheme({scheme, tone}, config),
81
+ }
82
+ })
83
+
84
+ return Object.assign({}, ...tones) as TMP_ButtonColorTheme
85
+ }
86
+
87
+ function buildButtonColorToneTheme(
88
+ options: {
89
+ scheme: 'light' | 'dark'
90
+ tone: ColorStateTone
91
+ },
92
+ config?: ThemeConfig,
93
+ ): TMP_ButtonModesColorTheme {
94
+ const {scheme, tone} = options
95
+
96
+ const modes = COLOR_BUTTON_MODES.map((mode): Partial<TMP_ButtonModesColorTheme> => {
97
+ return {
98
+ [mode]: buildButtonModeColorTheme({mode, scheme, tone}, config),
99
+ }
100
+ })
101
+
102
+ return Object.assign({}, ...modes) as TMP_ButtonModesColorTheme
103
+ }
104
+
105
+ function buildButtonModeColorTheme(
106
+ options: {
107
+ mode: ColorButtonMode
108
+ scheme: 'light' | 'dark'
109
+ tone: ColorStateTone
110
+ },
111
+ config?: ThemeConfig,
112
+ ): TMP_ButtonStatesColorTheme {
113
+ const {mode, scheme, tone} = options
114
+
115
+ const states = COLOR_STATES.map((state): Partial<TMP_ButtonStatesColorTheme> => {
116
+ return {
117
+ [state]: buildButtonStateColorTheme({mode, tone, scheme, state}, config),
118
+ }
119
+ })
120
+
121
+ return Object.assign({}, ...states) as TMP_ButtonStatesColorTheme
122
+ }
123
+
124
+ function buildButtonStateColorTheme(
125
+ options: {
126
+ mode: ColorButtonMode
127
+ tone: ColorStateTone
128
+ scheme: 'light' | 'dark'
129
+ state: ColorState
130
+ },
131
+ config?: ThemeConfig,
132
+ ): TMP_StateColorTheme {
133
+ const {mode, tone, scheme, state} = options
134
+ const tokens = config?.color?.tokens ?? defaultColorTokens
135
+ const hue =
136
+ tokens?.button?.[tone]?.[mode]?.[state]?._hue ||
137
+ tokens?.button?.['*']?.[mode]?.[state]?._hue ||
138
+ tokens?.button?.[tone]?._hue ||
139
+ tokens?.[tone]?._hue ||
140
+ 'gray'
141
+ const spec3 = tokens?.button?.['*']?.[mode]?.['*']
142
+ const spec2 = tokens?.button?.['*']?.[mode]?.[state]
143
+ const spec1 = tokens?.button?.[tone]?.[mode]?.['*']
144
+ const spec0 = tokens?.button?.[tone]?.[mode]?.[state]
145
+
146
+ const _blend = spec0?._blend ||
147
+ spec1?._blend ||
148
+ spec2?._blend ||
149
+ spec3?._blend || ['screen', 'multiply']
150
+
151
+ return {
152
+ _blend: _blend[scheme === 'light' ? 0 : 1],
153
+ bg: resolveColorTokenValue({
154
+ hue,
155
+ scheme,
156
+ value: spec0?.bg || spec1?.bg || spec2?.bg || spec3?.bg || ['500', '400'],
157
+ }),
158
+ bg2: resolveColorTokenValue({
159
+ hue,
160
+ scheme,
161
+ value: spec0?.bg2 || spec1?.bg2 || spec2?.bg2 || spec3?.bg2 || ['500', '400'],
162
+ }),
163
+ fg: resolveColorTokenValue({
164
+ hue,
165
+ scheme,
166
+ value: spec0?.fg || spec1?.fg || spec2?.fg || spec3?.fg || ['white', 'black'],
167
+ }),
168
+ border: resolveColorTokenValue({
169
+ hue,
170
+ scheme,
171
+ value: spec0?.border || spec1?.border || spec2?.border || spec3?.border || ['500', '400'],
172
+ }),
173
+ muted: {
174
+ fg: resolveColorTokenValue({
175
+ hue,
176
+ scheme,
177
+ value: spec0?.muted?.fg ||
178
+ spec1?.muted?.fg ||
179
+ spec2?.muted?.fg ||
180
+ spec3?.muted?.fg || ['500', '400'],
181
+ }),
182
+ },
183
+ accent: {
184
+ fg: resolveColorTokenValue({
185
+ hue,
186
+ scheme,
187
+ value: spec0?.accent?.fg ||
188
+ spec1?.accent?.fg ||
189
+ spec2?.accent?.fg ||
190
+ spec3?.accent?.fg || ['500', '400'],
191
+ }),
192
+ },
193
+ link: {
194
+ fg: resolveColorTokenValue({
195
+ hue,
196
+ scheme,
197
+ value: spec0?.link?.fg ||
198
+ spec1?.link?.fg ||
199
+ spec2?.link?.fg ||
200
+ spec3?.link?.fg || ['500', '400'],
201
+ }),
202
+ },
203
+ code: {
204
+ bg: resolveColorTokenValue({
205
+ hue,
206
+ scheme,
207
+ value: spec0?.code?.bg ||
208
+ spec1?.code?.bg ||
209
+ spec2?.code?.bg ||
210
+ spec3?.code?.bg || ['500', '400'],
211
+ }),
212
+ fg: resolveColorTokenValue({
213
+ hue,
214
+ scheme,
215
+ value: spec0?.code?.fg ||
216
+ spec1?.code?.fg ||
217
+ spec2?.code?.fg ||
218
+ spec3?.code?.fg || ['500', '400'],
219
+ }),
220
+ },
221
+ }
222
+ }
@@ -0,0 +1,226 @@
1
+ import {ColorTint as ColorPaletteValue} from '@sanity/color'
2
+ import {rgba} from '../../../lib/color-fns'
3
+ import {ColorBlendModeValue, parseTokenValue, TMP_ColorPalette} from '../../config'
4
+ import {
5
+ TMP_BaseColorTheme,
6
+ TMP_ButtonColorTheme,
7
+ TMP_ButtonModesColorTheme,
8
+ TMP_ButtonStatesColorTheme,
9
+ TMP_ColorTheme,
10
+ TMP_StateColorTheme,
11
+ } from '../../types'
12
+ import {multiply, screen} from '../helpers'
13
+
14
+ export function renderColorTheme(
15
+ colorPalette: TMP_ColorPalette,
16
+ value: {
17
+ light: TMP_ColorTheme
18
+ dark: TMP_ColorTheme
19
+ },
20
+ ): {
21
+ light: TMP_ColorTheme
22
+ dark: TMP_ColorTheme
23
+ } {
24
+ return {
25
+ light: renderColorScheme(colorPalette, value.light),
26
+ dark: renderColorScheme(colorPalette, value.dark),
27
+ }
28
+ }
29
+
30
+ function renderColorScheme(colorPalette: TMP_ColorPalette, value: TMP_ColorTheme): TMP_ColorTheme {
31
+ const toneEntries = Object.entries(value)
32
+ const [, transparentTone] = toneEntries.find(([k]) => k === 'transparent')!
33
+ const [, defaultTone] = toneEntries.find(([k]) => k === 'default')!
34
+
35
+ const renderedTransparentTone = renderColorBase(
36
+ colorPalette,
37
+ transparentTone,
38
+ transparentTone._blend === 'multiply' ? '#ffffff' : '#000000',
39
+ )
40
+
41
+ const renderedDefaultTone = renderColorBase(
42
+ colorPalette,
43
+ defaultTone,
44
+ defaultTone._blend === 'multiply' ? '#ffffff' : '#000000',
45
+ )
46
+
47
+ return Object.fromEntries([
48
+ ['transparent', renderedTransparentTone],
49
+ ['default', renderedDefaultTone],
50
+ ...toneEntries
51
+ .filter(([k]) => k !== 'default' && k !== 'transparent')
52
+ .map(([k, v]) => [k, renderColorBase(colorPalette, v, renderedDefaultTone.base.bg)]),
53
+ ]) as TMP_ColorTheme
54
+ }
55
+
56
+ function renderColorBase(
57
+ colorPalette: TMP_ColorPalette,
58
+ value: TMP_BaseColorTheme,
59
+ bg: string,
60
+ ): TMP_BaseColorTheme {
61
+ const nestedBg = renderColorValue(colorPalette, bg, value._blend, value.base.bg)
62
+
63
+ return {
64
+ _blend: value._blend,
65
+ dark: value.dark,
66
+ base: {
67
+ bg: nestedBg,
68
+ fg: renderColorValue(colorPalette, nestedBg, value._blend, value.base.fg),
69
+ border: renderColorValue(colorPalette, nestedBg, value._blend, value.base.border),
70
+ },
71
+ button: renderButtonColorTheme(colorPalette, nestedBg, value._blend, value.button),
72
+ }
73
+ }
74
+
75
+ function renderButtonColorTheme(
76
+ colorPalette: TMP_ColorPalette,
77
+ bg: string,
78
+ baseBlendMode: ColorBlendModeValue,
79
+ value: TMP_ButtonColorTheme,
80
+ ): TMP_ButtonColorTheme {
81
+ return {
82
+ default: renderButtonStateColorTheme(colorPalette, bg, baseBlendMode, value.default),
83
+ primary: renderButtonStateColorTheme(colorPalette, bg, baseBlendMode, value.primary),
84
+ positive: renderButtonStateColorTheme(colorPalette, bg, baseBlendMode, value.positive),
85
+ caution: renderButtonStateColorTheme(colorPalette, bg, baseBlendMode, value.caution),
86
+ critical: renderButtonStateColorTheme(colorPalette, bg, baseBlendMode, value.critical),
87
+ }
88
+ }
89
+
90
+ function renderButtonStateColorTheme(
91
+ colorPalette: TMP_ColorPalette,
92
+ bg: string,
93
+ baseBlendMode: ColorBlendModeValue,
94
+ value: TMP_ButtonModesColorTheme,
95
+ ): TMP_ButtonModesColorTheme {
96
+ return {
97
+ default: renderStatesColorTheme(colorPalette, bg, baseBlendMode, value.default),
98
+ ghost: renderStatesColorTheme(colorPalette, bg, baseBlendMode, value.ghost),
99
+ bleed: renderStatesColorTheme(colorPalette, bg, baseBlendMode, value.bleed),
100
+ }
101
+ }
102
+
103
+ function renderStatesColorTheme(
104
+ colorPalette: TMP_ColorPalette,
105
+ bg: string,
106
+ baseBlendMode: ColorBlendModeValue,
107
+ value: TMP_ButtonStatesColorTheme,
108
+ ) {
109
+ return {
110
+ enabled: renderStateColorTheme(colorPalette, bg, baseBlendMode, value.enabled),
111
+ hovered: renderStateColorTheme(colorPalette, bg, baseBlendMode, value.hovered),
112
+ pressed: renderStateColorTheme(colorPalette, bg, baseBlendMode, value.pressed),
113
+ selected: renderStateColorTheme(colorPalette, bg, baseBlendMode, value.selected),
114
+ disabled: renderStateColorTheme(colorPalette, bg, baseBlendMode, value.disabled),
115
+ }
116
+ }
117
+
118
+ function renderStateColorTheme(
119
+ colorPalette: TMP_ColorPalette,
120
+ baseBg: string,
121
+ rootBlendMode: ColorBlendModeValue,
122
+ value: TMP_StateColorTheme,
123
+ ): TMP_StateColorTheme {
124
+ const blendMode = value._blend
125
+
126
+ const bg =
127
+ rootBlendMode === 'multiply' && value.bg === 'white'
128
+ ? '#ffffff'
129
+ : rootBlendMode === 'screen' && value.bg === 'black'
130
+ ? '#000000'
131
+ : renderColorValue(
132
+ colorPalette,
133
+ rootBlendMode === 'multiply' ? '#ffffff' : '#000000',
134
+ rootBlendMode,
135
+ value.bg,
136
+ )
137
+
138
+ const bg2 = renderColorValue(colorPalette, bg, blendMode, value.bg2 || value.bg)
139
+ const fg = renderColorValue(colorPalette, bg, blendMode, value.fg)
140
+ const border = renderColorValue(colorPalette, bg, blendMode, value.border)
141
+ const muted = {
142
+ fg: renderColorValue(colorPalette, bg, blendMode, value.muted.fg),
143
+ }
144
+ const accent = {
145
+ fg: renderColorValue(colorPalette, bg, blendMode, value.accent.fg),
146
+ }
147
+ const link = {
148
+ fg: renderColorValue(colorPalette, bg, blendMode, value.link.fg),
149
+ }
150
+ const code = {
151
+ bg: renderColorValue(colorPalette, bg, blendMode, value.code.bg),
152
+ fg: renderColorValue(colorPalette, bg, blendMode, value.code.fg),
153
+ }
154
+
155
+ const blend = rootBlendMode === 'multiply' ? multiply : screen
156
+
157
+ return {
158
+ _blend: blendMode,
159
+ bg: blend(baseBg, bg),
160
+ bg2: blend(baseBg, bg2),
161
+ fg: blend(baseBg, fg),
162
+ border: blend(baseBg, border),
163
+ muted: {
164
+ fg: blend(baseBg, muted.fg),
165
+ },
166
+ accent: {
167
+ fg: blend(baseBg, accent.fg),
168
+ },
169
+ link: {
170
+ fg: blend(baseBg, link.fg),
171
+ },
172
+ code: {
173
+ bg: blend(baseBg, code.bg),
174
+ fg: blend(baseBg, code.fg),
175
+ },
176
+ }
177
+ }
178
+
179
+ function renderColorValue(
180
+ colorPalette: TMP_ColorPalette,
181
+ bg: string,
182
+ blendMode: ColorBlendModeValue,
183
+ str: string,
184
+ ): string {
185
+ const node = parseTokenValue(str)
186
+
187
+ if (!node || node.type !== 'color') {
188
+ throw new Error(`Invalid color token value: ${str}`)
189
+ }
190
+
191
+ let hex = ''
192
+
193
+ if (node.key === 'black') {
194
+ hex = renderColorHex(colorPalette.black)
195
+ }
196
+
197
+ if (node.key === 'white') {
198
+ hex = renderColorHex(colorPalette.white)
199
+ }
200
+
201
+ if (node.hue && node.tint) {
202
+ hex = renderColorHex(colorPalette[node.hue][node.tint])
203
+ }
204
+
205
+ if (!hex) {
206
+ throw new Error(`Invalid color token value: ${str}`)
207
+ }
208
+
209
+ // apply blend mode
210
+ try {
211
+ hex = blendMode === 'multiply' ? multiply(bg, hex) : screen(bg, hex)
212
+ } catch (err) {
213
+ // eslint-disable-next-line no-console
214
+ console.log('could not blend', hex)
215
+ }
216
+
217
+ if (node.opacity !== undefined) {
218
+ hex = rgba(hex, node.opacity)
219
+ }
220
+
221
+ return hex
222
+ }
223
+
224
+ function renderColorHex(color: string | ColorPaletteValue) {
225
+ return typeof color === 'string' ? color : color.hex
226
+ }
@@ -0,0 +1,8 @@
1
+ import {color} from '@sanity/color'
2
+
3
+ import {TMP_ColorPalette} from '../../config'
4
+
5
+ export const defaultColorPalette: TMP_ColorPalette = {
6
+ ...color,
7
+ black: '#000000',
8
+ }
@@ -0,0 +1,124 @@
1
+ import {ColorTokens} from '../../config'
2
+
3
+ export const defaultColorTokens: ColorTokens = {
4
+ '*': {
5
+ _blend: ['multiply', 'screen'],
6
+ bg: ['50', '950'],
7
+ fg: ['800', '200'],
8
+ border: ['200', '800'],
9
+ },
10
+ transparent: {
11
+ bg: ['50', 'black'],
12
+ fg: ['600', '400'],
13
+ },
14
+ default: {
15
+ bg: ['white', '950'],
16
+ fg: ['black', '200'],
17
+ },
18
+ primary: {
19
+ _hue: 'cyan',
20
+ },
21
+ positive: {
22
+ _hue: 'cyan',
23
+ },
24
+ caution: {
25
+ _hue: 'yellow',
26
+ },
27
+ critical: {
28
+ _hue: 'red',
29
+ },
30
+ button: {
31
+ '*': {
32
+ default: {
33
+ '*': {
34
+ _blend: ['screen', 'multiply'],
35
+ bg: ['500', '400'],
36
+ border: ['500/0', '400/0'],
37
+ },
38
+ hovered: {
39
+ bg: ['600', '300'],
40
+ border: ['600/0', '300/0'],
41
+ },
42
+ pressed: {
43
+ bg: ['700', '200'],
44
+ },
45
+ selected: {
46
+ bg: ['700', '200'],
47
+ },
48
+ disabled: {
49
+ _hue: 'gray',
50
+ bg: ['100', '900'],
51
+ },
52
+ },
53
+ ghost: {
54
+ '*': {
55
+ _blend: ['multiply', 'screen'],
56
+ bg: ['white', 'black'],
57
+ fg: ['600', '400'],
58
+ border: ['200', '800'],
59
+ },
60
+ hovered: {
61
+ bg: ['50', '950'],
62
+ fg: ['700', '300'],
63
+ },
64
+ pressed: {
65
+ bg: ['100', '900'],
66
+ fg: ['800', '200'],
67
+ },
68
+ selected: {
69
+ bg: ['100', '900'],
70
+ fg: ['800', '200'],
71
+ },
72
+ disabled: {
73
+ _hue: 'gray',
74
+ fg: ['100', '900'],
75
+ border: ['100', '900'],
76
+ },
77
+ },
78
+ bleed: {
79
+ '*': {
80
+ _blend: ['multiply', 'screen'],
81
+ bg: ['white', 'black'],
82
+ fg: ['600', '400'],
83
+ border: ['white/0', 'black/0'],
84
+ },
85
+ hovered: {
86
+ bg: ['50', '950'],
87
+ fg: ['700', '300'],
88
+ },
89
+ pressed: {
90
+ bg: ['100', '900'],
91
+ fg: ['800', '200'],
92
+ },
93
+ selected: {
94
+ bg: ['100', '900'],
95
+ fg: ['800', '200'],
96
+ },
97
+ disabled: {
98
+ _hue: 'gray',
99
+ fg: ['100', '900'],
100
+ },
101
+ },
102
+ },
103
+ default: {
104
+ default: {
105
+ '*': {
106
+ bg: ['900', '200'],
107
+ },
108
+ hovered: {
109
+ bg: ['black', '100'],
110
+ },
111
+ pressed: {
112
+ bg: ['900', '200'],
113
+ },
114
+ selected: {
115
+ bg: ['black', '200'],
116
+ },
117
+ disabled: {
118
+ _hue: 'gray',
119
+ bg: ['100', '900'],
120
+ },
121
+ },
122
+ },
123
+ },
124
+ }
@@ -0,0 +1,64 @@
1
+ import {
2
+ parseColor,
3
+ rgbToHex,
4
+ screen as _screen,
5
+ multiply as _multiply,
6
+ rgba,
7
+ } from '../../lib/color-fns'
8
+ import {ColorTokenValue, parseTokenValue, TokenColorValueNode} from '../config'
9
+ import {ColorHueValue} from '../types'
10
+
11
+ export function resolveColorTokenValue(options: {
12
+ hue: ColorHueValue
13
+ scheme: 'light' | 'dark'
14
+ value: ColorTokenValue
15
+ }): string {
16
+ const {hue, scheme, value} = options
17
+ const node = parseTokenValue(value[scheme === 'light' ? 0 : 1])
18
+
19
+ if (!node || node.type !== 'color') {
20
+ throw new Error(`Invalid color token: ${value[0]}`)
21
+ }
22
+
23
+ return compileColorTokenValue({...node, hue: node.hue || hue})
24
+ }
25
+
26
+ export function compileColorTokenValue(node: TokenColorValueNode): string {
27
+ let key = ''
28
+
29
+ if (node.key === 'black' || node.key === 'white') {
30
+ key = node.key
31
+ } else {
32
+ key = `${node.hue}/${node.tint}`
33
+ }
34
+
35
+ if (node.opacity !== undefined) {
36
+ key += `/${node.opacity}`
37
+ }
38
+
39
+ return key
40
+ }
41
+
42
+ export function multiply(bg: string, fg: string): string {
43
+ const b = parseColor(bg)
44
+ const s = parseColor(fg)
45
+ const hex = rgbToHex(_multiply(b, s))
46
+
47
+ if (s.a !== undefined) {
48
+ return rgba(hex, s.a)
49
+ }
50
+
51
+ return hex
52
+ }
53
+
54
+ export function screen(bg: string, fg: string): string {
55
+ const b = parseColor(bg)
56
+ const s = parseColor(fg)
57
+ const hex = rgbToHex(_screen(b, s))
58
+
59
+ if (s.a !== undefined) {
60
+ return rgba(hex, s.a)
61
+ }
62
+
63
+ return hex
64
+ }
@@ -0,0 +1 @@
1
+ export * from './buildTheme'
@@ -0,0 +1,47 @@
1
+ import {parseTokenValue} from './token'
2
+ import {
3
+ COLOR_CONFIG_BASE_KEYS,
4
+ COLOR_CONFIG_BASE_TONES,
5
+ COLOR_CONFIG_BLEND_KEYS,
6
+ COLOR_CONFIG_STATE_KEYS,
7
+ COLOR_CONFIG_STATE_TONES,
8
+ ColorConfigBaseKey,
9
+ ColorConfigBaseTone,
10
+ ColorConfigBlendKey,
11
+ ColorConfigOpacityValue,
12
+ ColorConfigStateKey,
13
+ ColorConfigStateTone,
14
+ ColorConfigValue,
15
+ } from './types'
16
+
17
+ export function isColorConfigBaseTone(str: string): str is ColorConfigBaseTone {
18
+ return COLOR_CONFIG_BASE_TONES.includes(str as ColorConfigBaseTone)
19
+ }
20
+
21
+ export function isColorConfigBaseKey(str: string): str is ColorConfigBaseKey {
22
+ return COLOR_CONFIG_BASE_KEYS.includes(str as ColorConfigBaseKey)
23
+ }
24
+
25
+ export function isColorConfigStateKey(str: string): str is ColorConfigStateKey {
26
+ return COLOR_CONFIG_STATE_KEYS.includes(str as ColorConfigStateKey)
27
+ }
28
+
29
+ export function isColorConfigStateTone(str: string): str is ColorConfigStateTone {
30
+ return COLOR_CONFIG_STATE_TONES.includes(str as ColorConfigStateTone)
31
+ }
32
+
33
+ export function isColorConfigBlendKey(str: string): str is ColorConfigBlendKey {
34
+ return COLOR_CONFIG_BLEND_KEYS.includes(str as ColorConfigBlendKey)
35
+ }
36
+
37
+ export function isColorTokenValue(str: string): str is ColorConfigValue {
38
+ return parseTokenValue(str)?.type === 'color' || parseTokenValue(str)?.type === 'hue'
39
+ }
40
+
41
+ export function isColorValue(str: string): str is 'black' | 'white' {
42
+ return str === 'black' || str === 'white'
43
+ }
44
+
45
+ export function isColorOpacityValue(str: string): str is ColorConfigOpacityValue {
46
+ return str === '0' || /^0\.[0-9]+$/.test(str) || str === '1'
47
+ }
@@ -0,0 +1,3 @@
1
+ export * from './helpers'
2
+ export * from './token'
3
+ export * from './types'
@@ -0,0 +1,2 @@
1
+ export * from './parseTokenKey'
2
+ export * from './parseTokenValue'