@sanity/ui 2.0.0-alpha.2 → 2.0.0-alpha.21
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 +28 -0
- package/dist/index.d.ts +476 -12
- package/dist/index.esm.js +1326 -524
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1353 -523
- package/dist/index.js.map +1 -1
- package/package.json +6 -8
- package/src/components/autocomplete/autocomplete.tsx +6 -0
- package/src/components/dialog/constants.ts +4 -0
- package/src/components/dialog/dialog.tsx +79 -15
- package/src/components/hotkeys/hotkeys.tsx +2 -0
- package/src/components/menu/menu.tsx +2 -0
- package/src/components/menu/menuButton.tsx +2 -0
- package/src/components/menu/menuGroup.tsx +22 -23
- package/src/components/menu/menuItem.tsx +29 -35
- package/src/components/tab/tab.tsx +4 -1
- package/src/components/toast/toast.tsx +4 -0
- package/src/primitives/_selectable/style.ts +2 -1
- package/src/primitives/avatar/avatar.tsx +16 -9
- package/src/primitives/avatar/avatarCounter.tsx +3 -3
- package/src/primitives/avatar/styles.ts +1 -1
- package/src/primitives/badge/badge.tsx +7 -3
- package/src/primitives/box/box.tsx +3 -0
- package/src/primitives/button/__workshop__/sanityUploadButton.tsx +2 -1
- package/src/primitives/button/button.tsx +7 -3
- package/src/primitives/button/styles.ts +9 -2
- package/src/primitives/card/card.tsx +4 -0
- package/src/primitives/card/styles.ts +2 -0
- package/src/primitives/checkbox/checkbox.tsx +2 -0
- package/src/primitives/code/code.tsx +1 -0
- package/src/primitives/container/container.tsx +2 -0
- package/src/primitives/flex/flex.tsx +2 -0
- package/src/primitives/grid/grid.tsx +2 -0
- package/src/primitives/heading/heading.tsx +2 -0
- package/src/primitives/inline/inline.tsx +3 -0
- package/src/primitives/kbd/kbd.tsx +2 -0
- package/src/primitives/label/label.tsx +2 -0
- package/src/primitives/popover/popover.tsx +6 -1
- package/src/primitives/radio/radio.tsx +2 -0
- package/src/primitives/select/select.tsx +2 -0
- package/src/primitives/select/styles.ts +2 -0
- package/src/primitives/spinner/spinner.tsx +2 -0
- package/src/primitives/stack/stack.tsx +2 -0
- package/src/primitives/switch/switch.tsx +4 -0
- package/src/primitives/text/text.tsx +3 -0
- package/src/primitives/textArea/textArea.tsx +4 -1
- package/src/primitives/textInput/textInput.tsx +10 -1
- package/src/primitives/tooltip/__workshop__/customPortal.tsx +99 -0
- package/src/primitives/tooltip/__workshop__/index.ts +15 -0
- package/src/primitives/tooltip/__workshop__/overflowingBoundary.tsx +73 -0
- package/src/primitives/tooltip/__workshop__/resizableBoundary.tsx +85 -0
- package/src/primitives/tooltip/constants.ts +1 -0
- package/src/primitives/tooltip/tooltip.test.tsx +192 -0
- package/src/primitives/tooltip/tooltip.tsx +109 -33
- package/src/primitives/types.ts +4 -0
- package/src/styles/input/textInputStyle.ts +11 -6
- package/src/theme/_internal/__workshop__/build/story.tsx +288 -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 +16 -0
- package/src/theme/_internal/build/colorTheme/buildColorTheme.test.ts +185 -0
- package/src/theme/_internal/build/colorTheme/buildColorTheme.ts +164 -0
- package/src/theme/_internal/build/colorTheme/renderColorTheme.ts +242 -0
- package/src/theme/_internal/build/colorTheme/resolveColorTokens.ts +121 -0
- package/src/theme/_internal/build/defaults/colorPalette.ts +8 -0
- package/src/theme/_internal/build/defaults/colorTokens.ts +147 -0
- package/src/theme/_internal/build/helpers.ts +65 -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 +137 -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 +91 -0
- package/src/theme/index.ts +1 -0
- package/src/theme/lib/color-fns/blend/multiply.ts +2 -2
- package/src/theme/lib/color-fns/blend/screen.ts +2 -2
- package/src/theme/lib/color-fns/convert.ts +15 -1
- package/src/theme/lib/color-fns/parse.ts +7 -3
- package/src/theme/lib/color-fns/types.ts +11 -0
- package/src/theme/lib/theme/avatar.ts +2 -0
- package/src/theme/lib/theme/color/_legacy/createColorTheme.ts +7 -0
- package/src/theme/lib/theme/color/_legacy/index.ts +1 -0
- package/src/theme/lib/theme/color/_legacy/legacyColor.ts +3997 -0
- package/src/theme/studioTheme/color.ts +98 -82
- package/src/theme/studioTheme/helpers.ts +15 -1
- package/src/theme/studioTheme/theme.ts +5 -5
- package/src/theme/studioTheme/tints.ts +244 -84
- package/src/types/button.ts +5 -0
|
@@ -0,0 +1,164 @@
|
|
|
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 {ColorTokenContext, resolveColorTokenValue as _color} from '../helpers'
|
|
17
|
+
import {resolveColorTokens} from './resolveColorTokens'
|
|
18
|
+
|
|
19
|
+
export function buildColorTheme(
|
|
20
|
+
options: {scheme: 'light' | 'dark'},
|
|
21
|
+
config?: ThemeConfig,
|
|
22
|
+
): TMP_ColorTheme {
|
|
23
|
+
const {scheme} = options
|
|
24
|
+
|
|
25
|
+
const resolvedConfig = {
|
|
26
|
+
...config,
|
|
27
|
+
color: {
|
|
28
|
+
...config?.color,
|
|
29
|
+
tokens: resolveColorTokens(config?.color?.tokens ?? defaultColorTokens),
|
|
30
|
+
},
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
transparent: buildBaseColorTheme({scheme, tone: 'transparent'}, resolvedConfig),
|
|
35
|
+
default: buildBaseColorTheme({scheme, tone: 'default'}, resolvedConfig),
|
|
36
|
+
primary: buildBaseColorTheme({scheme, tone: 'primary'}, resolvedConfig),
|
|
37
|
+
positive: buildBaseColorTheme({scheme, tone: 'positive'}, resolvedConfig),
|
|
38
|
+
caution: buildBaseColorTheme({scheme, tone: 'caution'}, resolvedConfig),
|
|
39
|
+
critical: buildBaseColorTheme({scheme, tone: 'critical'}, resolvedConfig),
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function buildBaseColorTheme(
|
|
44
|
+
options: {scheme: 'light' | 'dark'; tone: ColorBaseTone},
|
|
45
|
+
config?: ThemeConfig,
|
|
46
|
+
): TMP_BaseColorTheme {
|
|
47
|
+
const {scheme, tone} = options
|
|
48
|
+
const tokens = config?.color?.tokens?.[tone]
|
|
49
|
+
const hue = tokens?._hue || 'gray'
|
|
50
|
+
const context: ColorTokenContext = {hue, scheme}
|
|
51
|
+
const bg = _color(context, tokens?.bg || ['gray/50', 'black'])
|
|
52
|
+
const blendMode = tokens?._blend || ['screen', 'multiply']
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
_blend: blendMode[scheme === 'light' ? 0 : 1],
|
|
56
|
+
dark: scheme === 'dark',
|
|
57
|
+
base: {
|
|
58
|
+
bg,
|
|
59
|
+
fg: _color(context, tokens?.fg || ['black', 'white']),
|
|
60
|
+
border: _color(context, tokens?.border || ['black', 'white']),
|
|
61
|
+
focusRing: _color(context, tokens?.focusRing || ['black', 'white']),
|
|
62
|
+
shadow: {
|
|
63
|
+
outline: _color(context, tokens?.shadow?.outline || ['500/0.2', '500/0.2']),
|
|
64
|
+
umbra: _color(context, tokens?.shadow?.umbra || ['500/0.2', '500/0.2']),
|
|
65
|
+
penumbra: _color(context, tokens?.shadow?.penumbra || ['500/0.2', '500/0.2']),
|
|
66
|
+
ambient: _color(context, tokens?.shadow?.ambient || ['500/0.2', '500/0.2']),
|
|
67
|
+
},
|
|
68
|
+
skeleton: {
|
|
69
|
+
from: _color(context, tokens?.skeleton?.from || ['500/0.2', '500/0.2']),
|
|
70
|
+
to: _color(context, tokens?.skeleton?.to || ['500/0.2', '500/0.2']),
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
button: buildButtonColorTheme({scheme}, config),
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function buildButtonColorTheme(
|
|
78
|
+
options: {scheme: 'light' | 'dark'},
|
|
79
|
+
config?: ThemeConfig,
|
|
80
|
+
): TMP_ButtonColorTheme {
|
|
81
|
+
const {scheme} = options
|
|
82
|
+
|
|
83
|
+
const tones = COLOR_STATE_TONES.map((tone): Partial<TMP_ButtonColorTheme> => {
|
|
84
|
+
return {
|
|
85
|
+
[tone]: buildButtonColorToneTheme({scheme, tone}, config),
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
return Object.assign({}, ...tones) as TMP_ButtonColorTheme
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function buildButtonColorToneTheme(
|
|
93
|
+
options: {
|
|
94
|
+
scheme: 'light' | 'dark'
|
|
95
|
+
tone: ColorStateTone
|
|
96
|
+
},
|
|
97
|
+
config?: ThemeConfig,
|
|
98
|
+
): TMP_ButtonModesColorTheme {
|
|
99
|
+
const {scheme, tone} = options
|
|
100
|
+
|
|
101
|
+
const modes = COLOR_BUTTON_MODES.map((mode): Partial<TMP_ButtonModesColorTheme> => {
|
|
102
|
+
return {
|
|
103
|
+
[mode]: buildButtonModeColorTheme({mode, scheme, tone}, config),
|
|
104
|
+
}
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
return Object.assign({}, ...modes) as TMP_ButtonModesColorTheme
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function buildButtonModeColorTheme(
|
|
111
|
+
options: {
|
|
112
|
+
mode: ColorButtonMode
|
|
113
|
+
scheme: 'light' | 'dark'
|
|
114
|
+
tone: ColorStateTone
|
|
115
|
+
},
|
|
116
|
+
config?: ThemeConfig,
|
|
117
|
+
): TMP_ButtonStatesColorTheme {
|
|
118
|
+
const {mode, scheme, tone} = options
|
|
119
|
+
|
|
120
|
+
const states = COLOR_STATES.map((state): Partial<TMP_ButtonStatesColorTheme> => {
|
|
121
|
+
return {
|
|
122
|
+
[state]: buildButtonStateColorTheme({mode, tone, scheme, state}, config),
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
return Object.assign({}, ...states) as TMP_ButtonStatesColorTheme
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function buildButtonStateColorTheme(
|
|
130
|
+
options: {
|
|
131
|
+
mode: ColorButtonMode
|
|
132
|
+
tone: ColorStateTone
|
|
133
|
+
scheme: 'light' | 'dark'
|
|
134
|
+
state: ColorState
|
|
135
|
+
},
|
|
136
|
+
config?: ThemeConfig,
|
|
137
|
+
): TMP_StateColorTheme {
|
|
138
|
+
const {mode, tone, scheme, state} = options
|
|
139
|
+
const tokens = config?.color?.tokens?.button?.[tone]?.[mode]?.[state]
|
|
140
|
+
const hue = tokens?._hue || 'gray'
|
|
141
|
+
const blendMode = tokens?._blend || ['screen', 'multiply']
|
|
142
|
+
const context: ColorTokenContext = {hue, scheme}
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
_blend: blendMode[scheme === 'light' ? 0 : 1],
|
|
146
|
+
bg: _color(context, tokens?.bg || ['500', '400']),
|
|
147
|
+
bg2: _color(context, tokens?.bg2 || ['500', '400']),
|
|
148
|
+
fg: _color(context, tokens?.fg || ['white', 'black']),
|
|
149
|
+
border: _color(context, tokens?.border || ['500', '400']),
|
|
150
|
+
muted: {
|
|
151
|
+
fg: _color(context, tokens?.fg || ['500', '400']),
|
|
152
|
+
},
|
|
153
|
+
accent: {
|
|
154
|
+
fg: _color(context, tokens?.fg || ['500', '400']),
|
|
155
|
+
},
|
|
156
|
+
link: {
|
|
157
|
+
fg: _color(context, tokens?.fg || ['500', '400']),
|
|
158
|
+
},
|
|
159
|
+
code: {
|
|
160
|
+
bg: _color(context, tokens?.bg || ['500', '400']),
|
|
161
|
+
fg: _color(context, tokens?.fg || ['500', '400']),
|
|
162
|
+
},
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import {ColorTint as ColorPaletteValue} from '@sanity/color'
|
|
2
|
+
import {rgba} from '../../../lib/color-fns'
|
|
3
|
+
import {ColorBlendModeValue, parseTokenValue, ThemeConfig, 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
|
+
TMP_Theme,
|
|
12
|
+
} from '../../types'
|
|
13
|
+
import {defaultColorPalette} from '../defaults/colorPalette'
|
|
14
|
+
import {multiply, screen} from '../helpers'
|
|
15
|
+
|
|
16
|
+
export function renderColorTheme(
|
|
17
|
+
value: TMP_Theme['color'],
|
|
18
|
+
config?: ThemeConfig,
|
|
19
|
+
): TMP_Theme['color'] {
|
|
20
|
+
const colorPalette = config?.color?.palette ?? defaultColorPalette
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
light: renderColorScheme(colorPalette, value.light),
|
|
24
|
+
dark: renderColorScheme(colorPalette, value.dark),
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function renderColorScheme(colorPalette: TMP_ColorPalette, value: TMP_ColorTheme): TMP_ColorTheme {
|
|
29
|
+
const toneEntries = Object.entries(value)
|
|
30
|
+
const [, transparentTone] = toneEntries.find(([k]) => k === 'transparent')!
|
|
31
|
+
const [, defaultTone] = toneEntries.find(([k]) => k === 'default')!
|
|
32
|
+
|
|
33
|
+
const renderedTransparentTone = renderColorBase(
|
|
34
|
+
colorPalette,
|
|
35
|
+
transparentTone,
|
|
36
|
+
transparentTone._blend === 'multiply' ? '#ffffff' : '#000000',
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
const renderedDefaultTone = renderColorBase(
|
|
40
|
+
colorPalette,
|
|
41
|
+
defaultTone,
|
|
42
|
+
defaultTone._blend === 'multiply' ? '#ffffff' : '#000000',
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
return Object.fromEntries([
|
|
46
|
+
['transparent', renderedTransparentTone],
|
|
47
|
+
['default', renderedDefaultTone],
|
|
48
|
+
...toneEntries
|
|
49
|
+
.filter(([k]) => k !== 'default' && k !== 'transparent')
|
|
50
|
+
.map(([k, v]) => [k, renderColorBase(colorPalette, v, renderedDefaultTone.base.bg)]),
|
|
51
|
+
]) as TMP_ColorTheme
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function renderColorBase(
|
|
55
|
+
colorPalette: TMP_ColorPalette,
|
|
56
|
+
value: TMP_BaseColorTheme,
|
|
57
|
+
bg: string,
|
|
58
|
+
): TMP_BaseColorTheme {
|
|
59
|
+
const nestedBg = renderColorValue(colorPalette, bg, value._blend, value.base.bg)
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
_blend: value._blend,
|
|
63
|
+
dark: value.dark,
|
|
64
|
+
base: {
|
|
65
|
+
bg: nestedBg,
|
|
66
|
+
fg: renderColorValue(colorPalette, nestedBg, value._blend, value.base.fg),
|
|
67
|
+
border: renderColorValue(colorPalette, nestedBg, value._blend, value.base.border),
|
|
68
|
+
focusRing: renderColorValue(colorPalette, nestedBg, value._blend, value.base.focusRing),
|
|
69
|
+
shadow: {
|
|
70
|
+
outline: renderColorValue(colorPalette, nestedBg, value._blend, value.base.shadow.outline),
|
|
71
|
+
umbra: renderColorValue(colorPalette, nestedBg, value._blend, value.base.shadow.umbra),
|
|
72
|
+
penumbra: renderColorValue(
|
|
73
|
+
colorPalette,
|
|
74
|
+
nestedBg,
|
|
75
|
+
value._blend,
|
|
76
|
+
value.base.shadow.penumbra,
|
|
77
|
+
),
|
|
78
|
+
ambient: renderColorValue(colorPalette, nestedBg, value._blend, value.base.shadow.ambient),
|
|
79
|
+
},
|
|
80
|
+
skeleton: {
|
|
81
|
+
from: renderColorValue(colorPalette, nestedBg, value._blend, value.base.skeleton.from),
|
|
82
|
+
to: renderColorValue(colorPalette, nestedBg, value._blend, value.base.skeleton.to),
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
button: renderButtonColorTheme(colorPalette, nestedBg, value._blend, value.button),
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function renderButtonColorTheme(
|
|
90
|
+
colorPalette: TMP_ColorPalette,
|
|
91
|
+
bg: string,
|
|
92
|
+
baseBlendMode: ColorBlendModeValue,
|
|
93
|
+
value: TMP_ButtonColorTheme,
|
|
94
|
+
): TMP_ButtonColorTheme {
|
|
95
|
+
return {
|
|
96
|
+
default: renderButtonStateColorTheme(colorPalette, bg, baseBlendMode, value.default),
|
|
97
|
+
primary: renderButtonStateColorTheme(colorPalette, bg, baseBlendMode, value.primary),
|
|
98
|
+
positive: renderButtonStateColorTheme(colorPalette, bg, baseBlendMode, value.positive),
|
|
99
|
+
caution: renderButtonStateColorTheme(colorPalette, bg, baseBlendMode, value.caution),
|
|
100
|
+
critical: renderButtonStateColorTheme(colorPalette, bg, baseBlendMode, value.critical),
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function renderButtonStateColorTheme(
|
|
105
|
+
colorPalette: TMP_ColorPalette,
|
|
106
|
+
bg: string,
|
|
107
|
+
baseBlendMode: ColorBlendModeValue,
|
|
108
|
+
value: TMP_ButtonModesColorTheme,
|
|
109
|
+
): TMP_ButtonModesColorTheme {
|
|
110
|
+
return {
|
|
111
|
+
default: renderStatesColorTheme(colorPalette, bg, baseBlendMode, value.default),
|
|
112
|
+
ghost: renderStatesColorTheme(colorPalette, bg, baseBlendMode, value.ghost),
|
|
113
|
+
bleed: renderStatesColorTheme(colorPalette, bg, baseBlendMode, value.bleed),
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function renderStatesColorTheme(
|
|
118
|
+
colorPalette: TMP_ColorPalette,
|
|
119
|
+
bg: string,
|
|
120
|
+
baseBlendMode: ColorBlendModeValue,
|
|
121
|
+
value: TMP_ButtonStatesColorTheme,
|
|
122
|
+
) {
|
|
123
|
+
return {
|
|
124
|
+
enabled: renderStateColorTheme(colorPalette, bg, baseBlendMode, value.enabled),
|
|
125
|
+
hovered: renderStateColorTheme(colorPalette, bg, baseBlendMode, value.hovered),
|
|
126
|
+
pressed: renderStateColorTheme(colorPalette, bg, baseBlendMode, value.pressed),
|
|
127
|
+
selected: renderStateColorTheme(colorPalette, bg, baseBlendMode, value.selected),
|
|
128
|
+
disabled: renderStateColorTheme(colorPalette, bg, baseBlendMode, value.disabled),
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function renderStateColorTheme(
|
|
133
|
+
colorPalette: TMP_ColorPalette,
|
|
134
|
+
baseBg: string,
|
|
135
|
+
rootBlendMode: ColorBlendModeValue,
|
|
136
|
+
value: TMP_StateColorTheme,
|
|
137
|
+
): TMP_StateColorTheme {
|
|
138
|
+
const blendMode = value._blend
|
|
139
|
+
|
|
140
|
+
const bg =
|
|
141
|
+
rootBlendMode === 'multiply' && value.bg === 'white'
|
|
142
|
+
? '#ffffff'
|
|
143
|
+
: rootBlendMode === 'screen' && value.bg === 'black'
|
|
144
|
+
? '#000000'
|
|
145
|
+
: renderColorValue(
|
|
146
|
+
colorPalette,
|
|
147
|
+
rootBlendMode === 'multiply' ? '#ffffff' : '#000000',
|
|
148
|
+
rootBlendMode,
|
|
149
|
+
value.bg,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
const blend = rootBlendMode === 'multiply' ? multiply : screen
|
|
153
|
+
|
|
154
|
+
const unmixed = {
|
|
155
|
+
bg2: renderColorValue(colorPalette, bg, blendMode, value.bg2 || value.bg),
|
|
156
|
+
fg: renderColorValue(colorPalette, bg, blendMode, value.fg),
|
|
157
|
+
border: renderColorValue(colorPalette, bg, blendMode, value.border),
|
|
158
|
+
muted: {
|
|
159
|
+
fg: renderColorValue(colorPalette, bg, blendMode, value.muted.fg),
|
|
160
|
+
},
|
|
161
|
+
accent: {
|
|
162
|
+
fg: renderColorValue(colorPalette, bg, blendMode, value.accent.fg),
|
|
163
|
+
},
|
|
164
|
+
link: {
|
|
165
|
+
fg: renderColorValue(colorPalette, bg, blendMode, value.link.fg),
|
|
166
|
+
},
|
|
167
|
+
code: {
|
|
168
|
+
bg: renderColorValue(colorPalette, bg, blendMode, value.code.bg),
|
|
169
|
+
fg: renderColorValue(colorPalette, bg, blendMode, value.code.fg),
|
|
170
|
+
},
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
_blend: blendMode,
|
|
175
|
+
bg: blend(baseBg, bg),
|
|
176
|
+
bg2: blend(baseBg, unmixed.bg2),
|
|
177
|
+
fg: blend(baseBg, unmixed.fg),
|
|
178
|
+
border: blend(baseBg, unmixed.border),
|
|
179
|
+
muted: {
|
|
180
|
+
fg: blend(baseBg, unmixed.muted.fg),
|
|
181
|
+
},
|
|
182
|
+
accent: {
|
|
183
|
+
fg: blend(baseBg, unmixed.accent.fg),
|
|
184
|
+
},
|
|
185
|
+
link: {
|
|
186
|
+
fg: blend(baseBg, unmixed.link.fg),
|
|
187
|
+
},
|
|
188
|
+
code: {
|
|
189
|
+
bg: blend(baseBg, unmixed.code.bg),
|
|
190
|
+
fg: blend(baseBg, unmixed.code.fg),
|
|
191
|
+
},
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function renderColorValue(
|
|
196
|
+
colorPalette: TMP_ColorPalette,
|
|
197
|
+
bg: string,
|
|
198
|
+
blendMode: ColorBlendModeValue,
|
|
199
|
+
str: string,
|
|
200
|
+
): string {
|
|
201
|
+
const node = parseTokenValue(str)
|
|
202
|
+
|
|
203
|
+
if (!node || node.type !== 'color') {
|
|
204
|
+
throw new Error(`Invalid color token value: ${str}`)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
let hex = ''
|
|
208
|
+
|
|
209
|
+
if (node.key === 'black') {
|
|
210
|
+
hex = renderColorHex(colorPalette.black)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (node.key === 'white') {
|
|
214
|
+
hex = renderColorHex(colorPalette.white)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (node.hue && node.tint) {
|
|
218
|
+
hex = renderColorHex(colorPalette[node.hue][node.tint])
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (!hex) {
|
|
222
|
+
throw new Error(`Invalid color token value: ${str}`)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// apply blend mode
|
|
226
|
+
try {
|
|
227
|
+
hex = blendMode === 'multiply' ? multiply(bg, hex) : screen(bg, hex)
|
|
228
|
+
} catch (err) {
|
|
229
|
+
// eslint-disable-next-line no-console
|
|
230
|
+
console.log('could not blend', hex)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (node.opacity !== undefined) {
|
|
234
|
+
hex = rgba(hex, node.opacity)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return hex
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function renderColorHex(color: string | ColorPaletteValue) {
|
|
241
|
+
return typeof color === 'string' ? color : color.hex
|
|
242
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BaseColorTokens,
|
|
3
|
+
ButtonColorTokens,
|
|
4
|
+
ButtonModeColorTokens,
|
|
5
|
+
ColorConfigStateTone,
|
|
6
|
+
ColorTokens,
|
|
7
|
+
StateColorTokens,
|
|
8
|
+
} from '../../config'
|
|
9
|
+
import {
|
|
10
|
+
COLOR_BASE_TONES,
|
|
11
|
+
COLOR_BUTTON_MODES,
|
|
12
|
+
COLOR_STATES,
|
|
13
|
+
COLOR_STATE_TONES,
|
|
14
|
+
} from '../../constants'
|
|
15
|
+
import {ColorBaseTone, ColorButtonMode, ColorState, ColorStateTone} from '../../types'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Convert a tree of color tokens from a sparse format to a dense format.
|
|
19
|
+
*/
|
|
20
|
+
export function resolveColorTokens(sparseTokens: ColorTokens): ColorTokens {
|
|
21
|
+
const denseTokens: ColorTokens = {...sparseTokens}
|
|
22
|
+
|
|
23
|
+
// base tones
|
|
24
|
+
for (const tone of COLOR_BASE_TONES) {
|
|
25
|
+
denseTokens[tone] = resolveBaseColorTones(sparseTokens, tone)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// button
|
|
29
|
+
denseTokens.button = resolveButtonColorTokens(sparseTokens)
|
|
30
|
+
|
|
31
|
+
return denseTokens
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function resolveBaseColorTones(sparseTokens: ColorTokens, tone: ColorBaseTone): BaseColorTokens {
|
|
35
|
+
const spec0 = sparseTokens?.[tone]
|
|
36
|
+
const spec1 = sparseTokens?.['*']
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
...spec1,
|
|
40
|
+
...spec0,
|
|
41
|
+
shadow: {...spec1?.shadow, ...spec0?.shadow},
|
|
42
|
+
skeleton: {...spec1?.skeleton, ...spec0?.skeleton},
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function resolveButtonColorTokens(
|
|
47
|
+
sparseTokens: ColorTokens,
|
|
48
|
+
): Partial<Record<ColorConfigStateTone, ButtonColorTokens>> {
|
|
49
|
+
const tokens: Partial<Record<ColorConfigStateTone, ButtonColorTokens>> = {}
|
|
50
|
+
|
|
51
|
+
for (const tone of COLOR_STATE_TONES) {
|
|
52
|
+
tokens[tone] = resolveButtonToneColorTokens(sparseTokens, tone)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return tokens
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function resolveButtonToneColorTokens(
|
|
59
|
+
sparseTokens: ColorTokens,
|
|
60
|
+
tone: ColorStateTone,
|
|
61
|
+
): ButtonColorTokens {
|
|
62
|
+
const tokens: ButtonColorTokens = {
|
|
63
|
+
...sparseTokens.button?.[tone],
|
|
64
|
+
...sparseTokens.button?.['*'],
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
for (const mode of COLOR_BUTTON_MODES) {
|
|
68
|
+
tokens[mode] = resolveButtonModeColorTokens(sparseTokens, tone, mode)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return tokens
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function resolveButtonModeColorTokens(
|
|
75
|
+
sparseTokens: ColorTokens,
|
|
76
|
+
tone: ColorStateTone,
|
|
77
|
+
mode: ColorButtonMode,
|
|
78
|
+
): ButtonModeColorTokens {
|
|
79
|
+
const spec0 = sparseTokens.button?.[tone]?.[mode]
|
|
80
|
+
const spec1 = sparseTokens.button?.['*']?.[mode]
|
|
81
|
+
const tokens = {...spec1, ...spec0}
|
|
82
|
+
|
|
83
|
+
for (const state of COLOR_STATES) {
|
|
84
|
+
tokens[state] = resolveButtonStateColorTokens(sparseTokens, tone, mode, state)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return tokens
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function resolveButtonStateColorTokens(
|
|
91
|
+
tokens: ColorTokens,
|
|
92
|
+
tone: ColorStateTone,
|
|
93
|
+
mode: ColorButtonMode,
|
|
94
|
+
state: ColorState,
|
|
95
|
+
): StateColorTokens {
|
|
96
|
+
const spec0 = tokens?.button?.[tone]?.[mode]?.[state]
|
|
97
|
+
const spec1 = tokens?.button?.[tone]?.[mode]?.['*']
|
|
98
|
+
const spec2 = tokens?.button?.['*']?.[mode]?.[state]
|
|
99
|
+
const spec3 = tokens?.button?.['*']?.[mode]?.['*']
|
|
100
|
+
|
|
101
|
+
const hue =
|
|
102
|
+
spec0?._hue ||
|
|
103
|
+
spec1?._hue ||
|
|
104
|
+
spec2?._hue ||
|
|
105
|
+
spec3?._hue ||
|
|
106
|
+
tokens?.button?.[tone]?._hue ||
|
|
107
|
+
tokens?.[tone]?._hue
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
...spec3,
|
|
111
|
+
...spec2,
|
|
112
|
+
...spec1,
|
|
113
|
+
...spec0,
|
|
114
|
+
_hue: hue,
|
|
115
|
+
muted: {...spec3?.muted, ...spec2?.muted, ...spec1?.muted, ...spec0?.muted},
|
|
116
|
+
accent: {...spec3?.accent, ...spec2?.accent, ...spec1?.accent, ...spec0?.accent},
|
|
117
|
+
link: {...spec3?.link, ...spec2?.link, ...spec1?.link, ...spec0?.link},
|
|
118
|
+
code: {...spec3?.code, ...spec2?.code, ...spec1?.code, ...spec0?.code},
|
|
119
|
+
skeleton: {...spec3?.skeleton, ...spec2?.skeleton, ...spec1?.skeleton, ...spec0?.skeleton},
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
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
|
+
focusRing: ['cyan/500', 'cyan/500'],
|
|
10
|
+
shadow: {
|
|
11
|
+
outline: ['500/0.25', '400/0.3'],
|
|
12
|
+
umbra: ['500/0.1', 'black/0.4'],
|
|
13
|
+
penumbra: ['500/0.07', 'black/0.28'],
|
|
14
|
+
ambient: ['500/0.06', 'black/0.24'],
|
|
15
|
+
},
|
|
16
|
+
skeleton: {
|
|
17
|
+
from: ['100', '900'],
|
|
18
|
+
to: ['100/0.5', '900/0.5'],
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
transparent: {
|
|
22
|
+
bg: ['50', 'black'],
|
|
23
|
+
fg: ['600', '400'],
|
|
24
|
+
},
|
|
25
|
+
default: {
|
|
26
|
+
bg: ['white', '950'],
|
|
27
|
+
fg: ['black', '200'],
|
|
28
|
+
},
|
|
29
|
+
primary: {
|
|
30
|
+
_hue: 'cyan',
|
|
31
|
+
},
|
|
32
|
+
positive: {
|
|
33
|
+
_hue: 'cyan',
|
|
34
|
+
},
|
|
35
|
+
caution: {
|
|
36
|
+
_hue: 'yellow',
|
|
37
|
+
},
|
|
38
|
+
critical: {
|
|
39
|
+
_hue: 'red',
|
|
40
|
+
},
|
|
41
|
+
button: {
|
|
42
|
+
'*': {
|
|
43
|
+
default: {
|
|
44
|
+
'*': {
|
|
45
|
+
_blend: ['screen', 'multiply'],
|
|
46
|
+
bg: ['500', '400'],
|
|
47
|
+
bg2: ['950', '50'],
|
|
48
|
+
border: ['500/0', '400/0'],
|
|
49
|
+
muted: {
|
|
50
|
+
fg: ['200', '700'],
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
hovered: {
|
|
54
|
+
bg: ['600', '300'],
|
|
55
|
+
border: ['600/0', '300/0'],
|
|
56
|
+
},
|
|
57
|
+
pressed: {
|
|
58
|
+
bg: ['700', '200'],
|
|
59
|
+
},
|
|
60
|
+
selected: {
|
|
61
|
+
bg: ['700', '200'],
|
|
62
|
+
},
|
|
63
|
+
disabled: {
|
|
64
|
+
_hue: 'gray',
|
|
65
|
+
bg: ['200', '900'],
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
ghost: {
|
|
69
|
+
'*': {
|
|
70
|
+
_blend: ['multiply', 'screen'],
|
|
71
|
+
bg: ['white', 'black'],
|
|
72
|
+
bg2: ['50', '950'],
|
|
73
|
+
fg: ['600', '400'],
|
|
74
|
+
border: ['200', '800'],
|
|
75
|
+
muted: {
|
|
76
|
+
fg: ['600/0.6', '400/0.6'],
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
hovered: {
|
|
80
|
+
bg: ['50', '950'],
|
|
81
|
+
fg: ['700', '300'],
|
|
82
|
+
},
|
|
83
|
+
pressed: {
|
|
84
|
+
bg: ['100', '900'],
|
|
85
|
+
fg: ['800', '200'],
|
|
86
|
+
},
|
|
87
|
+
selected: {
|
|
88
|
+
bg: ['100', '900'],
|
|
89
|
+
fg: ['800', '200'],
|
|
90
|
+
},
|
|
91
|
+
disabled: {
|
|
92
|
+
_hue: 'gray',
|
|
93
|
+
fg: ['200', '900'],
|
|
94
|
+
border: ['100', '950'],
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
bleed: {
|
|
98
|
+
'*': {
|
|
99
|
+
_blend: ['multiply', 'screen'],
|
|
100
|
+
bg: ['white', 'black'],
|
|
101
|
+
bg2: ['50', '950'],
|
|
102
|
+
fg: ['600', '400'],
|
|
103
|
+
border: ['white/0', 'black/0'],
|
|
104
|
+
muted: {
|
|
105
|
+
fg: ['600/0.6', '400/0.6'],
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
hovered: {
|
|
109
|
+
bg: ['50', '950'],
|
|
110
|
+
fg: ['700', '300'],
|
|
111
|
+
},
|
|
112
|
+
pressed: {
|
|
113
|
+
bg: ['100', '900'],
|
|
114
|
+
fg: ['800', '200'],
|
|
115
|
+
},
|
|
116
|
+
selected: {
|
|
117
|
+
bg: ['100', '900'],
|
|
118
|
+
fg: ['800', '200'],
|
|
119
|
+
},
|
|
120
|
+
disabled: {
|
|
121
|
+
_hue: 'gray',
|
|
122
|
+
fg: ['200', '900'],
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
default: {
|
|
127
|
+
default: {
|
|
128
|
+
'*': {
|
|
129
|
+
bg: ['900', '200'],
|
|
130
|
+
},
|
|
131
|
+
hovered: {
|
|
132
|
+
bg: ['black', '100'],
|
|
133
|
+
},
|
|
134
|
+
pressed: {
|
|
135
|
+
bg: ['900', '200'],
|
|
136
|
+
},
|
|
137
|
+
selected: {
|
|
138
|
+
bg: ['black', '200'],
|
|
139
|
+
},
|
|
140
|
+
disabled: {
|
|
141
|
+
_hue: 'gray',
|
|
142
|
+
bg: ['200', '900'],
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
}
|