@microbit/ui 0.1.0-alpha.10
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/LICENSE.md +53 -0
- package/README.md +220 -0
- package/lang/ui.ca.json +22 -0
- package/lang/ui.de.json +22 -0
- package/lang/ui.en-us.json +22 -0
- package/lang/ui.en.json +22 -0
- package/lang/ui.es-es.json +22 -0
- package/lang/ui.fr.json +22 -0
- package/lang/ui.ga-ie.json +22 -0
- package/lang/ui.ja.json +22 -0
- package/lang/ui.ko.json +22 -0
- package/lang/ui.lol.json +22 -0
- package/lang/ui.nl.json +22 -0
- package/lang/ui.pl.json +22 -0
- package/lang/ui.pt-br.json +22 -0
- package/lang/ui.zh-cn.json +22 -0
- package/lang/ui.zh-tw.json +22 -0
- package/package.json +58 -0
- package/postcss-legacy-safari.cjs +96 -0
- package/reset.css +35 -0
- package/src/Button.recipe.ts +162 -0
- package/src/Button.tsx +69 -0
- package/src/ButtonGroup.tsx +63 -0
- package/src/Card.recipe.ts +49 -0
- package/src/Card.tsx +56 -0
- package/src/Checkbox.recipe.ts +105 -0
- package/src/Checkbox.tsx +76 -0
- package/src/CloseButton.tsx +87 -0
- package/src/CloseIcon.tsx +40 -0
- package/src/Code.tsx +20 -0
- package/src/Collapse.tsx +180 -0
- package/src/Divider.tsx +52 -0
- package/src/Drawer.recipe.ts +98 -0
- package/src/Drawer.tsx +138 -0
- package/src/Fade.tsx +48 -0
- package/src/Heading.recipe.ts +52 -0
- package/src/Heading.tsx +14 -0
- package/src/Icon.tsx +55 -0
- package/src/IconButton.tsx +44 -0
- package/src/Image.tsx +11 -0
- package/src/Input.recipe.ts +72 -0
- package/src/Input.tsx +40 -0
- package/src/InputGroup.tsx +62 -0
- package/src/Kbd.tsx +26 -0
- package/src/Link.tsx +23 -0
- package/src/LinkBox.tsx +88 -0
- package/src/LinkButton.tsx +80 -0
- package/src/List.tsx +31 -0
- package/src/Menu.recipe.ts +119 -0
- package/src/Menu.tsx +261 -0
- package/src/Modal.recipe.ts +163 -0
- package/src/Modal.tsx +279 -0
- package/src/NativeSelect.tsx +94 -0
- package/src/NumberField.recipe.ts +67 -0
- package/src/NumberField.tsx +86 -0
- package/src/PopoverArrow.tsx +67 -0
- package/src/ProgressBar.tsx +61 -0
- package/src/Radio.recipe.ts +107 -0
- package/src/Radio.tsx +89 -0
- package/src/SharedUIProvider.tsx +55 -0
- package/src/Slide.tsx +54 -0
- package/src/Slider.recipe.ts +102 -0
- package/src/Slider.tsx +163 -0
- package/src/Spinner.tsx +69 -0
- package/src/Svg.tsx +23 -0
- package/src/Switch.recipe.ts +107 -0
- package/src/Switch.tsx +62 -0
- package/src/Text.recipe.ts +29 -0
- package/src/Text.tsx +16 -0
- package/src/TextField.recipe.ts +54 -0
- package/src/TextField.tsx +89 -0
- package/src/Toast.recipe.ts +98 -0
- package/src/Toast.tsx +171 -0
- package/src/Tooltip.tsx +91 -0
- package/src/UnmountCallback.tsx +18 -0
- package/src/VisuallyHidden.tsx +14 -0
- package/src/base-preset.ts +294 -0
- package/src/base-tokens.ts +1017 -0
- package/src/button-icon.ts +23 -0
- package/src/hooks/useBreakpointValue.ts +63 -0
- package/src/hooks/useClipboard.ts +64 -0
- package/src/hooks/useMediaQuery.ts +28 -0
- package/src/hooks/usePrevious.ts +18 -0
- package/src/index.ts +55 -0
- package/src/messages.ts +17 -0
- package/src/system.ts +36 -0
package/src/Tooltip.tsx
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* (c) 2026, Micro:bit Educational Foundation and contributors
|
|
3
|
+
*
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { ReactElement, ReactNode, RefObject } from "react";
|
|
7
|
+
import { Tooltip as RACTooltip, TooltipTrigger } from "react-aria-components";
|
|
8
|
+
import { css } from "styled-system/css";
|
|
9
|
+
import { SystemStyleObject } from "styled-system/types";
|
|
10
|
+
import { PopoverArrow } from "./PopoverArrow";
|
|
11
|
+
|
|
12
|
+
// Base as an object (not a precomputed class) so a caller's `css` override is
|
|
13
|
+
// merged into a single css() call — Panda then dedupes conflicting utilities
|
|
14
|
+
// (e.g. px/py) so overrides actually win.
|
|
15
|
+
const tooltipBase: SystemStyleObject = {
|
|
16
|
+
bg: "gray.700",
|
|
17
|
+
color: "white",
|
|
18
|
+
px: "2",
|
|
19
|
+
py: "1",
|
|
20
|
+
borderRadius: "md",
|
|
21
|
+
fontSize: "sm",
|
|
22
|
+
fontWeight: "medium",
|
|
23
|
+
boxShadow: "md",
|
|
24
|
+
maxW: "xs",
|
|
25
|
+
zIndex: "tooltip",
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export interface TooltipProps {
|
|
29
|
+
/**
|
|
30
|
+
* Tooltip body (Chakra's `label`). Not named `content`: Panda extracts
|
|
31
|
+
* utility-named props with literal values from any JSX component, so a
|
|
32
|
+
* `content` prop taking a string would emit a broken CSS `content` rule.
|
|
33
|
+
*/
|
|
34
|
+
label: ReactNode;
|
|
35
|
+
/** A single focusable trigger element (e.g. a Button). */
|
|
36
|
+
children: ReactElement;
|
|
37
|
+
placement?:
|
|
38
|
+
| "top"
|
|
39
|
+
| "bottom"
|
|
40
|
+
| "left"
|
|
41
|
+
| "right"
|
|
42
|
+
| "top start"
|
|
43
|
+
| "top end"
|
|
44
|
+
| "bottom start"
|
|
45
|
+
| "bottom end"
|
|
46
|
+
| "left top"
|
|
47
|
+
| "left bottom"
|
|
48
|
+
| "right top"
|
|
49
|
+
| "right bottom";
|
|
50
|
+
hasArrow?: boolean;
|
|
51
|
+
/** Controlled open state (otherwise hover/focus driven). */
|
|
52
|
+
isOpen?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Anchor element for positioning, when the child cannot register itself as
|
|
55
|
+
* the trigger (i.e. it is not a RAC component or `Focusable`).
|
|
56
|
+
*/
|
|
57
|
+
triggerRef?: RefObject<HTMLElement | null>;
|
|
58
|
+
/** Hover open delay in ms (RAC default ~1500; pass 0 for instant). */
|
|
59
|
+
delay?: number;
|
|
60
|
+
css?: SystemStyleObject;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Tooltip — react-aria-components TooltipTrigger + Tooltip, styled to match
|
|
65
|
+
* Chakra's dark tooltip. The child must be a focusable element so the tooltip
|
|
66
|
+
* is reachable by keyboard (RAC requirement), unless `triggerRef` provides
|
|
67
|
+
* the anchor and the caller manages open state and keyboard access itself.
|
|
68
|
+
*/
|
|
69
|
+
export const Tooltip = ({
|
|
70
|
+
label,
|
|
71
|
+
children,
|
|
72
|
+
placement = "top",
|
|
73
|
+
hasArrow,
|
|
74
|
+
isOpen,
|
|
75
|
+
triggerRef,
|
|
76
|
+
delay = 0,
|
|
77
|
+
css: cssProp,
|
|
78
|
+
}: TooltipProps) => (
|
|
79
|
+
<TooltipTrigger isOpen={isOpen} delay={delay} closeDelay={0}>
|
|
80
|
+
{children}
|
|
81
|
+
<RACTooltip
|
|
82
|
+
triggerRef={triggerRef}
|
|
83
|
+
placement={placement}
|
|
84
|
+
offset={hasArrow ? 8 : 4}
|
|
85
|
+
className={css({ ...tooltipBase, ...cssProp })}
|
|
86
|
+
>
|
|
87
|
+
{hasArrow && <PopoverArrow css={{ "& svg": { fill: "gray.700" } }} />}
|
|
88
|
+
{label}
|
|
89
|
+
</RACTooltip>
|
|
90
|
+
</TooltipTrigger>
|
|
91
|
+
);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* (c) 2026, Micro:bit Educational Foundation and contributors
|
|
3
|
+
*
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { useEffect, useRef } from "react";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Runs its callback when unmounted. RAC keeps an overlay tree mounted until
|
|
10
|
+
* the exit transition finishes, so mounting this inside a Modal/Drawer gives
|
|
11
|
+
* the equivalent of Chakra's `onCloseComplete`. Internal to shared-ui.
|
|
12
|
+
*/
|
|
13
|
+
export const UnmountCallback = ({ callback }: { callback?: () => void }) => {
|
|
14
|
+
const ref = useRef(callback);
|
|
15
|
+
ref.current = callback;
|
|
16
|
+
useEffect(() => () => ref.current?.(), []);
|
|
17
|
+
return null;
|
|
18
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* (c) 2026, Micro:bit Educational Foundation and contributors
|
|
3
|
+
*
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { styled } from "styled-system/jsx";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* VisuallyHidden — screen-reader-only content (Panda's `srOnly` utility).
|
|
10
|
+
* Renders a span like Chakra's; use `as="div"` for block children.
|
|
11
|
+
*/
|
|
12
|
+
export const VisuallyHidden = styled("span", {
|
|
13
|
+
base: { srOnly: true },
|
|
14
|
+
});
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* (c) 2026, Micro:bit Educational Foundation and contributors
|
|
3
|
+
*
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { definePreset } from "@pandacss/dev";
|
|
7
|
+
import {
|
|
8
|
+
blurs,
|
|
9
|
+
borders,
|
|
10
|
+
breakpoints,
|
|
11
|
+
colors,
|
|
12
|
+
durations,
|
|
13
|
+
easings,
|
|
14
|
+
fontSizes,
|
|
15
|
+
fontWeights,
|
|
16
|
+
letterSpacings,
|
|
17
|
+
lineHeights,
|
|
18
|
+
radii,
|
|
19
|
+
shadows,
|
|
20
|
+
sizes,
|
|
21
|
+
spacing,
|
|
22
|
+
zIndex,
|
|
23
|
+
} from "./base-tokens";
|
|
24
|
+
// Config recipes are colocated with the shared-ui components they style; this
|
|
25
|
+
// preset registers them so Panda merges them at codegen time.
|
|
26
|
+
import { button } from "./Button.recipe";
|
|
27
|
+
import { card } from "./Card.recipe";
|
|
28
|
+
import { checkbox } from "./Checkbox.recipe";
|
|
29
|
+
import { radio } from "./Radio.recipe";
|
|
30
|
+
import { drawer } from "./Drawer.recipe";
|
|
31
|
+
import { heading } from "./Heading.recipe";
|
|
32
|
+
import { input } from "./Input.recipe";
|
|
33
|
+
import { numberField } from "./NumberField.recipe";
|
|
34
|
+
import { menu } from "./Menu.recipe";
|
|
35
|
+
import { slider } from "./Slider.recipe";
|
|
36
|
+
import { switchRecipe } from "./Switch.recipe";
|
|
37
|
+
import { dialog } from "./Modal.recipe";
|
|
38
|
+
import { text } from "./Text.recipe";
|
|
39
|
+
import { field } from "./TextField.recipe";
|
|
40
|
+
import { toast } from "./Toast.recipe";
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The base preset: the complete, working micro:bit design system. The base
|
|
44
|
+
* token scales (base-tokens.ts), the micro:bit house style
|
|
45
|
+
* (pill `radii.button`, `outline*` focus shadows, Helvetica fonts, the
|
|
46
|
+
* `language`/`toolbar` button variants in Button.recipe.ts, the
|
|
47
|
+
* `languageText`/`toast*Bg`/`statusBarBg` semantic tokens), the shared-ui
|
|
48
|
+
* component recipes, the react-aria condition widening, the Chakra-reset
|
|
49
|
+
* parity `globalCss`, and the `staticCss` that keeps runtime-prop recipe
|
|
50
|
+
* variants generated. Used alone it renders in the OSS default look.
|
|
51
|
+
*
|
|
52
|
+
* ── Brand contract ──────────────────────────────────────────────────────
|
|
53
|
+
* A private brand preset (a sibling repo, e.g. CreateAI) is merged AFTER this
|
|
54
|
+
* one to restyle everything by overriding just these token *values* (never
|
|
55
|
+
* their names — see the CSS-var contract in the README):
|
|
56
|
+
* - colours: the `brand` and `brand2` ramps (OSS defaults: Chakra
|
|
57
|
+
* blue / Chakra's unmodified gray). Other ramps a brand tweaks
|
|
58
|
+
* (teal/purple/pink/…) already exist in the Chakra scales below.
|
|
59
|
+
* - font: `display` (OSS default: Helvetica; e.g. GT Walsheim privately).
|
|
60
|
+
* The recipes and semantic tokens here reference those, so a brand swap needs
|
|
61
|
+
* no recipe changes. With no private preset, these OSS defaults stand.
|
|
62
|
+
*/
|
|
63
|
+
export const basePreset = definePreset({
|
|
64
|
+
name: "microbit-ui-base",
|
|
65
|
+
theme: {
|
|
66
|
+
breakpoints,
|
|
67
|
+
keyframes: {
|
|
68
|
+
// Spinner's revolution (the only keyframe a shared-ui component uses).
|
|
69
|
+
spin: {
|
|
70
|
+
"0%": { transform: "rotate(0deg)" },
|
|
71
|
+
"100%": { transform: "rotate(360deg)" },
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
tokens: {
|
|
75
|
+
colors: {
|
|
76
|
+
...colors,
|
|
77
|
+
gray: {
|
|
78
|
+
...colors.gray,
|
|
79
|
+
// Very light grays the family's designs use below Chakra's 50.
|
|
80
|
+
10: { value: "#fcfcfc" },
|
|
81
|
+
25: { value: "#f5f5f5" },
|
|
82
|
+
},
|
|
83
|
+
// OSS default brand ramps (see the brand contract above). `brand`
|
|
84
|
+
// aliases Chakra blue; `brand2` Chakra's *unmodified* gray (not the
|
|
85
|
+
// `gray` above, whose 10/25 additions are lighter — getting this
|
|
86
|
+
// wrong once made card text near-invisible).
|
|
87
|
+
brand: colors.blue,
|
|
88
|
+
brand2: colors.gray,
|
|
89
|
+
},
|
|
90
|
+
spacing,
|
|
91
|
+
sizes,
|
|
92
|
+
fontSizes,
|
|
93
|
+
fontWeights,
|
|
94
|
+
lineHeights,
|
|
95
|
+
letterSpacings,
|
|
96
|
+
zIndex,
|
|
97
|
+
blurs,
|
|
98
|
+
borders,
|
|
99
|
+
durations,
|
|
100
|
+
easings,
|
|
101
|
+
radii: {
|
|
102
|
+
...radii,
|
|
103
|
+
// Pill button radius (4/4 apps in the family census).
|
|
104
|
+
button: { value: "2rem" },
|
|
105
|
+
},
|
|
106
|
+
shadows: {
|
|
107
|
+
...shadows,
|
|
108
|
+
// Chakra's outline shadow widened to 4px, plus dark/light-surface
|
|
109
|
+
// companions. Consumed via the `focusShadow` utility.
|
|
110
|
+
outline: { value: "0 0 0 4px rgba(66, 153, 225, 0.6)" },
|
|
111
|
+
outlineDark: { value: "0 0 0 4px rgba(0, 0, 0, 0.5)" },
|
|
112
|
+
outlineLight: { value: "0 0 0 4px rgba(255, 255, 255, 0.8)" },
|
|
113
|
+
},
|
|
114
|
+
fonts: {
|
|
115
|
+
// Helvetica heading/body (4/4 apps); a brand preset leaves these and
|
|
116
|
+
// overrides only `display` (the marketing font — see the brand
|
|
117
|
+
// contract above). `mono` is Chakra's default stack.
|
|
118
|
+
heading: { value: "Helvetica, Arial, sans-serif" },
|
|
119
|
+
body: { value: "Helvetica, Arial, sans-serif" },
|
|
120
|
+
mono: {
|
|
121
|
+
value:
|
|
122
|
+
'SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace',
|
|
123
|
+
},
|
|
124
|
+
// OSS default marketing font (the `marketing` heading variant). No OSS
|
|
125
|
+
// brand display face, so it falls back to the body stack.
|
|
126
|
+
display: { value: "Helvetica, Arial, sans-serif" },
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
semanticTokens: {
|
|
130
|
+
colors: {
|
|
131
|
+
// Checked/focus states of form controls (Chakra's default blue
|
|
132
|
+
// colorScheme). Checkbox/Switch checked backgrounds, Input focus
|
|
133
|
+
// border, and the Slider/ProgressBar fills (the last two are
|
|
134
|
+
// near-dead defaults - current call sites override them).
|
|
135
|
+
controlCheckedBg: { value: "{colors.blue.500}" },
|
|
136
|
+
controlCheckedHoverBg: { value: "{colors.blue.600}" },
|
|
137
|
+
focusBorder: { value: "{colors.blue.500}" },
|
|
138
|
+
sliderFilledTrack: { value: "{colors.blue.500}" },
|
|
139
|
+
progressFilledTrack: { value: "{colors.blue.500}" },
|
|
140
|
+
// Error/destructive ramp (Chakra red). Destructive button variants,
|
|
141
|
+
// field error states and the error toast; the record* button
|
|
142
|
+
// variants deliberately stay on red.* (recording vocabulary, not
|
|
143
|
+
// danger).
|
|
144
|
+
danger: {
|
|
145
|
+
50: { value: "{colors.red.50}" },
|
|
146
|
+
100: { value: "{colors.red.100}" },
|
|
147
|
+
500: { value: "{colors.red.500}" },
|
|
148
|
+
600: { value: "{colors.red.600}" },
|
|
149
|
+
700: { value: "{colors.red.700}" },
|
|
150
|
+
},
|
|
151
|
+
// The `language` button variant's text colour follows the primary
|
|
152
|
+
// interactive brand: every consumer resolves it to its `brand` ramp
|
|
153
|
+
// (CreateAI privately to brand.600 with no hover change,
|
|
154
|
+
// python-editor to brand.500/600 — the default). Semantic tokens so
|
|
155
|
+
// the recipe stays shared and a brand preset overrides only values.
|
|
156
|
+
// (Was brand2.* — the grey ml-trainer OSS Chakra look — but both
|
|
157
|
+
// apps' final values sit on their primary brand, so the default
|
|
158
|
+
// follows; OSS language buttons are brand blue.)
|
|
159
|
+
languageText: { value: "{colors.brand.500}" },
|
|
160
|
+
languageTextHover: { value: "{colors.brand.600}" },
|
|
161
|
+
// Toast status colours: the Chakra-era toast Alert restyle (teal for
|
|
162
|
+
// every status except error) shared across the app family.
|
|
163
|
+
toastInfoBg: { value: "{colors.teal.800}" },
|
|
164
|
+
toastSuccessBg: { value: "{colors.teal.800}" },
|
|
165
|
+
toastWarningBg: { value: "{colors.teal.800}" },
|
|
166
|
+
toastErrorBg: { value: "{colors.danger.600}" },
|
|
167
|
+
// The native app's status-bar area colour, shared by the ActionBar
|
|
168
|
+
// and the full-size dialog's safe-area gradient.
|
|
169
|
+
statusBarBg: { value: "{colors.brand2.500}" },
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
recipes: {
|
|
173
|
+
button,
|
|
174
|
+
heading,
|
|
175
|
+
input,
|
|
176
|
+
text,
|
|
177
|
+
},
|
|
178
|
+
slotRecipes: {
|
|
179
|
+
card,
|
|
180
|
+
checkbox,
|
|
181
|
+
dialog,
|
|
182
|
+
drawer,
|
|
183
|
+
field,
|
|
184
|
+
menu,
|
|
185
|
+
numberField,
|
|
186
|
+
radio,
|
|
187
|
+
slider,
|
|
188
|
+
switchRecipe,
|
|
189
|
+
toast,
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
// What ChakraProvider used to inject and Panda's preflight doesn't cover:
|
|
193
|
+
// the theme's styles.global (body text/background defaults, global
|
|
194
|
+
// border/placeholder colours) plus the parts of Chakra's CSS reset that
|
|
195
|
+
// Panda's has no equivalent for — kerning/text-rendering (their absence
|
|
196
|
+
// shifts glyphs page-wide), word-wrap and touch-action. Token references
|
|
197
|
+
// resolve against the merged preset stack, so the values track any brand
|
|
198
|
+
// overrides exactly as they did under Chakra's runtime theme.
|
|
199
|
+
globalCss: {
|
|
200
|
+
html: {
|
|
201
|
+
textRendering: "optimizeLegibility",
|
|
202
|
+
touchAction: "manipulation",
|
|
203
|
+
},
|
|
204
|
+
body: {
|
|
205
|
+
position: "relative",
|
|
206
|
+
minHeight: "100%",
|
|
207
|
+
fontFeatureSettings: '"kern"',
|
|
208
|
+
fontFamily: "body",
|
|
209
|
+
color: "gray.800",
|
|
210
|
+
bg: "white",
|
|
211
|
+
transitionProperty: "background-color",
|
|
212
|
+
transitionDuration: "normal",
|
|
213
|
+
lineHeight: "base",
|
|
214
|
+
},
|
|
215
|
+
"*::placeholder": {
|
|
216
|
+
color: "gray.500",
|
|
217
|
+
},
|
|
218
|
+
// The `* { border-color; word-wrap }` Chakra-reset parity lives in
|
|
219
|
+
// ../reset.css, imported into the `reset` layer by consumers'
|
|
220
|
+
// layers.css — NOT here: globalCss emits into the `base` layer, which
|
|
221
|
+
// the legacy-Safari cascade-layer flattening specificity-boosts above
|
|
222
|
+
// runtime-injected CSS (CodeMirror themes) and other app CSS files.
|
|
223
|
+
// Resets must stay at the bottom (playbook gotcha #28).
|
|
224
|
+
// Panda's preflight, unlike Chakra's reset, doesn't set the pointer
|
|
225
|
+
// cursor on buttons. Recipes' disabled states (cursor: not-allowed)
|
|
226
|
+
// override this from the higher recipes layer.
|
|
227
|
+
"button, [role='button']": {
|
|
228
|
+
cursor: "pointer",
|
|
229
|
+
},
|
|
230
|
+
// Panda's preflight balance-wraps headings; Chakra didn't, and balanced
|
|
231
|
+
// multi-line headings break at different points (mobile/translations).
|
|
232
|
+
"h1, h2, h3, h4, h5, h6": {
|
|
233
|
+
textWrap: "wrap",
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
// shared-ui components forward `variant`/`size`/etc. as runtime props to
|
|
237
|
+
// the recipe functions, so Panda's static analysis can't see which variants
|
|
238
|
+
// are used and would emit no CSS for them. Generate every recipe variant.
|
|
239
|
+
// Lives in the preset (not the consumer's panda.config.ts) so no consumer
|
|
240
|
+
// can silently lose runtime-prop variants.
|
|
241
|
+
staticCss: {
|
|
242
|
+
recipes: {
|
|
243
|
+
button: ["*"],
|
|
244
|
+
checkbox: ["*"],
|
|
245
|
+
heading: ["*"],
|
|
246
|
+
card: ["*"],
|
|
247
|
+
// Dialog size is chosen with responsive objects ({ base, md }) passed
|
|
248
|
+
// as a runtime prop, so generate the breakpoint-prefixed variants too.
|
|
249
|
+
dialog: [{ size: ["*"], responsive: true }, { centered: ["*"] }],
|
|
250
|
+
drawer: ["*"],
|
|
251
|
+
input: ["*"],
|
|
252
|
+
radio: ["*"],
|
|
253
|
+
switchRecipe: ["*"],
|
|
254
|
+
text: ["*"],
|
|
255
|
+
// Toast status is chosen at runtime from the toast content.
|
|
256
|
+
toast: ["*"],
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
utilities: {
|
|
260
|
+
extend: {
|
|
261
|
+
// The app-wide focus indicator, usually inside `_focusVisible`. Values
|
|
262
|
+
// are the outline* shadow token names. The transparent outline is for
|
|
263
|
+
// forced-colors modes, which strip box-shadows but recolour outlines to
|
|
264
|
+
// a visible system colour. (Named to avoid preset-base's outline-based
|
|
265
|
+
// `focusRing` utility, whose values would break this transform.)
|
|
266
|
+
focusShadow: {
|
|
267
|
+
className: "focus-shadow",
|
|
268
|
+
values: ["outline", "outlineDark", "outlineLight"],
|
|
269
|
+
transform: (value: string, { token }) => ({
|
|
270
|
+
outline: "2px solid transparent",
|
|
271
|
+
outlineOffset: "2px",
|
|
272
|
+
boxShadow: token(`shadows.${value}`),
|
|
273
|
+
}),
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
// Widen the interaction conditions so the Chakra-shaped recipe/style objects
|
|
278
|
+
// (`_hover`/`_active`/`_focusVisible`/`_disabled`) also respond to
|
|
279
|
+
// react-aria-components' data attributes, not just native pseudo-classes.
|
|
280
|
+
conditions: {
|
|
281
|
+
extend: {
|
|
282
|
+
hover: "&:is(:hover, [data-hovered])",
|
|
283
|
+
active: "&:is(:active, [data-pressed])",
|
|
284
|
+
focusVisible: "&:is(:focus-visible, [data-focus-visible])",
|
|
285
|
+
disabled:
|
|
286
|
+
"&:is(:disabled, [disabled], [data-disabled], [aria-disabled=true])",
|
|
287
|
+
// High-contrast/forced-palette modes (e.g. Windows High Contrast), which
|
|
288
|
+
// strip author backgrounds and box-shadows.
|
|
289
|
+
forcedColors: "@media (forced-colors: active)",
|
|
290
|
+
},
|
|
291
|
+
},
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
export default basePreset;
|