@microbit/ui 0.1.0-alpha.22 → 0.1.0-alpha.24

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 (97) hide show
  1. package/LICENSE.md +5 -5
  2. package/README.md +40 -13
  3. package/lang/ui.ca.json +12 -12
  4. package/lang/ui.cy.json +4 -4
  5. package/lang/ui.de.json +6 -6
  6. package/lang/ui.es-es.json +5 -5
  7. package/lang/ui.fr.json +6 -6
  8. package/lang/ui.ga-ie.json +6 -6
  9. package/lang/ui.it.json +4 -4
  10. package/lang/ui.ja.json +7 -7
  11. package/lang/ui.ko.json +6 -6
  12. package/lang/ui.lo.json +58 -0
  13. package/lang/ui.nl.json +9 -9
  14. package/lang/ui.pl.json +8 -8
  15. package/lang/ui.pt-br.json +7 -7
  16. package/lang/ui.vi.json +58 -0
  17. package/lang/ui.zh-cn.json +6 -6
  18. package/lang/ui.zh-tw.json +7 -7
  19. package/package.json +1 -1
  20. package/src/Avatar.recipe.ts +16 -20
  21. package/src/Avatar.tsx +31 -29
  22. package/src/Breadcrumb.recipe.ts +3 -7
  23. package/src/Breadcrumb.tsx +6 -8
  24. package/src/Button.recipe.ts +22 -33
  25. package/src/Button.tsx +10 -12
  26. package/src/ButtonGroup.tsx +10 -9
  27. package/src/Card.recipe.ts +1 -2
  28. package/src/Card.tsx +2 -1
  29. package/src/Checkbox.recipe.ts +7 -9
  30. package/src/Checkbox.tsx +2 -3
  31. package/src/CheckboxGroup.tsx +5 -7
  32. package/src/CloseButton.tsx +2 -2
  33. package/src/CloseIcon.tsx +6 -4
  34. package/src/Code.tsx +1 -1
  35. package/src/Collapse.tsx +13 -14
  36. package/src/Divider.tsx +3 -3
  37. package/src/Drawer.recipe.ts +4 -5
  38. package/src/Drawer.tsx +3 -4
  39. package/src/Fade.tsx +6 -10
  40. package/src/Field.recipe.ts +9 -12
  41. package/src/Field.tsx +16 -18
  42. package/src/GridList.recipe.ts +1 -2
  43. package/src/Heading.recipe.ts +5 -5
  44. package/src/Heading.tsx +3 -3
  45. package/src/Icon.tsx +7 -11
  46. package/src/IconButton.tsx +1 -1
  47. package/src/Image.tsx +1 -1
  48. package/src/Input.recipe.ts +5 -6
  49. package/src/Input.tsx +4 -4
  50. package/src/InputGroup.tsx +4 -5
  51. package/src/Kbd.tsx +1 -1
  52. package/src/Link.tsx +2 -2
  53. package/src/LinkBox.tsx +2 -3
  54. package/src/LinkButton.tsx +4 -4
  55. package/src/List.tsx +5 -7
  56. package/src/Menu.recipe.ts +15 -16
  57. package/src/Menu.tsx +9 -13
  58. package/src/Modal.recipe.ts +7 -8
  59. package/src/Modal.tsx +19 -24
  60. package/src/NativeSelect.tsx +16 -16
  61. package/src/NumberField.recipe.ts +8 -10
  62. package/src/NumberField.tsx +4 -4
  63. package/src/PopoverArrow.tsx +1 -2
  64. package/src/ProgressBar.tsx +2 -3
  65. package/src/Radio.recipe.ts +8 -9
  66. package/src/Radio.tsx +2 -2
  67. package/src/RadioGroup.tsx +4 -5
  68. package/src/Select.recipe.ts +9 -9
  69. package/src/Select.tsx +8 -9
  70. package/src/Skeleton.tsx +13 -15
  71. package/src/Slide.tsx +2 -2
  72. package/src/Slider.recipe.ts +11 -14
  73. package/src/Slider.tsx +3 -7
  74. package/src/Spinner.tsx +6 -9
  75. package/src/Svg.tsx +2 -3
  76. package/src/Switch.recipe.ts +4 -5
  77. package/src/Switch.tsx +3 -4
  78. package/src/Text.recipe.ts +4 -7
  79. package/src/Text.tsx +2 -2
  80. package/src/TextField.tsx +3 -4
  81. package/src/Toast.recipe.ts +43 -11
  82. package/src/Toast.tsx +29 -28
  83. package/src/Tooltip.recipe.ts +4 -9
  84. package/src/Tooltip.tsx +9 -11
  85. package/src/TooltipButton.tsx +1 -2
  86. package/src/UnmountCallback.tsx +2 -2
  87. package/src/VisuallyHidden.tsx +1 -1
  88. package/src/base-preset.ts +40 -44
  89. package/src/button-icon.ts +2 -3
  90. package/src/dense-preset.ts +6 -7
  91. package/src/hooks/useBreakpointValue.ts +4 -4
  92. package/src/hooks/useClipboard.ts +5 -6
  93. package/src/hooks/useDisclosure.ts +4 -5
  94. package/src/hooks/useMediaQuery.ts +3 -4
  95. package/src/hooks/usePrevious.ts +1 -4
  96. package/src/index.ts +3 -3
  97. package/src/system.ts +2 -2
