@microbit/ui 0.1.0-alpha.28 → 0.1.0-alpha.29
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/package.json +1 -1
- package/src/Button.recipe.ts +52 -25
- package/src/Button.tsx +2 -1
- package/src/Field.recipe.ts +2 -4
- package/src/LinkButton.tsx +2 -1
- package/src/base-preset.ts +38 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@microbit/ui",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.29",
|
|
4
4
|
"description": "micro:bit design-system primitives: react-aria-components + Panda CSS with a design language ported from Chakra UI v2. Ships as source; see README for the consumption setup.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/src/Button.recipe.ts
CHANGED
|
@@ -20,11 +20,9 @@ const transitionCommon =
|
|
|
20
20
|
*
|
|
21
21
|
* A config recipe (not a component cva): styles land in the `recipes` layer so
|
|
22
22
|
* call sites can override with plain style props, and presets extend the
|
|
23
|
-
* variants.
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* `led`/`record*`/`secondary-disabled`). Brand divergence within a variant is
|
|
27
|
-
* token-driven (see the `button.*` and `languageText` semantic tokens).
|
|
23
|
+
* variants. Colour reaches a variant either through the `button.*` semantic
|
|
24
|
+
* tokens (the app's button idiom) or through `tone`, never through a per-app
|
|
25
|
+
* fork of a shape.
|
|
28
26
|
*
|
|
29
27
|
* Registered in the base preset (base-preset.ts).
|
|
30
28
|
*/
|
|
@@ -131,29 +129,40 @@ export const button = defineRecipe({
|
|
|
131
129
|
},
|
|
132
130
|
_active: { bg: "button.primaryActiveBg" },
|
|
133
131
|
},
|
|
134
|
-
//
|
|
135
|
-
//
|
|
136
|
-
//
|
|
137
|
-
//
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
132
|
+
// `solid`/`outline` are coloured by `tone`, and reference only the
|
|
133
|
+
// stops it guarantees (50/500/600/700). They are not `primary`/
|
|
134
|
+
// `secondary` in another colour: those follow the app's button idiom,
|
|
135
|
+
// which is black-on-white in half the family and so can't be a palette.
|
|
136
|
+
solid: {
|
|
137
|
+
color: "white",
|
|
138
|
+
bg: "colorPalette.500",
|
|
139
|
+
_hover: {
|
|
140
|
+
bg: "colorPalette.600",
|
|
141
|
+
_disabled: { bg: "colorPalette.500" },
|
|
142
|
+
},
|
|
143
|
+
_active: { bg: "colorPalette.700" },
|
|
144
|
+
},
|
|
145
|
+
// Border at 500 (a boundary needs only 3:1) so a `solid`/`outline`
|
|
146
|
+
// toggle pair shows the same edge either way; the label needs 600.
|
|
147
|
+
//
|
|
148
|
+
// Classroom restates two other outlines per call site — a neutral 1px
|
|
149
|
+
// grey one and a white-on-colour one. Promote either if a second
|
|
150
|
+
// consumer appears.
|
|
151
|
+
outline: {
|
|
141
152
|
borderWidth: "2px",
|
|
142
|
-
borderColor: "
|
|
143
|
-
color: "
|
|
153
|
+
borderColor: "colorPalette.500",
|
|
154
|
+
color: "colorPalette.600",
|
|
144
155
|
bg: "transparent",
|
|
145
|
-
_hover: { borderColor: "
|
|
146
|
-
_active: { bg: "
|
|
156
|
+
_hover: { borderColor: "colorPalette.600", color: "colorPalette.700" },
|
|
157
|
+
_active: { bg: "colorPalette.50" },
|
|
147
158
|
},
|
|
148
|
-
//
|
|
149
|
-
//
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
bg: "
|
|
155
|
-
_hover: { bg: "danger.600", _disabled: { bg: "danger.500" } },
|
|
156
|
-
_active: { bg: "danger.700" },
|
|
159
|
+
// Not a palette shape: a light fill under dark text is a different
|
|
160
|
+
// button from `solid`, and 350 exists in no other ramp.
|
|
161
|
+
neutral: {
|
|
162
|
+
color: "gray.800",
|
|
163
|
+
bg: "gray.100",
|
|
164
|
+
_hover: { bg: "gray.300", _disabled: { bg: "gray.100" } },
|
|
165
|
+
_active: { bg: "gray.350" },
|
|
157
166
|
},
|
|
158
167
|
// Family-wide variant (every censused app has toolbar-class buttons).
|
|
159
168
|
// No ring override: the bar decides, and a dark one must spread
|
|
@@ -165,9 +174,27 @@ export const button = defineRecipe({
|
|
|
165
174
|
_active: { bg: "whiteAlpha.800" },
|
|
166
175
|
},
|
|
167
176
|
},
|
|
177
|
+
/**
|
|
178
|
+
* The palette behind `solid`/`outline`. An allowlist rather than Panda's
|
|
179
|
+
* open `colorPalette` prop, because a palette missing a stop a shape
|
|
180
|
+
* reads renders it as nothing at all, with no error anywhere
|
|
181
|
+
* (docs/hints.md): this is where a palette is vetted. A tone should
|
|
182
|
+
* alias a whole ramp, so it has nowhere to fall through. Apps may add
|
|
183
|
+
* their own.
|
|
184
|
+
*/
|
|
185
|
+
tone: {
|
|
186
|
+
brand: { colorPalette: "brand" },
|
|
187
|
+
// The destructive role, which a brand preset can re-point.
|
|
188
|
+
danger: { colorPalette: "danger" },
|
|
189
|
+
// Conventional red that isn't destructive (record buttons), so
|
|
190
|
+
// deliberately not following a brand's error colour.
|
|
191
|
+
red: { colorPalette: "red" },
|
|
192
|
+
},
|
|
168
193
|
},
|
|
169
194
|
defaultVariants: {
|
|
170
195
|
variant: "secondary",
|
|
171
196
|
size: "md",
|
|
197
|
+
// Never absent: a shape with no palette renders nothing.
|
|
198
|
+
tone: "brand",
|
|
172
199
|
},
|
|
173
200
|
});
|
package/src/Button.tsx
CHANGED
|
@@ -71,6 +71,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
|
|
71
71
|
{
|
|
72
72
|
variant,
|
|
73
73
|
size,
|
|
74
|
+
tone,
|
|
74
75
|
css: cssProp,
|
|
75
76
|
className,
|
|
76
77
|
leftIcon,
|
|
@@ -96,7 +97,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
|
|
96
97
|
<RACButton
|
|
97
98
|
ref={ref}
|
|
98
99
|
className={cx(
|
|
99
|
-
button({ variant, size }),
|
|
100
|
+
button({ variant, size, tone }),
|
|
100
101
|
cssProp ? css(cssProp) : undefined,
|
|
101
102
|
className,
|
|
102
103
|
)}
|
package/src/Field.recipe.ts
CHANGED
|
@@ -52,8 +52,7 @@ export const field = defineSlotRecipe({
|
|
|
52
52
|
},
|
|
53
53
|
requiredIndicator: {
|
|
54
54
|
marginStart: "1",
|
|
55
|
-
|
|
56
|
-
color: "danger.600",
|
|
55
|
+
color: "danger.500",
|
|
57
56
|
},
|
|
58
57
|
helperText: {
|
|
59
58
|
// RAC's Text renders a span, and RadioGroup/CheckboxGroup roots are not
|
|
@@ -71,8 +70,7 @@ export const field = defineSlotRecipe({
|
|
|
71
70
|
mt: "2",
|
|
72
71
|
fontSize: "sm",
|
|
73
72
|
lineHeight: "normal",
|
|
74
|
-
|
|
75
|
-
color: "danger.600",
|
|
73
|
+
color: "danger.500",
|
|
76
74
|
},
|
|
77
75
|
},
|
|
78
76
|
variants: {
|
package/src/LinkButton.tsx
CHANGED
|
@@ -48,6 +48,7 @@ export const LinkButton = forwardRef<HTMLAnchorElement, LinkButtonProps>(
|
|
|
48
48
|
{
|
|
49
49
|
variant,
|
|
50
50
|
size,
|
|
51
|
+
tone,
|
|
51
52
|
css: cssProp,
|
|
52
53
|
className,
|
|
53
54
|
leftIcon,
|
|
@@ -61,7 +62,7 @@ export const LinkButton = forwardRef<HTMLAnchorElement, LinkButtonProps>(
|
|
|
61
62
|
<RACLink
|
|
62
63
|
ref={ref}
|
|
63
64
|
className={cx(
|
|
64
|
-
button({ variant, size }),
|
|
65
|
+
button({ variant, size, tone }),
|
|
65
66
|
css(linkReset, cssProp),
|
|
66
67
|
className,
|
|
67
68
|
)}
|
package/src/base-preset.ts
CHANGED
|
@@ -83,6 +83,25 @@ const gray = {
|
|
|
83
83
|
900: { value: "#1a1a1a" },
|
|
84
84
|
};
|
|
85
85
|
|
|
86
|
+
// The family red, on the gray ramp's ladder — it is the conventional colour
|
|
87
|
+
// for errors and recording, not a brand colour, so it can be graded rather
|
|
88
|
+
// than negotiated. 400 was already exactly gray's 3:1 and stays verbatim,
|
|
89
|
+
// anchoring the hue and saturation the darker stops hold while their
|
|
90
|
+
// lightness solves for gray's ratio. The washes have no contract and keep
|
|
91
|
+
// their values.
|
|
92
|
+
const red = {
|
|
93
|
+
50: { value: "#FFF5F5" },
|
|
94
|
+
100: { value: "#FED7D7" },
|
|
95
|
+
200: { value: "#FEB2B2" },
|
|
96
|
+
300: { value: "#FC8181" },
|
|
97
|
+
400: { value: "#F56565" }, // 3.03:1
|
|
98
|
+
500: { value: "#e22b2b" }, // 4.55:1 — the white-text fill stop
|
|
99
|
+
600: { value: "#ac1818" },
|
|
100
|
+
700: { value: "#811212" },
|
|
101
|
+
800: { value: "#4f0b0b" },
|
|
102
|
+
900: { value: "#380808" },
|
|
103
|
+
};
|
|
104
|
+
|
|
86
105
|
/**
|
|
87
106
|
* The base preset: the complete, working micro:bit design system. The base
|
|
88
107
|
* token scales (base-tokens.ts), the micro:bit house style
|
|
@@ -141,6 +160,7 @@ export const basePreset = definePreset({
|
|
|
141
160
|
colors: {
|
|
142
161
|
...colors,
|
|
143
162
|
gray,
|
|
163
|
+
red,
|
|
144
164
|
// OSS default brand ramps (see the brand contract above). `brand`
|
|
145
165
|
// aliases the blue ramp; `brand2` is a frozen legacy alias of the
|
|
146
166
|
// slate gray in base-tokens, deliberately decoupled from the neutral
|
|
@@ -208,16 +228,20 @@ export const basePreset = definePreset({
|
|
|
208
228
|
focusRing: {
|
|
209
229
|
value: { base: "{colors.gray.900}", _onDark: "{colors.white}" },
|
|
210
230
|
},
|
|
211
|
-
// Error/destructive ramp
|
|
212
|
-
//
|
|
213
|
-
//
|
|
214
|
-
// danger).
|
|
231
|
+
// Error/destructive ramp: field error states, the error toast, and
|
|
232
|
+
// the `danger` button tone. Aliased whole, not just at the stops in
|
|
233
|
+
// use, so a tone has nowhere to fall through (Button.recipe.ts).
|
|
215
234
|
danger: {
|
|
216
235
|
50: { value: "{colors.red.50}" },
|
|
217
236
|
100: { value: "{colors.red.100}" },
|
|
237
|
+
200: { value: "{colors.red.200}" },
|
|
238
|
+
300: { value: "{colors.red.300}" },
|
|
239
|
+
400: { value: "{colors.red.400}" },
|
|
218
240
|
500: { value: "{colors.red.500}" },
|
|
219
241
|
600: { value: "{colors.red.600}" },
|
|
220
242
|
700: { value: "{colors.red.700}" },
|
|
243
|
+
800: { value: "{colors.red.800}" },
|
|
244
|
+
900: { value: "{colors.red.900}" },
|
|
221
245
|
},
|
|
222
246
|
// The language-dialog cards' text colour (@microbit/ui-patterns'
|
|
223
247
|
// LanguageDialog) follows the primary interactive brand: every
|
|
@@ -259,7 +283,9 @@ export const basePreset = definePreset({
|
|
|
259
283
|
toastInfoBg: { value: "{colors.teal.800}" },
|
|
260
284
|
toastSuccessBg: { value: "{colors.teal.800}" },
|
|
261
285
|
toastWarningBg: { value: "{colors.teal.800}" },
|
|
262
|
-
|
|
286
|
+
// 500, the text-safe stop, rather than following the teal toasts'
|
|
287
|
+
// 800: white on it is 4.55:1 and an error toast should read as red.
|
|
288
|
+
toastErrorBg: { value: "{colors.danger.500}" },
|
|
263
289
|
// The native app's status-bar area colour, shared by the ActionBar
|
|
264
290
|
// and the full-size dialog's safe-area gradient.
|
|
265
291
|
statusBarBg: { value: "{colors.brand2.500}" },
|
|
@@ -384,7 +410,13 @@ export const basePreset = definePreset({
|
|
|
384
410
|
// too — otherwise the class lands on the element with no rule behind it
|
|
385
411
|
// and the button silently falls back to the base size.
|
|
386
412
|
avatar: ["*"],
|
|
387
|
-
|
|
413
|
+
// `tone` generates as its own rule, not crossed with `variant`: it
|
|
414
|
+
// only assigns the palette custom properties a shape reads.
|
|
415
|
+
button: [
|
|
416
|
+
{ size: ["*"], responsive: true },
|
|
417
|
+
{ variant: ["*"] },
|
|
418
|
+
{ tone: ["*"] },
|
|
419
|
+
],
|
|
388
420
|
checkbox: ["*"],
|
|
389
421
|
heading: ["*"],
|
|
390
422
|
card: ["*"],
|