@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.
- package/dist/index.cjs.mjs +27 -0
- package/dist/index.d.ts +337 -7
- package/dist/index.esm.js +745 -58
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +772 -58
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/theme/_internal/__workshop__/build/story.tsx +178 -0
- package/src/theme/_internal/__workshop__/build/theme.ts +3 -0
- package/src/theme/_internal/__workshop__/index.ts +14 -0
- package/src/theme/_internal/build/buildTheme.test.ts +78 -0
- package/src/theme/_internal/build/buildTheme.ts +15 -0
- package/src/theme/_internal/build/colorTheme/buildColorTheme.test.ts +185 -0
- package/src/theme/_internal/build/colorTheme/buildColorTheme.ts +222 -0
- package/src/theme/_internal/build/colorTheme/renderColorTheme.ts +226 -0
- package/src/theme/_internal/build/defaults/colorPalette.ts +8 -0
- package/src/theme/_internal/build/defaults/colorTokens.ts +124 -0
- package/src/theme/_internal/build/helpers.ts +64 -0
- package/src/theme/_internal/build/index.ts +1 -0
- package/src/theme/_internal/config/helpers.ts +47 -0
- package/src/theme/_internal/config/index.ts +3 -0
- package/src/theme/_internal/config/token/index.ts +2 -0
- package/src/theme/_internal/config/token/parseTokenKey.test.ts +72 -0
- package/src/theme/_internal/config/token/parseTokenKey.ts +88 -0
- package/src/theme/_internal/config/token/parseTokenValue.test.ts +45 -0
- package/src/theme/_internal/config/token/parseTokenValue.ts +123 -0
- package/src/theme/_internal/config/types.ts +126 -0
- package/src/theme/_internal/constants.ts +48 -0
- package/src/theme/_internal/helpers.ts +19 -0
- package/src/theme/_internal/index.ts +5 -0
- package/src/theme/_internal/types.ts +72 -0
- 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,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
|
+
}
|