package/src/Toast.tsx CHANGED
@@ -23,7 +23,6 @@ import { toast as toastRecipe } from "styled-system/recipes";
23
23
  import { CloseIcon } from "./CloseIcon";
24
24
  import { Icon } from "./Icon";
25
25
  import { uiMessage } from "./messages";
26
- import { VisuallyHidden } from "./VisuallyHidden";
27
26
 
28
27
  export type ToastStatus = "info" | "success" | "warning" | "error";
29
28
 
@@ -84,11 +83,11 @@ export const toastQueue = new RACToastQueue<ToastContent>({
84
83
  // call onClose, so closeAll empties both.
85
84
  const keysById = new Map<string, string>();
86
85
 
87
- // Status icon matching Chakra's AlertIcon (filled glyphs, coloured by the
88
- // toast foreground = white here). Warning is a triangle, error a circle, as
89
- // in Chakra the glyph must distinguish them because the colours alone
90
- // don't reliably. The icon is decorative; the status is announced via the
91
- // visually hidden status text.
86
+ // Status icon (filled glyphs, coloured by the toast foreground = white
87
+ // here). Warning is a triangle, error a circle — the glyph must distinguish
88
+ // them because the colours alone don't reliably. The glyph is also what
89
+ // carries the status for assistive tech, via its accessible name (see
90
+ // ToastProvider).
92
91
  const statusIcon: Record<ToastStatus, IconType> = {
93
92
  info: RiInformationFill,
94
93
  success: RiCheckboxCircleFill,
@@ -131,21 +130,24 @@ export const ToastProvider = () => {
131
130
  // group and lets old/new pair up across the transition.
132
131
  style={{ viewTransitionName: toast.key }}
133
132
  >
134
- <Icon as={statusIcon[status]} className={slots.icon} aria-hidden />
135
- <RACToastContent>
136
- {/* Colour and icon are the only visible status signals; say it
137
- for assistive tech too. */}
138
- <VisuallyHidden>
139
- {intl.formatMessage(uiMessage(`ui.toast-status-${status}`))}{" "}
140
- </VisuallyHidden>
141
- {toast.content.title && (
142
- <p className={slots.title}>{toast.content.title}</p>
143
- )}
144
- {toast.content.description && (
145
- <div className={slots.description}>
146
- {toast.content.description}
147
- </div>
148
- )}
133
+ <RACToastContent className={slots.content}>
134
+ <Icon
135
+ as={statusIcon[status]}
136
+ className={slots.icon}
137
+ aria-label={intl.formatMessage(
138
+ uiMessage(`ui.toast-status-${status}`),
139
+ )}
140
+ />
141
+ <div className={slots.body}>
142
+ {toast.content.title && (
143
+ <p className={slots.title}>{toast.content.title}</p>
144
+ )}
145
+ {toast.content.description && (
146
+ <div className={slots.description}>
147
+ {toast.content.description}
148
+ </div>
149
+ )}
150
+ </div>
149
151
  </RACToastContent>
150
152
  {toast.content.isClosable && (
151
153
  <RACButton
@@ -181,19 +183,18 @@ export interface ToastFn {
181
183
  */
182
184
  isActive(id: string): boolean;
183
185
  /**
184
- * Replace a queued toast's content (Chakra's toast.update). The toast is
185
- * re-added, so unlike Chakra it re-animates, restarts any timeout, and
186
- * takes its place at the front of the queue.
186
+ * Replace a queued toast's content. The toast is re-added: it re-animates,
187
+ * restarts any timeout, and takes its place at the front of the queue.
187
188
  */
188
189
  update(id: string, options: ToastOptions): void;
189
- /** Dismiss every toast, queued as well as displayed (Chakra's toast.closeAll). */
190
+ /** Dismiss every toast, queued as well as displayed. */
190
191
  closeAll(): void;
191
192
  }
192
193
 
193
194
  /**
194
- * useToast — imperative toast trigger in the shape of Chakra's `useToast()`
195
- * call sites: `toast({ title, description, status, duration })`. Unlike
196
- * Chakra there is no `duration: null`; use `persistent: true` instead.
195
+ * useToast — imperative toast trigger:
196
+ * `toast({ title, description, status, duration })`. There is no
197
+ * `duration: null`; use `persistent: true` instead.
197
198
  */
198
199
  export const useToast = (): ToastFn =>
199
200
  useMemo(() => {
@@ -6,17 +6,12 @@
6
6
  import { defineRecipe } from "@pandacss/dev";
7
7
 
8
8
  /**
9
- * Tooltip recipe — Chakra's dark tooltip.
9
+ * Tooltip recipe — the dark tooltip.
10
10
  *
11
11
  * A recipe rather than styles inside the component because tooltip typography
12
- * is the kind of thing an app sets once for all of them: classroom's Chakra
13
- * theme did exactly that (`fontSize: md`), and a `css` override at today's
14
- * call sites would quietly not apply to tomorrow's.
15
- *
16
- * The colour, vertical padding and radius are Chakra's exactly. They had
17
- * drifted (white, `py: 1`, `borderRadius: md`) while this lived inside the
18
- * component, which classroom's port measured: a 6px radius where Chakra drew
19
- * 2px. ml-trainer and python-editor pick the correction up too.
12
+ * is the kind of thing an app sets once for all of them (classroom does,
13
+ * `fontSize: md`), and a `css` override at today's call sites would quietly
14
+ * not apply to tomorrow's.
20
15
  *
21
16
  * Registered in the base preset (base-preset.ts).
22
17
  */
package/src/Tooltip.tsx CHANGED
@@ -12,9 +12,9 @@ import { PopoverArrow } from "./PopoverArrow";
12
12
 
13
13
  export interface TooltipProps {
14
14
  /**
15
- * Tooltip body (Chakra's `label`). Not named `content`: Panda extracts
16
- * utility-named props with literal values from any JSX component, so a
17
- * `content` prop taking a string would emit a broken CSS `content` rule.
15
+ * Tooltip body. Not named `content`: Panda extracts utility-named props
16
+ * with literal values from any JSX component, so a `content` prop taking a
17
+ * string would emit a broken CSS `content` rule.
18
18
  */
19
19
  label: ReactNode;
20
20
  /** A single focusable trigger element (e.g. a Button). */
@@ -60,10 +60,8 @@ export interface TooltipProps {
60
60
  *
61
61
  * This is what makes a tooltip hoverable, as WCAG 1.4.13 asks: react-aria
62
62
  * puts hover handlers on the tooltip that re-open it, but with an immediate
63
- * close it has unmounted before the pointer can cross the gap. Chakra closed
64
- * on mouse-out and we matched that at first; a tooltip that vanishes as you
65
- * reach for it is not worth the parity. Pass 0 where the delay is wrong for a
66
- * particular control.
63
+ * close it has unmounted before the pointer can cross the gap. Pass 0 where
64
+ * the delay is wrong for a particular control.
67
65
  */
68
66
  closeDelay?: number;
69
67
  /**
@@ -79,10 +77,10 @@ export interface TooltipProps {
79
77
  }
80
78
 
81
79
  /**
82
- * Tooltip — react-aria-components TooltipTrigger + Tooltip, styled to match
83
- * Chakra's dark tooltip. The child must be a focusable element so the tooltip
84
- * is reachable by keyboard (RAC requirement), unless `triggerRef` provides
85
- * the anchor and the caller manages open state and keyboard access itself.
80
+ * Tooltip — react-aria-components TooltipTrigger + Tooltip in the dark
81
+ * tooltip style. The child must be a focusable element so the tooltip is
82
+ * reachable by keyboard (RAC requirement), unless `triggerRef` provides the
83
+ * anchor and the caller manages open state and keyboard access itself.
86
84
  */
87
85
  export const Tooltip = ({
88
86
  label,
@@ -94,8 +94,7 @@ export interface TooltipButtonProps {
94
94
  * (`ContextualHelp`), not a tooltip, which would remove the hidden copy of the
95
95
  * body and the pointer-geometry keep-alive below rather than work around them.
96
96
  * Tracked as microbit-foundation/ui#63, which would deprecate this component;
97
- * see "Open across the completed migrations" in docs/migration-playbook.md
98
- * before extending it.
97
+ * prefer that direction over extending it.
99
98
  */
100
99
  export const TooltipButton = ({
101
100
  label,
@@ -7,8 +7,8 @@ import { useEffect, useRef } from "react";
7
7
 
8
8
  /**
9
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.
10
+ * the exit transition finishes, so mounting this inside the overlay
11
+ * implements Modal/Drawer's `onCloseComplete`. Internal to shared-ui.
12
12
  */
13
13
  export const UnmountCallback = ({ callback }: { callback?: () => void }) => {
14
14
  const ref = useRef(callback);
@@ -7,7 +7,7 @@ import { styled } from "styled-system/jsx";
7
7
 
8
8
  /**
9
9
  * VisuallyHidden — screen-reader-only content (Panda's `srOnly` utility).
10
- * Renders a span like Chakra's; use `as="div"` for block children.
10
+ * Renders a span; use `as="div"` for block children.
11
11
  */
12
12
  export const VisuallyHidden = styled("span", {
13
13
  base: { srOnly: true },
@@ -63,7 +63,7 @@ import { toast } from "./Toast.recipe";
63
63
  // Override values, never names: raw var(--colors-gray-*) references and
64
64
  // paired private presets depend on the names, so a rename is a breaking
65
65
  // change to both and needs every app and paired preset moved in lockstep
66
- // (as was done when Chakra's misnamed darker-than-50 stop `25` became
66
+ // (as was done when the misnamed darker-than-50 stop `25` became
67
67
  // `75`). And never override partially in a way that lets a stop fall
68
68
  // through to a different grey system.
69
69
  const gray = {
@@ -88,17 +88,17 @@ const gray = {
88
88
  * (pill `radii.button`, `outline*` focus shadows, Helvetica fonts, the
89
89
  * `language`/`toolbar` button variants in Button.recipe.ts, the
90
90
  * `languageText`/`toast*Bg`/`statusBarBg` semantic tokens), the shared-ui
91
- * component recipes, the react-aria condition widening, the Chakra-reset
92
- * parity `globalCss`, and the `staticCss` that keeps runtime-prop recipe
91
+ * component recipes, the react-aria condition widening, the `globalCss`
92
+ * defaults, and the `staticCss` that keeps runtime-prop recipe
93
93
  * variants generated. Used alone it renders in the OSS default look.
94
94
  *
95
95
  * ── Brand contract ──────────────────────────────────────────────────────
96
96
  * A private brand preset (a sibling repo, e.g. CreateAI) is merged AFTER this
97
97
  * one to restyle everything by overriding just these token *values* (never
98
98
  * their names — see the CSS-var contract in the README):
99
- * - colours: the `brand` and `brand2` ramps (OSS defaults: Chakra
100
- * blue / Chakra's unmodified gray). Other ramps a brand tweaks
101
- * (teal/purple/pink/…) already exist in the Chakra scales below.
99
+ * - colours: the `brand` and `brand2` ramps (OSS defaults: the blue
100
+ * ramp / a legacy slate gray). Other ramps a brand tweaks
101
+ * (teal/purple/pink/…) already exist in the base scales below.
102
102
  * - font: `display` (OSS default: Helvetica; e.g. GT Walsheim privately).
103
103
  * The recipes and semantic tokens here reference those, so a brand swap needs
104
104
  * no recipe changes. With no private preset, these OSS defaults stand.
@@ -126,8 +126,8 @@ export const basePreset = definePreset({
126
126
  },
127
127
  },
128
128
  // Toast enter/exit, played on the view-transition snapshots (see the
129
- // ::view-transition rules in globalCss). Chakra-ballpark timings: fade
130
- // + short slide in, quicker fade + shrink out.
129
+ // ::view-transition rules in globalCss): fade + short slide in,
130
+ // quicker fade + shrink out.
131
131
  toastSlideIn: {
132
132
  from: { opacity: 0, transform: "translateY(-24px)" },
133
133
  },
@@ -140,9 +140,10 @@ export const basePreset = definePreset({
140
140
  ...colors,
141
141
  gray,
142
142
  // OSS default brand ramps (see the brand contract above). `brand`
143
- // aliases Chakra blue; `brand2` stays Chakra's slate gray a frozen
144
- // legacy alias, deliberately decoupled from the neutral `gray` above
145
- // so ml-trainer's OSS look and `statusBarBg`'s default don't move.
143
+ // aliases the blue ramp; `brand2` is a frozen legacy alias of the
144
+ // slate gray in base-tokens, deliberately decoupled from the neutral
145
+ // `gray` above so ml-trainer's OSS look and `statusBarBg`'s default
146
+ // don't move.
146
147
  // Removing the slot is a follow-up needing an ml-trainer lockstep.
147
148
  brand: colors.blue,
148
149
  brand2: colors.gray,
@@ -165,7 +166,7 @@ export const basePreset = definePreset({
165
166
  },
166
167
  shadows: {
167
168
  ...shadows,
168
- // Chakra's outline shadow widened to 4px, plus dark/light-surface
169
+ // The 4px focus outline shadow, plus dark/light-surface
169
170
  // companions. Consumed via the `focusShadow` utility.
170
171
  outline: { value: "0 0 0 4px rgba(66, 153, 225, 0.6)" },
171
172
  outlineDark: { value: "0 0 0 4px rgba(0, 0, 0, 0.5)" },
@@ -174,7 +175,7 @@ export const basePreset = definePreset({
174
175
  fonts: {
175
176
  // Helvetica heading/body (4/4 apps); a brand preset leaves these and
176
177
  // overrides only `display` (the marketing font — see the brand
177
- // contract above). `mono` is Chakra's default stack.
178
+ // contract above).
178
179
  heading: { value: "Helvetica, Arial, sans-serif" },
179
180
  body: { value: "Helvetica, Arial, sans-serif" },
180
181
  mono: {
@@ -195,7 +196,7 @@ export const basePreset = definePreset({
195
196
  controlCheckedBg: { value: "{colors.brand.500}" },
196
197
  controlCheckedHoverBg: { value: "{colors.brand.600}" },
197
198
  focusBorder: { value: "{colors.brand.500}" },
198
- // Error/destructive ramp (Chakra red). Destructive button variants,
199
+ // Error/destructive ramp. Destructive button variants,
199
200
  // field error states and the error toast; the record* button
200
201
  // variants deliberately stay on red.* (recording vocabulary, not
201
202
  // danger).
@@ -211,9 +212,6 @@ export const basePreset = definePreset({
211
212
  // (CreateAI privately to brand.600 with no hover change,
212
213
  // python-editor to brand.500/600 — the default). Semantic tokens so
213
214
  // the recipe stays shared and a brand preset overrides only values.
214
- // (Was brand2.* — the grey ml-trainer OSS Chakra look — but both
215
- // apps' final values sit on their primary brand, so the default
216
- // follows; OSS language buttons are brand blue.)
217
215
  languageText: { value: "{colors.brand.500}" },
218
216
  languageTextHover: { value: "{colors.brand.600}" },
219
217
  // The `label`/`subtitle` heading variants' colour (page-title chrome).
@@ -243,8 +241,8 @@ export const basePreset = definePreset({
243
241
  secondaryActiveBorder: { value: "{colors.brand.700}" },
244
242
  secondaryActiveBg: { value: "{colors.brand.50}" },
245
243
  },
246
- // Toast status colours: the Chakra-era toast Alert restyle (teal for
247
- // every status except error) shared across the app family.
244
+ // Toast status colours (teal for every status except error), shared
245
+ // across the app family.
248
246
  toastInfoBg: { value: "{colors.teal.800}" },
249
247
  toastSuccessBg: { value: "{colors.teal.800}" },
250
248
  toastWarningBg: { value: "{colors.teal.800}" },
@@ -280,20 +278,18 @@ export const basePreset = definePreset({
280
278
  toast,
281
279
  },
282
280
  },
283
- // What ChakraProvider used to inject and Panda's preflight doesn't cover:
284
- // the theme's styles.global (body text/background defaults, global
285
- // border/placeholder colours) plus the parts of Chakra's CSS reset that
286
- // Panda's has no equivalent for kerning/text-rendering (their absence
287
- // shifts glyphs page-wide), word-wrap and touch-action. Token references
288
- // resolve against the merged preset stack, so the values track any brand
289
- // overrides exactly as they did under Chakra's runtime theme.
281
+ // Global defaults Panda's preflight doesn't cover: body text/background,
282
+ // placeholder colour, kerning/text-rendering (their absence shifts
283
+ // glyphs page-wide) and touch-action. Token references resolve against
284
+ // the merged preset stack, so the values track any brand overrides.
290
285
  globalCss: {
291
286
  html: {
292
287
  textRendering: "optimizeLegibility",
293
288
  touchAction: "manipulation",
294
289
  },
295
290
  body: {
296
- position: "relative",
291
+ // No `position: relative` (Chakra had it): it breaks react-aria's
292
+ // overlay positioning — see Tooltip's "In a scrolling page" story.
297
293
  minHeight: "100%",
298
294
  fontFeatureSettings: '"kern"',
299
295
  fontFamily: "body",
@@ -306,20 +302,20 @@ export const basePreset = definePreset({
306
302
  "*::placeholder": {
307
303
  color: "gray.500",
308
304
  },
309
- // The `* { border-color; word-wrap }` Chakra-reset parity lives in
310
- // ../reset.css, imported into the `reset` layer by consumers'
311
- // layers.css — NOT here: globalCss emits into the `base` layer, which
312
- // the legacy-Safari cascade-layer flattening specificity-boosts above
313
- // runtime-injected CSS (CodeMirror themes) and other app CSS files.
314
- // Resets must stay at the bottom (playbook gotcha #28).
315
- // Panda's preflight, unlike Chakra's reset, doesn't set the pointer
316
- // cursor on buttons. Recipes' disabled states (cursor: not-allowed)
317
- // override this from the higher recipes layer.
305
+ // The `* { border-color; word-wrap }` defaults live in ../reset.css,
306
+ // imported into the `reset` layer by consumers' layers.css — NOT here:
307
+ // globalCss emits into the `base` layer, which the legacy-Safari
308
+ // cascade-layer flattening specificity-boosts above runtime-injected
309
+ // CSS (CodeMirror themes) and other app CSS files. Resets must stay in
310
+ // the bottom layer.
311
+ // Panda's preflight doesn't set the pointer cursor on buttons.
312
+ // Recipes' disabled states (cursor: not-allowed) override this from
313
+ // the higher recipes layer.
318
314
  "button, [role='button']": {
319
315
  cursor: "pointer",
320
316
  },
321
- // Panda's preflight balance-wraps headings; Chakra didn't, and balanced
322
- // multi-line headings break at different points (mobile/translations).
317
+ // Panda's preflight balance-wraps headings; balanced multi-line
318
+ // headings break at different points (mobile/translations), so undo it.
323
319
  "h1, h2, h3, h4, h5, h6": {
324
320
  textWrap: "wrap",
325
321
  },
@@ -336,8 +332,8 @@ export const basePreset = definePreset({
336
332
  },
337
333
  // Toast enter/exit (the ToastQueue wraps updates in
338
334
  // document.startViewTransition — see Toast.tsx, which also stamps the
339
- // scoping class on <html> while its transitions run). Timings sit in
340
- // Chakra's ballpark: 0.4s fade+slide in, 0.2s fade+shrink out; the
335
+ // scoping class on <html> while its transitions run). Timings: 0.4s
336
+ // fade+slide in, 0.2s fade+shrink out; the
341
337
  // stack reflow comes from the default group animation. `(*)` +
342
338
  // `:only-child` matches exactly the entering/exiting toast groups: the
343
339
  // root snapshot always has both old and new children, and toasts are
@@ -365,8 +361,8 @@ export const basePreset = definePreset({
365
361
  // can silently lose runtime-prop variants.
366
362
  staticCss: {
367
363
  recipes: {
368
- // Size is passed responsively at call sites ported from Chakra's
369
- // `size={["md", "lg"]}`, so generate the breakpoint-prefixed variants
364
+ // Size is passed responsively at call sites
365
+ // (`size={["md", "lg"]}`), so generate the breakpoint-prefixed variants
370
366
  // too — otherwise the class lands on the element with no rule behind it
371
367
  // and the button silently falls back to the base size.
372
368
  avatar: ["*"],
@@ -410,8 +406,8 @@ export const basePreset = definePreset({
410
406
  },
411
407
  },
412
408
  },
413
- // Widen the interaction conditions so the Chakra-shaped recipe/style objects
414
- // (`_hover`/`_active`/`_focusVisible`/`_disabled`) also respond to
409
+ // Widen the interaction conditions so recipe/style objects written with
410
+ // `_hover`/`_active`/`_focusVisible`/`_disabled` also respond to
415
411
  // react-aria-components' data attributes, not just native pseudo-classes.
416
412
  conditions: {
417
413
  extend: {
@@ -5,9 +5,8 @@
5
5
  */
6
6
  import { cva } from "styled-system/css";
7
7
 
8
- // Chakra's ButtonIcon: keeps the glyph centred and spaced from the label
9
- // (iconSpacing 0.5rem). Shared by Button and LinkButton; deliberately not
10
- // exported from the package index.
8
+ // Keeps the glyph centred and spaced 0.5rem from the label. Shared by Button
9
+ // and LinkButton; deliberately not exported from the package index.
11
10
  export const buttonIcon = cva({
12
11
  base: {
13
12
  display: "inline-flex",
@@ -11,11 +11,10 @@ const toTokens = (values: Record<string, string>) =>
11
11
  ) as Record<string, { value: string }>;
12
12
 
13
13
  /**
14
- * The numeric spacing/size grid, Chakra's 0.25rem step × 0.88.
14
+ * The numeric spacing/size grid, the base 0.25rem step × 0.88.
15
15
  *
16
16
  * Only the numeric scale is touched: the named `sizes` (`xs`…`8xl`, `max`,
17
- * `full`, `container.*`) stay at their base-preset values, as they did in
18
- * both apps' Chakra themes.
17
+ * `full`, `container.*`) stay at their base-preset values.
19
18
  */
20
19
  const scale = toTokens({
21
20
  px: "1px",
@@ -81,11 +80,11 @@ const denseFontSizes = toTokens({
81
80
  * ```
82
81
  *
83
82
  * Both python-editor and classroom shipped the same "make everything
84
- * smaller" Chakra theme change (2022): the numeric spacing/sizes grid at
85
- * × 0.88 and `fontSizes` from `md` up at × 0.9. The two themes' values were
83
+ * smaller" theme change (2022): the numeric spacing/sizes grid at
84
+ * × 0.88 and `fontSizes` from `md` up at × 0.9. The two apps' values were
86
85
  * byte-identical, so the scale lives here rather than being replicated in
87
- * each app preset (migration-playbook gotcha #25 — a global scale override
88
- * hides from every safeguard, so it needs to be explicit and shared).
86
+ * each app preset — a global scale override hides from every safeguard,
87
+ * so it needs to be explicit and shared.
89
88
  *
90
89
  * Whether this density stays or the family aligns on one scale is an open
91
90
  * design question; when it is answered, this preset is the single place the
@@ -31,10 +31,10 @@ const activeBreakpoint = (): Breakpoint => {
31
31
  };
32
32
 
33
33
  /**
34
- * JS-side responsive value resolver, replacing Chakra's `useBreakpointValue`.
35
- * Panda handles responsive *styles* in CSS; this is for responsive *logic*
36
- * (choosing a prop value, branching behaviour). Resolves to the value at the
37
- * active breakpoint, falling back to the nearest smaller one that is defined.
34
+ * JS-side responsive value resolver. Panda handles responsive *styles* in
35
+ * CSS; this is for responsive *logic* (choosing a prop value, branching
36
+ * behaviour). Resolves to the value at the active breakpoint, falling back to
37
+ * the nearest smaller one that is defined.
38
38
  */
39
39
  export function useBreakpointValue<T>(
40
40
  values: Partial<Record<Breakpoint, T>>,
@@ -7,7 +7,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
7
7
 
8
8
  /**
9
9
  * Copy a value to the clipboard with a transient `hasCopied` flag for
10
- * "Copied!" feedback. Replaces Chakra's `useClipboard`.
10
+ * "Copied!" feedback.
11
11
  */
12
12
  export function useClipboard(
13
13
  value: string,
@@ -34,11 +34,10 @@ export function useClipboard(
34
34
  }
35
35
 
36
36
  /**
37
- * Chakra's useClipboard wrapped the execCommand-based copy-to-clipboard
38
- * package, which works on a user gesture in contexts the async API refuses:
39
- * insecure (non-localhost http) origins, where `navigator.clipboard` is
40
- * undefined, and frames without a clipboard-write permissions policy, where
41
- * `writeText` rejects.
37
+ * execCommand-based fallback copy. Works on a user gesture in contexts the
38
+ * async API refuses: insecure (non-localhost http) origins, where
39
+ * `navigator.clipboard` is undefined, and frames without a clipboard-write
40
+ * permissions policy, where `writeText` rejects.
42
41
  */
43
42
  function execCommandCopy(value: string): boolean {
44
43
  const active = document.activeElement;
@@ -13,12 +13,11 @@ export interface Disclosure {
13
13
  }
14
14
 
15
15
  /**
16
- * useDisclosure — Chakra's hook of the same name: the open/closed state of a
17
- * dialog, menu or drawer, and the three functions that change it.
16
+ * useDisclosure — the open/closed state of a dialog, menu or drawer, and the
17
+ * three functions that change it.
18
18
  *
19
- * A thin `useState` wrapper, kept because it is the shape a Chakra app's
20
- * dialog call sites are written in, and because a stable object means a
21
- * disclosure can be passed to a memoised child without re-rendering it.
19
+ * A thin `useState` wrapper; the stable object means a disclosure can be
20
+ * passed to a memoised child without re-rendering it.
22
21
  */
23
22
  export const useDisclosure = (defaultIsOpen = false): Disclosure => {
24
23
  const [isOpen, setIsOpen] = useState(defaultIsOpen);
@@ -6,10 +6,9 @@
6
6
  import { useCallback, useSyncExternalStore } from "react";
7
7
 
8
8
  /**
9
- * Tracks a raw CSS media query, replacing Chakra's `useMediaQuery` for
10
- * queries that aren't breakpoint-based (custom widths, height-based
11
- * queries). For the preset's breakpoint scale prefer `useBreakpointValue`.
12
- * Returns false during SSR.
9
+ * Tracks a raw CSS media query, for queries that aren't breakpoint-based
10
+ * (custom widths, height-based queries). For the preset's breakpoint scale
11
+ * prefer `useBreakpointValue`. Returns false during SSR.
13
12
  */
14
13
  export function useMediaQuery(query: string): boolean {
15
14
  const subscribe = useCallback(
@@ -5,10 +5,7 @@
5
5
  */
6
6
  import { useEffect, useRef } from "react";
7
7
 
8
- /**
9
- * The value from the previous render (undefined on the first render).
10
- * Replaces Chakra's `usePrevious`.
11
- */
8
+ /** The value from the previous render (undefined on the first render). */
12
9
  export function usePrevious<T>(value: T): T | undefined {
13
10
  const ref = useRef<T>();
14
11
  useEffect(() => {
package/src/index.ts CHANGED
@@ -4,9 +4,9 @@
4
4
  * SPDX-License-Identifier: MIT
5
5
  */
6
6
  /**
7
- * shared-ui — react-aria-components + Panda CSS primitives replacing Chakra,
8
- * designed to be extracted into a library shared across sibling apps. Visuals
9
- * match the Chakra theme; behaviour follows react-aria patterns.
7
+ * shared-ui — react-aria-components + Panda CSS primitives shared across the
8
+ * micro:bit app family. Behaviour follows react-aria patterns; styling comes
9
+ * from the recipe/token system in the base preset.
10
10
  */
11
11
  export * from "./system";
12
12
  export * from "./Avatar";
package/src/system.ts CHANGED
@@ -22,13 +22,13 @@ export type {
22
22
  GridProps,
23
23
  } from "styled-system/jsx";
24
24
 
25
- // Layout patterns — the Panda-native equivalents of Chakra's Box/Flex/Stack/etc.
25
+ // Layout patterns — Box/Flex/Stack/etc.
26
26
  //
27
27
  // `styled` is re-exported for the `styled(Component)` form, which works from
28
28
  // anywhere. The `styled.tag` JSX form does NOT: Panda recognises the factory by
29
29
  // the module it was imported from, so `<styled.table css={…}>` on a `styled`
30
30
  // imported from here silently produces no CSS. Import it from
31
- // "styled-system/jsx" for that (playbook gotcha #41).
31
+ // "styled-system/jsx" for that.
32
32
  export {
33
33
  AspectRatio,
34
34
  Box,