From e5fe0ae2d4a346f5dca00e31d8da74224532fcd5 Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Fri, 24 Jul 2026 17:48:35 +0100 Subject: [PATCH 001/104] Add RAC migration status doc Census (July 2026, moved from ml-trainer's RAC-MIGRATION.md), the semantic-token pre-work plan (startable while still on Chakra), and the app-specific migration items. Method lives in the @microbit/ui repo's docs/migration-playbook.md. --- RAC-MIGRATION.md | 132 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 RAC-MIGRATION.md diff --git a/RAC-MIGRATION.md b/RAC-MIGRATION.md new file mode 100644 index 000000000..7cd6e8335 --- /dev/null +++ b/RAC-MIGRATION.md @@ -0,0 +1,132 @@ +# Chakra → react-aria-components + Panda CSS migration + +Status: **not started — census done (July 2026); semantic-token pre-work +can begin now, while still on Chakra.** + +Method: follow the **migration playbook** in the `@microbit/ui` monorepo +(`../ui/docs/migration-playbook.md`) — the sequence, the gotcha catalog +(read it before porting anything), the kit scripts in `../ui/bin/`, and the +consumption setup in `../ui/packages/ui/README.md`. ml-trainer is the +completed reference migration (its frozen `RAC-MIGRATION.md` is the +archive). This doc is this app's status log and app-specific plan; keep it +current as the per-session handover. + +## Goal + +Replace Chakra UI with react-aria-components (behaviour/accessibility) and +Panda CSS (styling) by consuming `@microbit/ui`. The visual result must +closely match the current Chakra UI. Compare against the live branded +deployment (https://python.microbit.org/) — the OSS default theme is a +washed-out grey and hides real issues. The OSS-vs-private brand split +(`../python-editor-v3-microbit`) must be preserved, with the private +package changing in lockstep. + +## Pre-work (shippable independently, before any Panda) + +The census found the OSS/private split is **not token-clean** (unlike +ml-trainer's): the private theme structurally extends component configs. +Converge these onto shared structure driven by semantic tokens while still +on Chakra, so brand divergence becomes token values before the migration +proper. Changing the OSS theme is acceptable where it simplifies — agreed +in principle; scope per component. Run the resolved-theme differ +(`node ../ui/bin/diff-chakra-themes.mjs`, from this repo) first and rerun +it after every theme change while Chakra remains. + +Known structural extensions to converge: + +- Button: private adds `outline` (colorScheme-conditional colours), + `unstyled`, `language` variants and a `baseStyle` radius. Define the + variants once OSS-side with `languageText*`-style semantic tokens (the + base preset already has `languageText`/`languageTextHover`). +- Alert `toast` variant recoloured per status privately (`blimpTeal.700` + success/info, `code.error` otherwise) — fold into the library's + `toast*Bg` status tokens. +- Container `sidebar-header` bg (OSS black → private `brand.500`) and the + sidebar Tabs variant's background (OSS black → private brand + **linear-gradient**): `sidebarHeaderBg`-type semantic tokens — a + semantic token can hold the gradient privately, flat black OSS. +- Private-only Tooltip config. +- Private theme also carries a full custom `gray` ramp (not just the + family 10/25 additions) and extra ramps (`purple`, `teal`, `blimpTeal`). +- Private adds `withDefaultColorScheme("brand")`, and the OSS default + button variant is `withDefaultVariant(outline)` (ml-trainer: secondary) — + the library recipe's `defaultVariants` must be overridden in this app's + preset at migration time. + +## Census (July 2026) + +Taken while planning the family migration; original context in +ml-trainer's archived doc. Same bones as ml-trainer: Chakra v2.10, +react-intl, react-icons, Playwright, and the identical +`deployment/default` + `theme-package` vite-alias split with a +`DeploymentConfig.chakraTheme` field — so the kill-switch shape (theme +moves build-time, `chakraTheme` dropped from the config) transfers +directly. ~157 tsx files, 127 Chakra import statements. + +**Brand contract validated, with striking convergences**: OSS default is +`brand = gray` plus the same `gray.10`/`gray.25` additions (`#fcfcfc`/ +`#f5f6f8`), `radii.button: 2rem`, Helvetica heading/body fonts, and a +`language` button variant that exists _only_ in the private theme — the +`languageText` semantic-token precedent applies verbatim. + +**Generalisation categories ml-trainer didn't surface**: + +- **Tokens consumed outside React as raw CSS vars**: CodeMirror's + highlightStyle/themeExtensions hardcode `var(--chakra-colors-code-*)`, + `var(--chakra-fonts-code)`; XTerm/Simulator/CodeMirrorView use + `useToken` at runtime. Migrate onto the library's documented + CSS-variable contract + runtime `token()` (see the package README). +- **App token namespaces**: `code.*` (syntax colours + `code.error`) + lives in both OSS and private themes — a legitimate app-preset token + category, part of this app's preset contract. +- **Toast**: uses per-call `position`; every call site is "top" except + XTerm's multi-line-paste info toast at "bottom-right" + (`src/serial/XTerm.tsx` — also untranslated), plausibly deliberate + (near the terminal, where attention is). Decide during migration: + shared Toast grows region placement, or the call site changes. The + custom Alert `variant: "toast"` is covered by the library's Toast slot + recipe + status tokens. +- Imperative promise-based dialog layer (`use-dialogs`' `Dialogs` class + + ProgressDialog) renders controlled Modals with no trigger — fine on the + library Modal (controlled `isOpen` is first-class). +- `zIndex.ts` numeric constants calibrated against third-party stacking + (xterm layers, Chakra's 1500 overlay scale) — move to a z-index token + scale. +- **29 files import `BoxProps`** and forward style props through plain + wrappers — gotcha #9's biggest hazard class in the family; budget an + explicit `css`-prop conversion sweep. + +**Surface demand (census counts)**: overwhelmingly within the library's +existing surface (Text/Box/stacks/Button/IconButton/Modal family/Menu/ +Tooltip/Link/Icon/Image/Input/Divider/List/Spinner/Progress/ +VisuallyHidden). Real gaps this app needs, by usage: **Collapse + Fade** +(~14 files, docs sidebar; their Slide is the same framer-motion component +already ported); **Tabs** (one site but it's the app chrome, heavily +brand-divergent); Menu checkable items + divider (`MenuOptionGroup`/ +`MenuItemOption`, `MenuDivider`); AlertDialog semantics for ConfirmDialog; +Table family (×3), NumberInput, Kbd, Code, Tag, Portal-as-primitive (×7), +FormControl+FormErrorMessage error slot, InputLeft/RightElement; hooks +`useMediaQuery` (raw queries incl. height-based), `usePrevious`, +`useClipboard`, `useToken`, `usePrefersReducedMotion`. These are library +work (playbook roadmap: core components go in the library, not app-side). +**Not needed**: Drawer, Card, Accordion, Popover-as-API, colour mode, +Chakra Heading (they compose Text). + +## App-specific migration items (beyond the playbook sequence) + +- Tabs adoption: library recipe + this app's branded sidebar variant as + preset-side styling. +- CodeMirror + xterm + simulator styling onto the CSS-var contract; + xterm's stylesheet into the `vendor` cascade layer. +- The 29-file BoxProps/style-prop-forwarding sweep (gotcha #9). +- z-index token scale replacing `zIndex.ts` constants. +- The paste-toast placement decision (above). +- Fidelity harness: Playwright is already in place; mask CodeMirror, + xterm, and the simulator iframe. Run both sides (branded + OSS) at the + kill-switch — the split here makes the dual run more important than it + was for ml-trainer. + +## Status log + +- July 2026: census taken; playbook + kit extracted to `../ui`; this doc + seeded. Nothing migrated yet. From 8838d58c5a3e935c19bef8f0426b4373de59a6de Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Fri, 24 Jul 2026 17:53:04 +0100 Subject: [PATCH 002/104] Add AI agent notes pointing at the migration doc Plus two status-log caveats: the revived kit scripts are unexercised (first differ run doubles as validation), and the private theme package pulled changes postdating the census. --- AGENTS.md | 17 +++++++++++++++++ RAC-MIGRATION.md | 8 +++++++- 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..1ffecf4f9 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,17 @@ +# AI agent notes + +## RAC/Panda migration + +This app is migrating from Chakra UI to react-aria-components + Panda CSS +via `@microbit/ui`. **Read `RAC-MIGRATION.md` at the repo root before any +styling/theming/UI work** — it is the status log and app-specific plan; the +method and gotcha catalog are in `../ui/docs/migration-playbook.md`. The +private theme package is the sibling repo `../python-editor-v3-microbit`. + +## Commands + +- Unit tests: `npm test` (vitest). E2e: run headlessly via + `npm run test:e2e:headless`. +- `npm run typecheck`, `npm run lint`. +- Format with Prettier: `npx prettier --write` (no npm script). +- New source files need the licensing header — `npm run fix-licensing-headers` applies it. diff --git a/RAC-MIGRATION.md b/RAC-MIGRATION.md index 7cd6e8335..2d9bf5734 100644 --- a/RAC-MIGRATION.md +++ b/RAC-MIGRATION.md @@ -129,4 +129,10 @@ Chakra Heading (they compose Text). ## Status log - July 2026: census taken; playbook + kit extracted to `../ui`; this doc - seeded. Nothing migrated yet. + seeded. Nothing migrated yet. Two caveats for whoever starts: + - The kit scripts were revived from ml-trainer's git history and + generalised but have not been exercised since — the first + `diff-chakra-themes.mjs` run here doubles as their validation. + - `../python-editor-v3-microbit` pulled upstream changes on 2026-07-24 + that postdate the census — spot-check the census's private-theme + claims against the current theme before acting on them. From 976849ccfff3e411f651c0024cc2a917bbff3be1 Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Mon, 27 Jul 2026 09:47:46 +0000 Subject: [PATCH 003/104] Converge OSS theme onto shared structure + semantic tokens Semantic-token pre-work for the RAC/Panda migration (lockstep with the private theme package). The OSS theme now carries the same component structure as the private theme, with brand divergence expressed through a new semanticTokens block rather than forked component configs: - Button: adopt 2rem radius, add baseStyle + unstyled/outline/language variants (language via languageText* tokens) - Alert: toast variant sets per-status bg via toast*Bg tokens - Container/Tabs: sidebar chrome via sidebar* tokens (incl. gradient) - Tooltip: new OSS config (fontSize md), registered in the theme The resolved-theme differ now shows zero structural divergence between the OSS and private themes. See RAC-MIGRATION.md. --- src/deployment/default/components/alert.ts | 25 ++++++++++++++-- src/deployment/default/components/button.ts | 25 ++++++++++++++++ .../default/components/container.ts | 2 +- src/deployment/default/components/tabs.ts | 6 ++-- src/deployment/default/components/tooltip.ts | 14 +++++++++ src/deployment/default/radii.ts | 12 ++------ src/deployment/default/theme.ts | 30 +++++++++++++++++++ 7 files changed, 98 insertions(+), 16 deletions(-) create mode 100644 src/deployment/default/components/tooltip.ts diff --git a/src/deployment/default/components/alert.ts b/src/deployment/default/components/alert.ts index 75aef7808..ac21b21e3 100644 --- a/src/deployment/default/components/alert.ts +++ b/src/deployment/default/components/alert.ts @@ -4,14 +4,33 @@ * SPDX-License-Identifier: MIT */ import { StyleFunctionProps, theme } from "@chakra-ui/react"; +import { StyleConfig } from "@chakra-ui/theme-tools"; -const Alert = { +// Per-status background for the "toast" variant, driven by semantic tokens so +// the brand recolour lives in token values, not forked structure (see +// RAC-MIGRATION.md). Falls back to the error token for unknown statuses. +const toastBgByStatus: Record = { + success: "toastSuccessBg", + info: "toastInfoBg", + warning: "toastWarningBg", + error: "toastErrorBg", + loading: "toastInfoBg", +}; + +const Alert: StyleConfig = { variants: { toast: (props: StyleFunctionProps) => { const base = { - ...theme.components.Alert.variants!["solid"](props), + // Issue with _dark leads to any here. + ...(theme.components.Alert.variants!.solid(props) as any), + }; + return { + ...base, + container: { + ...base.container, + bg: toastBgByStatus[props.status] ?? "toastErrorBg", + }, }; - return base; }, }, }; diff --git a/src/deployment/default/components/button.ts b/src/deployment/default/components/button.ts index 2cfc96d3f..b113d579c 100644 --- a/src/deployment/default/components/button.ts +++ b/src/deployment/default/components/button.ts @@ -6,7 +6,13 @@ import { StyleFunctionProps, theme } from "@chakra-ui/react"; const Button = { + baseStyle: { + borderRadius: "button", + }, variants: { + unstyled: { + borderRadius: "unset", + }, // Ideally we'd drop this variant. zoom: (props: StyleFunctionProps) => { const base = theme.components.Button.variants!.solid(props); @@ -22,6 +28,14 @@ const Button = { }, }; }, + outline: ({ colorScheme }: StyleFunctionProps) => ({ + borderWidth: "2px", + color: `${colorScheme}.${colorScheme === "brand" ? "500" : "600"}`, + _hover: { + color: `${colorScheme}.${colorScheme === "brand" ? "600" : "700"}`, + bg: "transparent", + }, + }), sidebar: (props: StyleFunctionProps) => { const base = { ...theme.components.Button.variants!.ghost(props), @@ -40,6 +54,17 @@ const Button = { }, }; }, + // Text driven by the languageText* semantic tokens; borders/hover follow + // the gray ramp. Brand divergence lives in those token values. + language: () => ({ + borderWidth: "2px", + borderColor: "gray.200", + color: "languageText", + _hover: { + color: "languageTextHover", + bg: "gray.100", + }, + }), }, }; diff --git a/src/deployment/default/components/container.ts b/src/deployment/default/components/container.ts index 77b9d9cb5..823ac5b78 100644 --- a/src/deployment/default/components/container.ts +++ b/src/deployment/default/components/container.ts @@ -6,7 +6,7 @@ const Container = { variants: { "sidebar-header": { - bg: "black", + bg: "sidebarHeaderBg", p: 0, maxW: "unset", }, diff --git a/src/deployment/default/components/tabs.ts b/src/deployment/default/components/tabs.ts index 0dd9f5540..324c53eb9 100644 --- a/src/deployment/default/components/tabs.ts +++ b/src/deployment/default/components/tabs.ts @@ -12,7 +12,7 @@ const Tabs = { return { ...base, tablist: { - background: "black", + background: "sidebarTablistBg", }, tab: { ...base.tab, @@ -20,8 +20,8 @@ const Tabs = { ml: "6px", borderRadius: "32px 0 0 32px", _selected: { - color: "black", - bg: "gray.50", + color: "sidebarTabSelectedText", + bg: "sidebarTabSelectedBg", outline: "none", }, _focus: { diff --git a/src/deployment/default/components/tooltip.ts b/src/deployment/default/components/tooltip.ts new file mode 100644 index 000000000..997256866 --- /dev/null +++ b/src/deployment/default/components/tooltip.ts @@ -0,0 +1,14 @@ +/** + * (c) 2026, Micro:bit Educational Foundation and contributors + * + * SPDX-License-Identifier: MIT + */ +const Tooltip = { + baseStyle: { + // Converged with the private theme during the RAC/Panda semantic-token + // pre-work; the previous OSS default (Chakra's "sm") was an oversight. + fontSize: "md", + }, +}; + +export default Tooltip; diff --git a/src/deployment/default/radii.ts b/src/deployment/default/radii.ts index 7b03db6aa..6faeb6d3f 100644 --- a/src/deployment/default/radii.ts +++ b/src/deployment/default/radii.ts @@ -1,18 +1,12 @@ -/** - * (c) 2021, Micro:bit Educational Foundation and contributors - * - * SPDX-License-Identifier: MIT - */ -import { theme } from "@chakra-ui/theme"; - /** * (c) 2021, Micro:bit Educational Foundation and contributors * * SPDX-License-Identifier: MIT */ const radii = { - // Used where we need to match rounding to button radius. - button: theme.radii.md, + // Design radius for buttons and other larger items. Converged with the + // private theme (2rem) during the RAC/Panda semantic-token pre-work. + button: "2rem", }; export default radii; diff --git a/src/deployment/default/theme.ts b/src/deployment/default/theme.ts index 582259446..413e20cc0 100644 --- a/src/deployment/default/theme.ts +++ b/src/deployment/default/theme.ts @@ -11,6 +11,7 @@ import Button from "./components/button"; import Container from "./components/container"; import Tabs from "./components/tabs"; import Text from "./components/text"; +import Tooltip from "./components/tooltip"; import fontSizes from "./font-sizes"; import fonts from "./fonts"; import radii from "./radii"; @@ -18,6 +19,33 @@ import sizes from "./sizes"; import space from "./space"; // See https://chakra-ui.com/docs/theming/customize-theme +// +// Semantic tokens carry the OSS/private brand divergence during the +// RAC/Panda semantic-token pre-work: component configs stay structurally +// identical across the two themes and reference these tokens, so brand +// divergence lives in token values rather than in forked component structure +// (see RAC-MIGRATION.md). The private theme overrides the same token names. +const semanticTokens = { + colors: { + // App chrome (sidebar). OSS flat black; private uses brand colours / + // a gradient (see the private theme). A semantic token can hold a + // gradient string. + sidebarHeaderBg: "black", + sidebarTablistBg: "black", + sidebarTabSelectedText: "black", + sidebarTabSelectedBg: "gray.50", + // Button "language" variant text (base preset precedent: languageText*). + languageText: "brand.500", + languageTextHover: "brand.600", + // Alert "toast" variant per-status background. OSS reproduces Chakra's + // default solid status colours; private recolours to brand. + toastSuccessBg: "green.500", + toastInfoBg: "blue.500", + toastWarningBg: "orange.500", + toastErrorBg: "red.500", + }, +}; + const overrides = { fonts, fontSizes, @@ -25,12 +53,14 @@ const overrides = { space, radii, colors, + semanticTokens, components: { Alert, Button, Container, Tabs, Text, + Tooltip, }, }; From 942828375e3fcf38385da4c89d0444acd2f4db4f Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Mon, 27 Jul 2026 09:47:53 +0000 Subject: [PATCH 004/104] Update RAC migration doc: pre-work done, findings, verification Status-log the semantic-token pre-work: differ run + kit fix, census cross-check, divergence classification, the executed 7-step convergence, and toCSSVar verification of the semantic-token CSS-var emission. Adds parked notes: the brand/brand2-vs-purple/teal colour-scheme finding (teal does not map to brand2), brand-ramp data nits, and the languageText base-preset default question for the shared-ui repo. --- RAC-MIGRATION.md | 266 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 259 insertions(+), 7 deletions(-) diff --git a/RAC-MIGRATION.md b/RAC-MIGRATION.md index 2d9bf5734..92927b2c4 100644 --- a/RAC-MIGRATION.md +++ b/RAC-MIGRATION.md @@ -1,7 +1,12 @@ # Chakra → react-aria-components + Panda CSS migration -Status: **not started — census done (July 2026); semantic-token pre-work -can begin now, while still on Chakra.** +Status: **semantic-token pre-work done on Chakra (2026-07-27) — all +structural OSS/private divergence converged onto shared component structure + +semantic tokens; differ shows zero structural diffs (only the +`withDefaultColorScheme` `defaultProps` diffs remain, by design). Static +checks green both repos; semantic-token CSS-var emission (incl. the sidebar +gradient) verified via `toCSSVar`. Pixel fidelity vs the live branded +deployment left as a migration-time harness task (see status log).** Method: follow the **migration playbook** in the `@microbit/ui` monorepo (`../ui/docs/migration-playbook.md`) — the sequence, the gotcha catalog @@ -27,8 +32,15 @@ The census found the OSS/private split is **not token-clean** (unlike ml-trainer's): the private theme structurally extends component configs. Converge these onto shared structure driven by semantic tokens while still on Chakra, so brand divergence becomes token values before the migration -proper. Changing the OSS theme is acceptable where it simplifies — agreed -in principle; scope per component. Run the resolved-theme differ +proper. **Decision (2026-07-27): the OSS theme must not be structurally +different from private — the structural gaps are historical laziness (only +the private theme got updated), not brand intent.** So every step mirrors +the structure into OSS; divergence lives only in token values, and where a +value diff isn't brand-meaningful (an OSS oversight) the value is unified +outright rather than tokenised. This is the rule, not a per-component +judgement call — the only per-component question is "token or unify?", never +"converge or not?". Changing the OSS theme is expected, not just acceptable. +Run the resolved-theme differ (`node ../ui/bin/diff-chakra-themes.mjs`, from this repo) first and rerun it after every theme change while Chakra remains. @@ -42,9 +54,13 @@ Known structural extensions to converge: success/info, `code.error` otherwise) — fold into the library's `toast*Bg` status tokens. - Container `sidebar-header` bg (OSS black → private `brand.500`) and the - sidebar Tabs variant's background (OSS black → private brand - **linear-gradient**): `sidebarHeaderBg`-type semantic tokens — a - semantic token can hold the gradient privately, flat black OSS. + sidebar Tabs variant: `sidebarHeaderBg`-type semantic tokens — a semantic + token can hold the gradient privately, flat black OSS. **Correction + (2026-07-27 differ run):** the sidebar Tabs variant diverges on *three* + properties, not just the tablist background the census named — `tablist. + background` (black → brand→blimpTeal linear-gradient), `tab._selected. + color` (black → `brand.300`) and `tab._selected.bg` (`gray.50` → + `gray.25`). Convergence needs three tokens, not one. - Private-only Tooltip config. - Private theme also carries a full custom `gray` ramp (not just the family 10/25 additions) and extra ramps (`purple`, `teal`, `blimpTeal`). @@ -136,3 +152,239 @@ Chakra Heading (they compose Text). - `../python-editor-v3-microbit` pulled upstream changes on 2026-07-24 that postdate the census — spot-check the census's private-theme claims against the current theme before acting on them. + +- 2026-07-27: **differ run, validated, and classified; convergence order + proposed (below) — awaiting review, no theme code changed.** + + **Kit validation.** `node ../ui/bin/diff-chakra-themes.mjs` failed on + first run: the app's `node_modules/esbuild` carries only the + `darwin-arm64` binary (macOS-populated tree, run on a linux-arm64 host). + Per the playbook rule ("fix the script in ../ui, don't work around it + here"), fixed in the kit rather than reinstalling app deps: + `diff-chakra-themes.mjs` now resolves esbuild from the app repo first + (to match the app's toolchain version) and **falls back to the kit's own + esbuild** — same version (0.25.12), correct platform — when the app's + binary won't launch, printing a one-line note. `packages: "external"` + keeps `@chakra-ui/react` resolving through the app either way, so the + fallback doesn't change what's diffed. Re-run clean: 56 token diffs, 56 + component diffs, 0 other, Panda cross-check skipped (no preset pair yet). + This is the kit's first successful run in the family; the fix should be + PR'd back to `../ui`. + + **Census cross-check (post-2026-07-24 pull).** Claims that still hold: + Button `outline` *is* still colorScheme-conditional (`color: + {scheme}.{scheme==='brand'?500:600}`, hover `…?600:700`, bg transparent), + plus `unstyled`, `language`, `baseStyle.borderRadius: button`; Alert + `toast` per-status recolour is exactly `blimpTeal.700` (success/info) / + `code.error` (else); Container `sidebar-header` black→`brand.500`; + Tooltip private-only (`baseStyle.fontSize` sm→md); full custom `gray` + ramp + `purple`/`teal`/`blimpTeal`; `withDefaultColorScheme('brand')` + + `withDefaultVariant('outline')`. Discrepancies / additions found: + - **Sidebar Tabs is broader than the census said** — three divergent + props, not one (see the corrected Pre-work bullet above). + - **Brand-ramp shape asymmetry:** OSS defines `brand.10/25/50/900` + (brand = gray copy); the private `brand` ramp defines only `100–800` + (no `.10/.25/.50/.900`). Low-risk — grep found **no app references to + `brand.10/25/900`** — but the private ramp shape should be made + intentional when the ramps move to the preset. + - **Private brand-ramp data nits (brand-team, out of convergence scope):** + `brand.100` is `#e1dbF3` (stray uppercase `F`); `brand.600` (`#50388f`) + is *darker* than `brand.700` (`#5c40a6`) — non-monotonic. Flag to + whoever owns the palette; not a structure question. + - **`withDefaultColorScheme('brand')` accounts for ~41 of the 56 + component diffs** (every `defaultProps.colorScheme → brand`). These are + one config lever, **not** per-component structural extensions — handled + at migration time by the recipe `defaultVariants` preset override the + census already flagged, not by pre-work theme edits. + + **Classification of the 112 diffs.** + - *A — token-value deltas (brand-preset territory, fine as values):* all + `gray.50–800`, `teal.*`, `purple.*`, `blimpTeal.*` (new ramp), + `brand.100–800`, `code.*`, `radii.button` (0.375rem→2rem; base preset + standardises 2rem family-wide). Plus the ramp-shape asymmetry above. + - *B — structural extensions (converge onto semantic tokens while on + Chakra):* Button `outline`/`language`/`unstyled` + baseStyle radius; + Alert `toast` per-status bg; Container `sidebar-header` bg; Tabs + `sidebar` (×3 props); Tooltip `fontSize`. + - *C — config-level, no pre-work edit:* the ~41 `defaultProps.colorScheme` + diffs from `withDefaultColorScheme`. + + Base preset already carries the target semantic tokens: `languageText`/ + `languageTextHover` (→`brand2.500/600`), `toast{Info,Success,Warning, + Error}Bg` (Info/Success/Warning=`teal.800`, Error=`danger.600`), + `statusBarBg`. **No `sidebarHeaderBg`/sidebar-Tabs tokens exist yet** — + that name in the Pre-work list is a proposal; the sidebar token set is a + front-load decision (playbook "Decisions to front-load", + `statusBarBg`-family). + + **Proposed per-component convergence order** (rerun the differ after each; + each step should move its rows out of section B into A or eliminate them — + "brand divergence becomes token values, never structure"): + 1. **Button `baseStyle.borderRadius`** — add `borderRadius: 'button'` OSS + baseStyle. **Decision (2026-07-27): OSS adopts 2rem** (converge to the + family/base-preset value; OSS-grey-theme visual change accepted). The + divergence disappears rather than becoming a token value. Trivial, + lowest risk. + 2. **Button `unstyled`** — identical both sides; lift to OSS as-is. No + token. Trivial. + 3. **Tooltip** — add OSS `Tooltip.baseStyle.fontSize`. **Decision + (2026-07-27): set OSS to `md`, no token** — the sm/md split was an OSS + oversight; both sides match and the divergence disappears. + 4. **Container `sidebar-header`** — introduce `sidebarHeaderBg` semantic + token (OSS `black`, private `brand.500`); OSS container uses + `bg: 'sidebarHeaderBg'`. First sidebar token — pairs with step 7. + 5. **Alert `toast`** — define the per-status container bg OSS-side against + the base preset's `toast{Success,Info}Bg`/`toast{Error,Warning}Bg` + tokens; app preset overrides Success/Info→`blimpTeal.700`, else→ + `code.error`. Retires the private-only status logic into tokens. + 6. **Button `outline` + `language`** — define both OSS-side. `outline`'s + colours are already colorScheme-driven (brand ramp refs), so sharing + the function OSS-side makes it structural-shared with value divergence + living in the ramp. `language` uses the base preset's `languageText`/ + `languageTextHover` tokens (hardcoded `brand.500/600` privately → + token overrides). Largest single step; retires two private-only + variants. + 7. **Tabs `sidebar`** — last (app chrome, heaviest divergence). Three + tokens: `sidebarTablistBg` (a semantic token *can* hold the gradient + string — flat `black` OSS / gradient private), `sidebarTabSelectedText` + (`black`/`brand.300`), `sidebarTabSelectedBg` (`gray.50`/`gray.25`). + OSS Tabs references the tokens; private preset overrides. Benefits + from the token patterns established in steps 4–6, and from the + `statusBarBg`-family front-load decision landing first. + + Not in this order: the `withDefaultColorScheme` `defaultProps` diffs + (category C — migration-time recipe override, left on Chakra untouched) + and the brand-ramp value/shape nits (brand-team, not structure). + +- 2026-07-27 (later): **convergence executed — all seven steps landed in + lockstep across both repos; differ shows zero structural divergence.** + Mechanism on Chakra: each component config was made *structurally + identical* across the OSS (`src/deployment/default`) and private + (`../python-editor-v3-microbit/src`) themes, with brand divergence moved + into Chakra `semanticTokens` (a new `semanticTokens` block in each + `theme.ts` — OSS holds the OSS value, private overrides the same names). + Differ before → after: **56 → 43 component diffs, and every one of the 43 + remaining is a `defaultProps.colorScheme` (category C, from + `withDefaultColorScheme('brand')`)** — no structural extension survives. + Divergence now lives in section A (brand ramp values) + 8 `semanticTokens` + (section C). + + Per-step outcomes (each verified by a differ re-run): + 1. Button radius — OSS `radii.button` → `2rem` + `baseStyle.borderRadius: + 'button'`; unified, no token (`radii.button` + `Button.baseStyle` + diffs gone). + 2. Button `unstyled` — lifted to OSS as-is (diff gone). + 3. Tooltip — new OSS `components/tooltip.ts` (`fontSize: 'md'`) registered + in OSS `theme.ts`; unified, no token (diff gone). + 4. Container `sidebar-header` — `bg: 'sidebarHeaderBg'` both sides + (`black` / `brand.500`). + 5. Alert `toast` — identical `toastBgByStatus` map → `toast{Success,Info, + Warning,Error}Bg` both sides (OSS = Chakra solid status colours; private + success/info→`blimpTeal.700`, warning/error→`code.error`). Retired the + private-only per-status branch into tokens. + 6. Button `outline` + `language` — both defined identically OSS-side. + `outline` stays colorScheme-conditional (value divergence flows through + the brand ramp); `language` uses `languageText`/`languageTextHover` + (both themes alias `brand.500`/`brand.600`, so the token names carry + intent while divergence flows through the ramp). + 7. Tabs `sidebar` — `sidebarTablistBg` / `sidebarTabSelectedText` / + `sidebarTabSelectedBg` both sides. The private gradient now lives in the + `sidebarTablistBg` token (and the stray trailing `;` in the old inline + gradient string was dropped in the move). + + Static checks: app `tsc --noEmit` clean for the theme changes (two + pre-existing errors in `codemirror/lint` + `language-server/diagnostics` + reproduce on the clean tree — unrelated); private-package `tsc --noEmit` + clean; ESLint + Prettier clean in both repos. Files touched — OSS: + `radii.ts`, `theme.ts`, `components/{button,alert,container,tabs}.ts`, new + `components/tooltip.ts`; private: `theme.ts`, + `components/{button,alert,container,tabs}.ts`. + + **Token mechanics verified (2026-07-27).** The differ validates structure, + not rendering, so the two things it can't see were checked by resolving + both themes through Chakra's `toCSSVar` pipeline (the private package was + rebuilt first). Results: + - **Gradient-in-a-semantic-token works.** `sidebarTablistBg` emits + verbatim as `--chakra-colors-sidebarTablistBg: transparent + linear-gradient(to bottom, var(--chakra-colors-brand-500) 0%, + var(--chakra-colors-blimpTeal-400) 100%) 0% 0% no-repeat padding-box` + (full background shorthand, nested var refs preserved, no trailing `;`); + OSS resolves to `var(--chakra-colors-black)`. The Tabs sidebar variant + references the token (`tablist.background → sidebarTablistBg`), so the + var is consumed. `background: var(--prop)` holding a background shorthand + is standard CSS and identical to the previous inline form. + - **All 10 semantic tokens emit a var on both themes** (nothing undefined); + toast tokens resolve per status (private success/info → `blimpTeal.700`, + warning/error → `code.error`; OSS → green/blue/orange/red.500). + Verification script: `scratchpad/verify-semantic-tokens.mjs` (throwaway). + + **Still nice-to-have — pixel fidelity against the live branded deployment.** + The token mechanics are confirmed, but an actual side-by-side against + https://python.microbit.org/ (sidebar chrome + real toasts) is still worth + doing at migration time via the fidelity harness — not blocking now, and + this sandbox can't reach the live host. A local branded run needs + `npm run build && npm run preview` with `node_modules/@microbit-foundation/ + python-editor-v3-microbit` linked to the local private package (the vite + `theme-package` alias points there; the private changes are + unpublished/unpinned). + +## Notes to revisit later + +Parked items surfaced during pre-work — out of scope for the convergence +steps above, to raise with the relevant owner when convenient. + +- **Private brand-ramp data nits (`../python-editor-v3-microbit` + `src/colors.ts`).** Not structure — palette-value bugs for whoever owns + the brand colours: + - `brand.100` is `#e1dbF3` — stray uppercase `F`. Harmless to CSS but + inconsistent with the rest of the ramp; normalise to lowercase. + - `brand.600` (`#50388f`) is *darker* than `brand.700` (`#5c40a6`) — the + ramp is non-monotonic in lightness at 600→700. Likely a mistake; confirm + the intended values before the ramps move to the Panda preset (a + non-monotonic ramp will bake the oddity into the preset tokens). +- **Brand-ramp shape asymmetry.** OSS `brand` (= gray copy) defines + `brand.10/25/50/900`; the private `brand` ramp defines only `100–800`. No + app references to `brand.10/25/900` today (grep-clean), so it's latent — + but decide the intended private ramp shape when the ramps move to the + preset rather than carrying the asymmetry forward silently. + +- **Cross-app `brand`/`brand2` mapping (2026-07-27 investigation) — teal↔ + brand2 does NOT map; parked.** This app has two brand hues — **purple** + (`brand`/`purple` ramps, both centred on `#6c4bc1`) and **teal** + (`teal`/`blimpTeal`, ~`#7bcdc2`) — over a gray/black/white base. Usage + census verdict: + - **Purple = primary interactive** — links, primary buttons, dialog + accents, sidebar header/logo, focus/hover; it's the private default + `colorScheme` (`withDefaultColorScheme('brand')`). This maps *cleanly* + onto the family `brand` role (ml-trainer's `brand` = primary interactive + too), and is already true here — `brand` **is** the purple ramp. Nothing + to do beyond confirming it at preset time. + - **Teal = a code/content marker, not a general accent** — docs code + snippets, drag-to-insert handles, simulator sensor icons, editor + code-block backgrounds. The intent is explicit in + `simulator/RadioModule.tsx` (`from === 'code' ? blimpTeal : brand` → + teal = machine/code-origin, purple = user). It is **never** a button + `colorScheme` and never general chrome. + - **Why teal ≠ `brand2`:** ml-trainer's `brand2` is a *general secondary + accent* (LED/progress/animation/toggle/status-chrome; even neutral gray + in OSS, green only privately). Same slot number, different meaning — and + a direct conflict: chrome/status fill is `brand2` (green) in ml-trainer + but `brand` (purple) here. Aliasing this app's teal to `brand2` would + misname it and cross the two apps' chrome onto opposite tokens. + **Decision: treat this app's teal as an app-specific "code/content" + semantic (sibling to the `code.*` category), not a family `brand2`.** + - Genuine consistency that *does* hold: `toast*Bg` is on the `teal` ramp + family-wide and this app's success/info toasts are already `blimpTeal.700` + (kept). Errors/destructive on red/`danger` also aligns. + - Within-app cleanup (independent): the `purple` and `teal` ramps are + **unused by name** — the app references `brand.*` and `blimpTeal.*` + exclusively — so they duplicate the canonical ramps. Consolidating to one + purple + one teal ramp is a simplification, but watch the `code.*` + palette, which hardcodes `teal.500`/`teal.700` hexes. + +- **`languageText` base-preset default looks wrong (raise against `../ui`).** + The base preset defaults `languageText`/`languageTextHover` to + `brand2.*`, but **both** apps override it to their *primary* brand + (ml-trainer → `brand.600`; this app → `brand.500`). Two apps overriding the + same default the same way suggests the base-preset default should be + `brand`, not `brand2` — a small family-level fix for the shared-ui repo. From 69b9bd83956d939543840cccf7edbc46bc91f833 Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Mon, 27 Jul 2026 10:32:05 +0000 Subject: [PATCH 005/104] Update RAC migration doc: live fidelity confirmed Record the headless side-by-side vs python.microbit.org/v/3: the sidebar Tabs gradient renders byte-identical (brand.500 -> blimpTeal.400) to live, confirming the inline-string -> semantic-token refactor preserves the branded appearance. Notes the sandbox setup needed (node_modules reinstall for platform-native binaries, proxy-authed Chromium, CI=true vite). --- RAC-MIGRATION.md | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/RAC-MIGRATION.md b/RAC-MIGRATION.md index 92927b2c4..5f8f046fd 100644 --- a/RAC-MIGRATION.md +++ b/RAC-MIGRATION.md @@ -4,9 +4,9 @@ Status: **semantic-token pre-work done on Chakra (2026-07-27) — all structural OSS/private divergence converged onto shared component structure + semantic tokens; differ shows zero structural diffs (only the `withDefaultColorScheme` `defaultProps` diffs remain, by design). Static -checks green both repos; semantic-token CSS-var emission (incl. the sidebar -gradient) verified via `toCSSVar`. Pixel fidelity vs the live branded -deployment left as a migration-time harness task (see status log).** +checks green both repos; semantic-token CSS-var emission verified via +`toCSSVar`; sidebar gradient confirmed byte-identical to the live branded +deployment (`python.microbit.org/v/3`). Ready for review/PR.** Method: follow the **migration playbook** in the `@microbit/ui` monorepo (`../ui/docs/migration-playbook.md`) — the sequence, the gotcha catalog @@ -318,15 +318,24 @@ Chakra Heading (they compose Text). warning/error → `code.error`; OSS → green/blue/orange/red.500). Verification script: `scratchpad/verify-semantic-tokens.mjs` (throwaway). - **Still nice-to-have — pixel fidelity against the live branded deployment.** - The token mechanics are confirmed, but an actual side-by-side against - https://python.microbit.org/ (sidebar chrome + real toasts) is still worth - doing at migration time via the fidelity harness — not blocking now, and - this sandbox can't reach the live host. A local branded run needs - `npm run build && npm run preview` with `node_modules/@microbit-foundation/ - python-editor-v3-microbit` linked to the local private package (the vite - `theme-package` alias points there; the private changes are - unpublished/unpinned). + **Live fidelity confirmed (2026-07-27).** Ran a headless-Chromium + side-by-side of the local branded build (private theme linked into + `node_modules/@microbit-foundation/python-editor-v3-microbit`, vite dev) + against the live `https://python.microbit.org/v/3`. The sidebar Tabs + gradient renders **byte-identical** on both: computed + `background-image: linear-gradient(rgb(108, 75, 193) 0%, rgb(123, 205, 194) + 100%)` — i.e. `brand.500` (#6c4bc1) → `blimpTeal.400` (#7bcdc2) — exactly + one gradient element (the tablist) on each side. Visually confirmed too + (purple→teal sidebar, brand logo, brand-purple "Send to micro:bit"). So the + inline-gradient-string → semantic-token refactor reproduces the production + branded appearance exactly. Toasts were not triggered live, but their + tokens are verified twice (differ + `toCSSVar`) and are ordinary colour + refs (`blimpTeal.700` / `code.error`); a full toast pixel pass can ride the + migration-time fidelity harness. Sandbox notes for whoever re-runs: the + app's `node_modules` needed a clean reinstall (wrong-platform native + binaries — rollup/esbuild), Chromium must be pointed at the sandbox proxy + with credentials (env userinfo alone → 407, bypass loopback for the local + server), and vite dev needs `CI=true` (+ same-command lifetime) to stay up. ## Notes to revisit later From ef63df36b6e85913509c9a625caf0471e8f16fbe Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Mon, 27 Jul 2026 12:06:45 +0000 Subject: [PATCH 006/104] Add Panda + preset stack foundation (Chakra coexistence) RAC/Panda migration step 2: install Panda alongside Chakra without porting any components. The app renders unchanged on Chakra; the generated CSS is inert until components port. - Deps: @pandacss/dev, @csstools/postcss-cascade-layers; @microbit/ui linked via file:../ui/packages/ui (ships as source); react-aria-components (peer). - panda.config.ts: preset stack (preset-base -> @microbit/ui/base-preset -> app preset -> optional private brand preset), eject:true, preflight:false, include app + @microbit/ui source. - App preset src/deployment/default/panda-preset.ts: code.* palette + sidebar/ language semantic tokens the base preset lacks. - Coexistence CSS: panda script does codegen + cssgen + unlayer; styled-system alias in tsconfig + vite; styled-system.css imported first in index.tsx; generated output ignored by git/eslint/prettier. - Legacy Safari (<15.4, app targets Safari/iOS 14): postcss.config.cjs runs expandLogicalShorthands + cascade-layers in production only. Providers + i18n are deferred to step 3 (first shared component port). See RAC-MIGRATION.md. --- .eslintrc.cjs | 1 + .gitignore | 4 + .prettierignore | 2 + package-lock.json | 2931 +++++++++++++++++++++++- package.json | 10 + panda.config.ts | 57 + postcss.config.cjs | 39 + src/deployment/default/panda-preset.ts | 64 + src/index.tsx | 4 + tsconfig.json | 4 + tsconfig.node.json | 2 +- vite.config.ts | 4 + 12 files changed, 3063 insertions(+), 59 deletions(-) create mode 100644 panda.config.ts create mode 100644 postcss.config.cjs create mode 100644 src/deployment/default/panda-preset.ts diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 83afc9aef..8dc1b93ca 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -12,6 +12,7 @@ module.exports = { ], ignorePatterns: [ "dist", + "styled-system", ".eslintrc.cjs", "deployment.cjs", "bin/**/*.js", diff --git a/.gitignore b/.gitignore index 232c2e487..b58b5a37a 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,10 @@ # production /build +# Panda CSS generated output +/styled-system +/src/styled-system.css + # misc .DS_Store .env.local diff --git a/.prettierignore b/.prettierignore index 94802660b..e8734ec6c 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1 +1,3 @@ src/editor/codemirror/lint/lint.ts +styled-system +src/styled-system.css diff --git a/package-lock.json b/package-lock.json index 8ed1dfab3..f0835e3cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "@emotion/styled": "^11.14.1", "@microbit/microbit-connection": "^1.0.0", "@microbit/microbit-fs": "^0.10.0", + "@microbit/ui": "file:../ui/packages/ui", "@sanity/block-content-to-react": "^3.0.0", "@sanity/image-url": "^1.0.1", "@testing-library/jest-dom": "^5.14.1", @@ -47,6 +48,7 @@ "marked": "^4.0.15", "mobile-drag-drop": "^2.3.0-rc.2", "react": "^18.3.1", + "react-aria-components": "^1.19.0", "react-dom": "^18.3.1", "react-hotkeys-hook": "^4.5.0", "react-icons": "^4.12.0", @@ -60,7 +62,9 @@ }, "devDependencies": { "@chakra-ui/cli": "2.5.8", + "@csstools/postcss-cascade-layers": "^6.0.0", "@formatjs/cli": "^6.2.7", + "@pandacss/dev": "^1.11.4", "@playwright/test": "^1.58.2", "@testing-library/jest-dom": "^5.14.1", "@testing-library/react": "^14.0.0", @@ -89,6 +93,33 @@ "npm": ">=11.18.0" } }, + "../ui/packages/ui": { + "name": "@microbit/ui", + "version": "0.0.0", + "license": "MIT", + "devDependencies": { + "@pandacss/dev": "^1.11.4", + "@storybook/react-vite": "^10.5.2", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.5.2", + "react": "^18.3.1", + "react-aria-components": "^1.19.0", + "react-dom": "^18.3.1", + "react-icons": "^4.12.0", + "react-intl": "^6.6.8", + "storybook": "^10.5.2", + "typescript": "^5.4.2", + "vite": "^6.3.5" + }, + "peerDependencies": { + "@pandacss/dev": "^1.11.4", + "react": "^18.3.1", + "react-aria-components": "^1.19.0", + "react-icons": "^4.12.0 || ^5.0.0", + "react-intl": "^6.6.8 || ^7.0.0" + } + }, "node_modules/@acemir/cssom": { "version": "0.9.31", "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.31.tgz", @@ -2548,6 +2579,56 @@ "node": ">=20.19.0" } }, + "node_modules/@csstools/postcss-cascade-layers": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-6.0.0.tgz", + "integrity": "sha512-WhsECqmrEZQGqaPlBA7JkmF/CJ2/+wetL4fkL9sOPccKd32PQ1qToFM6gqSI5rkpmYqubvbxjEJhyMTHYK0vZQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/selector-specificity": "^6.0.0", + "postcss-selector-parser": "^7.1.1" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/selector-specificity": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-6.0.0.tgz", + "integrity": "sha512-4sSgl78OtOXEX/2d++8A83zHNTgwCJMaR24FvsYL7Uf/VS8HZk9PTwR51elTbGqMuwH3szLvvOXEaVnqn0Z3zA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.1.1" + } + }, "node_modules/@emotion/babel-plugin": { "version": "11.13.5", "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", @@ -3545,6 +3626,19 @@ "node": ">=6" } }, + "node_modules/@hono/node-server": { + "version": "1.19.14", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", + "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", @@ -3614,6 +3708,33 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/@internationalized/date": { + "version": "3.12.2", + "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.12.2.tgz", + "integrity": "sha512-FY1Y+H64NDs+HAF6omlnWxm3mEpfgaCSWtL5l551ZZfImA+kGjPFgrnJrGjH6lfmLL0g8Z/mBu1R3kufeCp6Jw==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, + "node_modules/@internationalized/number": { + "version": "3.6.7", + "resolved": "https://registry.npmjs.org/@internationalized/number/-/number-3.6.7.tgz", + "integrity": "sha512-3ji1fcrT+FPAK86UqEhB/psHixYo6niWPJtt7+qRaYFynt/BaJG8GhAPimtWUpEiVSTq8ZM8L5psMxGquiB/Vg==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, + "node_modules/@internationalized/string": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/@internationalized/string/-/string-3.2.9.tgz", + "integrity": "sha512-kzP/M/mbQxODlmOt4bIQZ2SBVUWUSqMLXooXixnX7noche8WHaQcA+nwFN1K2KCF/cp+LDUhcJsCicwkvhD1pg==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, "node_modules/@isaacs/cliui": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz", @@ -4483,6 +4604,75 @@ "tslib": ">=1.11.1" } }, + "node_modules/@microbit/ui": { + "resolved": "../ui/packages/ui", + "link": true + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", + "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -5417,92 +5607,927 @@ "node": ">=14" } }, - "node_modules/@playwright/test": { - "version": "1.61.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.61.1.tgz", - "integrity": "sha512-8nKv6+0RJSL9FE4jYOEGXnPeM/Hg12qZpmqzZjRh3qM0Y7c3z1mrOTfFLids72RDQYVh9WpLEfR5WdpNX4fkig==", + "node_modules/@pandacss/config": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@pandacss/config/-/config-1.11.4.tgz", + "integrity": "sha512-fYdfRtMOtxdtrQQJmgoN6/IxKQOlQEpTGjUXqlHsHZ193JvwvE0FGEVVrGMLEOb/nbPn4vrscfFak+k4G8Qzww==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "playwright": "1.61.1" + "@pandacss/logger": "1.11.4", + "@pandacss/preset-base": "1.11.4", + "@pandacss/preset-panda": "1.11.4", + "@pandacss/shared": "1.11.4", + "@pandacss/types": "1.11.4", + "esbuild": "0.25.12", + "escalade": "3.2.0", + "microdiff": "1.5.0", + "typescript": "6.0.2" }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@pandacss/config/node_modules/typescript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.2.tgz", + "integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==", + "dev": true, + "license": "Apache-2.0", "bin": { - "playwright": "cli.js" + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" }, "engines": { - "node": ">=18" + "node": ">=14.17" } }, - "node_modules/@pnpm/config.env-replace": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", - "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "node_modules/@pandacss/core": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@pandacss/core/-/core-1.11.4.tgz", + "integrity": "sha512-2C9qwnmdP24oaoTFc+dTMjJHQZ6iV/l4VCLR4hZlGTiQ60k0EFMK4sV998vu0n57fi4p1I1yTDk9Ew4Wu27pGg==", "dev": true, "license": "MIT", + "dependencies": { + "@csstools/postcss-cascade-layers": "5.0.2", + "@pandacss/is-valid-prop": "^1.11.4", + "@pandacss/logger": "1.11.4", + "@pandacss/shared": "1.11.4", + "@pandacss/token-dictionary": "1.11.4", + "@pandacss/types": "1.11.4", + "browserslist": "4.28.1", + "lodash.merge": "4.6.2", + "outdent": "0.8.0", + "postcss": "8.5.14", + "postcss-discard-duplicates": "7.0.2", + "postcss-discard-empty": "7.0.1", + "postcss-minify-selectors": "7.0.5", + "postcss-nested": "7.0.2", + "postcss-normalize-whitespace": "7.0.1", + "postcss-selector-parser": "7.1.1", + "ts-pattern": "5.9.0" + }, "engines": { - "node": ">=12.22.0" + "node": ">=20" } }, - "node_modules/@pnpm/network.ca-file": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", - "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "node_modules/@pandacss/core/node_modules/@csstools/postcss-cascade-layers": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-5.0.2.tgz", + "integrity": "sha512-nWBE08nhO8uWl6kSAeCx4im7QfVko3zLrtgWZY4/bP87zrSPpSyN/3W3TDqz1jJuH+kbKOHXg5rJnK+ZVYcFFg==", "dev": true, - "license": "MIT", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "graceful-fs": "4.2.10" + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" }, "engines": { - "node": ">=12.22.0" + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "node_modules/@pandacss/core/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", "dev": true, - "license": "ISC" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } }, - "node_modules/@pnpm/npm-conf": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-3.0.3.tgz", - "integrity": "sha512-//0sR/cow/s4ICQaYoAobOl4aU8cjU6x/V24V7XkKotb9+O+3zySIYp146vpaobYHnxa4pZX8NkV54Z5AwbDKA==", + "node_modules/@pandacss/core/node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "@pnpm/config.env-replace": "^1.1.0", - "@pnpm/network.ca-file": "^1.0.1", - "config-chain": "^1.1.11" + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" }, "engines": { - "node": ">=12" + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/@popperjs/core": { - "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", - "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "node_modules/@pandacss/core/node_modules/postcss": { + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" } }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "node_modules/@pandacss/core/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "dev": true, - "license": "BSD-3-Clause" + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "node_modules/@pandacss/dev": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@pandacss/dev/-/dev-1.11.4.tgz", + "integrity": "sha512-jMexLMJAxnDutYZdzh9M3f1WTYX4Dl7QtsxJsQHRu4Vw3S5Sqb7awR+rP3PDPa8/zFNIbMhQXYtURkKByPrclA==", "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/codegen": { + "license": "MIT", + "dependencies": { + "@clack/prompts": "0.11.0", + "@pandacss/config": "1.11.4", + "@pandacss/logger": "1.11.4", + "@pandacss/mcp": "1.11.4", + "@pandacss/node": "1.11.4", + "@pandacss/postcss": "1.11.4", + "@pandacss/preset-base": "1.11.4", + "@pandacss/preset-panda": "1.11.4", + "@pandacss/shared": "1.11.4", + "@pandacss/token-dictionary": "1.11.4", + "@pandacss/types": "1.11.4", + "cac": "6.7.14" + }, + "bin": { + "panda": "bin.js", + "pandacss": "bin.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@pandacss/dev/node_modules/@clack/core": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@clack/core/-/core-0.5.0.tgz", + "integrity": "sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.0.0", + "sisteransi": "^1.0.5" + } + }, + "node_modules/@pandacss/dev/node_modules/@clack/prompts": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-0.11.0.tgz", + "integrity": "sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@clack/core": "0.5.0", + "picocolors": "^1.0.0", + "sisteransi": "^1.0.5" + } + }, + "node_modules/@pandacss/extractor": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@pandacss/extractor/-/extractor-1.11.4.tgz", + "integrity": "sha512-4xmyy5pUGZdqmyx+mRcq6xKuBZoLcU9EeNXnmMrrQKw8BhkxGOl3DNst0ZthH7S7JXEx9Aazc2Ac7kMlOh+cNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pandacss/shared": "1.11.4", + "ts-evaluator": "1.2.0", + "ts-morph": "28.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@pandacss/generator": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@pandacss/generator/-/generator-1.11.4.tgz", + "integrity": "sha512-UDL8J/qdnMXwEEjU7OvQfMTCk+BIntILg/b0fh76xEgex08TrvBLtEM/rZ3rOh95yCVuGwQI9n1Njzz8u3bKxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pandacss/core": "1.11.4", + "@pandacss/is-valid-prop": "^1.11.4", + "@pandacss/logger": "1.11.4", + "@pandacss/shared": "1.11.4", + "@pandacss/token-dictionary": "1.11.4", + "@pandacss/types": "1.11.4", + "javascript-stringify": "2.1.0", + "outdent": " ^0.8.0", + "pluralize": "8.0.0", + "postcss": "8.5.14", + "ts-pattern": "5.9.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@pandacss/generator/node_modules/postcss": { + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/@pandacss/is-valid-prop": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@pandacss/is-valid-prop/-/is-valid-prop-1.11.4.tgz", + "integrity": "sha512-RWxInlS+lGgKiF0fB0HO76vsJFgRvbavm5Z25/GqqN8MPHXYA6n5rZnfdp4itEXy5DJkQ9vt3yrwa2IKiuhtrA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/@pandacss/logger": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@pandacss/logger/-/logger-1.11.4.tgz", + "integrity": "sha512-NY9aW9tCQR2yJVqdCpoB4LeOIaLk1HxztAc0CrgJgNROteEyj7lV65lr8FyWCi4RH3WBZvIhyPMldd3CSon/OA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pandacss/types": "1.11.4", + "kleur": "4.1.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@pandacss/mcp": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@pandacss/mcp/-/mcp-1.11.4.tgz", + "integrity": "sha512-MDsfhaVje+gso5z1lwHnCj3G6/wsQXi4aVJ6KsJiBpUiZNYs5QS7wRoPT8cUIIoDQJztTxIDPR9ozoL1O+hJyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@clack/prompts": "0.11.0", + "@modelcontextprotocol/sdk": "^1.29.0", + "@pandacss/logger": "1.11.4", + "@pandacss/node": "1.11.4", + "@pandacss/token-dictionary": "1.11.4", + "@pandacss/types": "1.11.4", + "zod": "^4.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@pandacss/mcp/node_modules/@clack/core": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@clack/core/-/core-0.5.0.tgz", + "integrity": "sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.0.0", + "sisteransi": "^1.0.5" + } + }, + "node_modules/@pandacss/mcp/node_modules/@clack/prompts": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-0.11.0.tgz", + "integrity": "sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@clack/core": "0.5.0", + "picocolors": "^1.0.0", + "sisteransi": "^1.0.5" + } + }, + "node_modules/@pandacss/node": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@pandacss/node/-/node-1.11.4.tgz", + "integrity": "sha512-u1/y1oHVASGwXfoKbADVPcrPi54zJ0R8Qg1EvPpRNjw+ovcqJsFkZHBN03lCwSOFbb2ukvCKf4rfMzzNvABajg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pandacss/config": "1.11.4", + "@pandacss/core": "1.11.4", + "@pandacss/generator": "1.11.4", + "@pandacss/logger": "1.11.4", + "@pandacss/parser": "1.11.4", + "@pandacss/plugin-lightningcss": "1.11.4", + "@pandacss/plugin-svelte": "1.11.4", + "@pandacss/plugin-vue": "1.11.4", + "@pandacss/reporter": "1.11.4", + "@pandacss/shared": "1.11.4", + "@pandacss/token-dictionary": "1.11.4", + "@pandacss/types": "1.11.4", + "browserslist": "4.28.1", + "chokidar": "4.0.3", + "fast-glob": "3.3.3", + "fs-extra": "11.3.2", + "get-tsconfig": "^4.13.0", + "glob-parent": "6.0.2", + "is-glob": "4.0.3", + "lodash.merge": "4.6.2", + "look-it-up": "2.1.0", + "outdent": " ^0.8.0", + "p-limit": "5.0.0", + "package-manager-detector": "1.6.0", + "perfect-debounce": "1.0.0", + "picomatch": "4.0.4", + "pkg-types": "2.3.0", + "pluralize": "8.0.0", + "postcss": "8.5.14", + "prettier": "3.2.5", + "ts-morph": "28.0.0", + "ts-pattern": "5.9.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@pandacss/node/node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/@pandacss/node/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@pandacss/node/node_modules/fs-extra": { + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz", + "integrity": "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@pandacss/node/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@pandacss/node/node_modules/p-limit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", + "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@pandacss/node/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@pandacss/node/node_modules/postcss": { + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/@pandacss/node/node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/@pandacss/node/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@pandacss/node/node_modules/yocto-queue": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@pandacss/parser": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@pandacss/parser/-/parser-1.11.4.tgz", + "integrity": "sha512-GyJ/+O9QVUC8tCxc9FJPrL8Oqltc7OVDIg8uC46FMBFI2IrG8sJI+J1QkLGZ+OL4AYZ897JjYQK+pbYsPesHsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pandacss/config": "^1.11.4", + "@pandacss/core": "^1.11.4", + "@pandacss/extractor": "1.11.4", + "@pandacss/logger": "1.11.4", + "@pandacss/shared": "1.11.4", + "@pandacss/types": "1.11.4", + "ts-morph": "28.0.0", + "ts-pattern": "5.9.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@pandacss/plugin-lightningcss": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@pandacss/plugin-lightningcss/-/plugin-lightningcss-1.11.4.tgz", + "integrity": "sha512-DGEu7gkDfReBU5rqWfZ0+AAywS5OPfDmBchjuuEUmNUb+Cj3STEsd7jPTo4GZEMBFdd5GIMOIB/GScwZrrKCww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pandacss/logger": "1.11.4", + "@pandacss/types": "1.11.4", + "browserslist": "4.28.1", + "lightningcss": "1.31.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@pandacss/plugin-lightningcss/node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/@pandacss/plugin-svelte": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@pandacss/plugin-svelte/-/plugin-svelte-1.11.4.tgz", + "integrity": "sha512-S9gohIV49MaOozt3+Xc6EiJgXd5Rc12I90XrI1KNfoKjwKjWuz0IZQgJOr67LQZIXn/BlAnO6aNugI5cBaUBRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pandacss/types": "1.11.4", + "magic-string": "0.30.21" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@pandacss/plugin-vue": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@pandacss/plugin-vue/-/plugin-vue-1.11.4.tgz", + "integrity": "sha512-wP+VnQByq1x6aQMyG2/70CRiLG4UORUC+bL+j86x0kj1UxdOpsPRf8TF1P5EyJPfenrnwUyDChaL4hJWL83JjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pandacss/types": "1.11.4", + "@vue/compiler-sfc": "3.5.25", + "magic-string": "0.30.21" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@pandacss/postcss": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@pandacss/postcss/-/postcss-1.11.4.tgz", + "integrity": "sha512-FOVKZDqqDrHzNNu0qE4Xi7SN+AheVUj3fFBg5B+Isj+uSh+w2YJNf5lyrJLU95PczMQl8NzrAocI5u6qHLBJVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pandacss/node": "1.11.4", + "postcss": "8.5.14" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@pandacss/postcss/node_modules/postcss": { + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/@pandacss/preset-base": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@pandacss/preset-base/-/preset-base-1.11.4.tgz", + "integrity": "sha512-Pf4BX9aaUiwuYg2RBiwYA9wdzifJFNTJRYVNJv7YJHrojZipWY7ELR8PVRA4gdAbIjog7KoWlOmKz6PcUZNfnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pandacss/types": "1.11.4" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@pandacss/preset-panda": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@pandacss/preset-panda/-/preset-panda-1.11.4.tgz", + "integrity": "sha512-Z6yrY7o0Xyqc6JpnAZ954APGs5VhLeZLJqTzAJw9eu6Y0pP5SWaOeztZCdPwWZvK3LbyXliYzc3FY4cxEaVYNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pandacss/types": "1.11.4" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@pandacss/reporter": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@pandacss/reporter/-/reporter-1.11.4.tgz", + "integrity": "sha512-6+lCjdOTGwlL+P6RKEDlmExcYwgoedlLhR7JAgw0UF9IvgMxvmH7Xk6RX8drYq6B+a1fGG4RN9V371ySZKLzbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pandacss/core": "1.11.4", + "@pandacss/generator": "1.11.4", + "@pandacss/logger": "1.11.4", + "@pandacss/shared": "1.11.4", + "@pandacss/types": "1.11.4", + "table": "6.9.0", + "wordwrapjs": "5.1.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@pandacss/shared": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@pandacss/shared/-/shared-1.11.4.tgz", + "integrity": "sha512-zFPz5yladwlsynFBkFKtzDDqArlVwgy1MzW3Rbz8NqfT72pOvklmuizXoScHsEPv3ox8Y/tdMcJf48rn8R5e+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/@pandacss/token-dictionary": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@pandacss/token-dictionary/-/token-dictionary-1.11.4.tgz", + "integrity": "sha512-K6agiBFJdu8ncyh3Z4EC43noDVlRNWFIdD6JFnsa2FIhCuhIoJP1hEInicURTfcoq4Z6OakAPonL4IW+54vbXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pandacss/logger": "^1.11.4", + "@pandacss/shared": "1.11.4", + "@pandacss/types": "1.11.4", + "picomatch": "4.0.4", + "ts-pattern": "5.9.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@pandacss/token-dictionary/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@pandacss/types": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@pandacss/types/-/types-1.11.4.tgz", + "integrity": "sha512-Bn+ez7ckm2E406QBF0W2ckEeFIBFo91qvOy10/bdxxiAHR76fBmg6tr4YlHbLHdXpcSBjXFWrGWo8nqyKJSx2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/@playwright/test": { + "version": "1.61.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.61.1.tgz", + "integrity": "sha512-8nKv6+0RJSL9FE4jYOEGXnPeM/Hg12qZpmqzZjRh3qM0Y7c3z1mrOTfFLids72RDQYVh9WpLEfR5WdpNX4fkig==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.61.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true, + "license": "ISC" + }, + "node_modules/@pnpm/npm-conf": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-3.0.3.tgz", + "integrity": "sha512-//0sR/cow/s4ICQaYoAobOl4aU8cjU6x/V24V7XkKotb9+O+3zySIYp146vpaobYHnxa4pZX8NkV54Z5AwbDKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", @@ -5554,6 +6579,15 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/@react-types/shared": { + "version": "3.36.0", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.36.0.tgz", + "integrity": "sha512-DkP/H0C2YjjS7gZWKNqOmU8a16qHPjQNdzMwmTq9SzplM6Iw0kVMTZ0OIoe6FOgGqa+FwMsE2QbPjh/n3g/jXQ==", + "license": "Apache-2.0", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-rc.3", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz", @@ -6491,6 +7525,15 @@ "@svgr/core": "*" } }, + "node_modules/@swc/helpers": { + "version": "0.5.23", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz", + "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, "node_modules/@szmarczak/http-timer": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", @@ -6669,6 +7712,18 @@ "node": ">=12" } }, + "node_modules/@ts-morph/common": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.29.0.tgz", + "integrity": "sha512-35oUmphHbJvQ/+UTwFNme/t2p3FoKiGJ5auTjjpNTop2dyREspirjMy82PLSC1pnDJ8ah1GU98hwpVt64YXQsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimatch": "^10.0.1", + "path-browserify": "^1.0.1", + "tinyglobby": "^0.2.14" + } + }, "node_modules/@types/aria-query": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", @@ -7402,6 +8457,80 @@ "dev": true, "license": "MIT" }, + "node_modules/@vue/compiler-core": { + "version": "3.5.25", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.25.tgz", + "integrity": "sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@vue/shared": "3.5.25", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-core/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.25", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.25.tgz", + "integrity": "sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.25", + "@vue/shared": "3.5.25" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.25", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.25.tgz", + "integrity": "sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@vue/compiler-core": "3.5.25", + "@vue/compiler-dom": "3.5.25", + "@vue/compiler-ssr": "3.5.25", + "@vue/shared": "3.5.25", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.6", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.25", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.25.tgz", + "integrity": "sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.25", + "@vue/shared": "3.5.25" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.25", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.25.tgz", + "integrity": "sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==", + "dev": true, + "license": "MIT" + }, "node_modules/@zag-js/dom-query": { "version": "0.31.1", "resolved": "https://registry.npmjs.org/@zag-js/dom-query/-/dom-query-0.31.1.tgz", @@ -7430,10 +8559,51 @@ "dev": true, "license": "MIT", "dependencies": { - "event-target-shim": "^5.0.0" + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" }, "engines": { - "node": ">=6.5" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/acorn": { @@ -7518,6 +8688,48 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, "node_modules/ansi-align": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", @@ -7566,6 +8778,16 @@ "node": ">=8" } }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/ansi-escapes": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", @@ -7816,6 +9038,16 @@ "node": ">=12" } }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/async": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", @@ -8041,6 +9273,45 @@ "dev": true, "license": "MIT" }, + "node_modules/body-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^2.0.0", + "debug": "^4.4.3", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", + "on-finished": "^2.4.1", + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/boxen": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz", @@ -8240,6 +9511,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/cacheable-lookup": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", @@ -8867,6 +10158,12 @@ "node": ">=4" } }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -8938,6 +10235,22 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/code-block-writer": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz", + "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==", + "dev": true, + "license": "MIT" + }, "node_modules/code-excerpt": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-4.0.0.tgz", @@ -9522,6 +10835,13 @@ "dev": true, "license": "MIT" }, + "node_modules/confbox": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", + "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", + "dev": true, + "license": "MIT" + }, "node_modules/config-chain": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", @@ -9560,6 +10880,30 @@ "url": "https://github.com/yeoman/configstore?sponsor=1" } }, + "node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/convert-source-map": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", @@ -9576,6 +10920,26 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, "node_modules/copy-to-clipboard": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", @@ -9599,6 +10963,24 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/cosmiconfig": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", @@ -9664,6 +11046,26 @@ "node": ">= 8" } }, + "node_modules/crosspath": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crosspath/-/crosspath-2.0.0.tgz", + "integrity": "sha512-ju88BYCQ2uvjO2bR+SsgLSTwTSctU+6Vp2ePbKPgSCZyy4MWZxYsT738DlKVRE5utUjobjPRm1MkTYKJxCmpTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "^17.0.36" + }, + "engines": { + "node": ">=14.9.0" + } + }, + "node_modules/crosspath/node_modules/@types/node": { + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", + "dev": true, + "license": "MIT" + }, "node_modules/crypto-random-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", @@ -9714,6 +11116,19 @@ "dev": true, "license": "MIT" }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/cssstyle": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-6.2.0.tgz", @@ -10041,6 +11456,16 @@ "node": ">=0.4.0" } }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -10051,6 +11476,16 @@ "node": ">=6" } }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "devOptional": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-node-es": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", @@ -10158,6 +11593,13 @@ "dev": true, "license": "MIT" }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true, + "license": "MIT" + }, "node_modules/ejs": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", @@ -10195,6 +11637,16 @@ "dev": true, "license": "MIT" }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/entities": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", @@ -10545,6 +11997,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true, + "license": "MIT" + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -10970,6 +12429,16 @@ "url": "https://github.com/bgub/eta?sponsor=1" } }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/event-target-shim": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", @@ -10980,6 +12449,19 @@ "node": ">=6" } }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/eventsource-parser": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.1.0.tgz", @@ -11051,6 +12533,104 @@ "node": ">=12.0.0" } }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.6.0.tgz", + "integrity": "sha512-XKJXDsASUOo0LLtFwW5hCcQGH0N4WQc/Rn8/Pvoia+TJFOkkFPvrtW9lZOeeNcxQJspvOIERMwiRLsVFlhHEkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "ip-address": "^10.2.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/express/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/exsolve": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.1.0.tgz", + "integrity": "sha512-D+42+T12DdIlJM3uepa55qGiL3sYdLBOxIl2ifQCzCHz4c7eiolaHsi3BIqEr7JxBzxv2pYZQX9kw16ziMcEmw==", + "dev": true, + "license": "MIT" + }, "node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", @@ -11069,7 +12649,24 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true, - "license": "MIT" + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", @@ -11246,6 +12843,28 @@ "node": ">=8" } }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", @@ -11377,6 +12996,16 @@ "node": ">= 12.20" } }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/framer-motion": { "version": "10.18.0", "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-10.18.0.tgz", @@ -11433,6 +13062,16 @@ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", "license": "0BSD" }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -11646,6 +13285,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-tsconfig": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/gifwrap": { "version": "0.10.1", "resolved": "https://registry.npmjs.org/gifwrap/-/gifwrap-0.10.1.tgz", @@ -11991,6 +13643,16 @@ "react-is": "^16.7.0" } }, + "node_modules/hono": { + "version": "4.12.31", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.31.tgz", + "integrity": "sha512-zJIHFrl6bq3RDd2YusFNCDlM8qUprxKswyi/OPzPyzKDdyBXDqWx8bZlZ7R+saTdSTatUmb3O7K4SspGPaEOQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, "node_modules/html-element": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/html-element/-/html-element-2.3.1.tgz", @@ -12023,6 +13685,27 @@ "dev": true, "license": "BSD-2-Clause" }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", @@ -12096,6 +13779,23 @@ "html-element": "^2.0.0" } }, + "node_modules/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/idb": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", @@ -12273,6 +13973,26 @@ "tslib": "2" } }, + "node_modules/ip-address": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/is-arguments": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", @@ -12761,6 +14481,13 @@ "dev": true, "license": "MIT" }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, + "license": "MIT" + }, "node_modules/is-regex": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", @@ -13041,6 +14768,13 @@ "node": ">=10" } }, + "node_modules/javascript-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz", + "integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==", + "dev": true, + "license": "MIT" + }, "node_modules/jest-diff": { "version": "30.4.1", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.4.1.tgz", @@ -13358,6 +15092,16 @@ "node": ">=18" } }, + "node_modules/jose": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", + "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/jpeg-js": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz", @@ -13474,6 +15218,13 @@ "dev": true, "license": "MIT" }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "dev": true, + "license": "BSD-2-Clause" + }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -13553,6 +15304,16 @@ "node": ">=0.10.0" } }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/langbase": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/langbase/-/langbase-1.2.4.tgz", @@ -13705,7 +15466,269 @@ "type-check": "~0.4.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz", + "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==", + "devOptional": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.31.1", + "lightningcss-darwin-arm64": "1.31.1", + "lightningcss-darwin-x64": "1.31.1", + "lightningcss-freebsd-x64": "1.31.1", + "lightningcss-linux-arm-gnueabihf": "1.31.1", + "lightningcss-linux-arm64-gnu": "1.31.1", + "lightningcss-linux-arm64-musl": "1.31.1", + "lightningcss-linux-x64-gnu": "1.31.1", + "lightningcss-linux-x64-musl": "1.31.1", + "lightningcss-win32-arm64-msvc": "1.31.1", + "lightningcss-win32-x64-msvc": "1.31.1" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz", + "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz", + "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz", + "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz", + "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz", + "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz", + "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz", + "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz", + "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz", + "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz", + "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz", + "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, "node_modules/line-column-path": { @@ -13798,6 +15821,13 @@ "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", "license": "MIT" }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true, + "license": "MIT" + }, "node_modules/log-symbols": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-7.0.1.tgz", @@ -13822,6 +15852,13 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/look-it-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/look-it-up/-/look-it-up-2.1.0.tgz", + "integrity": "sha512-nMoGWW2HurtuJf6XAL56FWTDCWLOTSsanrgwOyaR5Y4e3zfG5N/0cU5xWZSEU3tBxhQugRbV1xL9jb+ug7yZww==", + "dev": true, + "license": "MIT" + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -13972,6 +16009,60 @@ "dev": true, "license": "CC0-1.0" }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/microdiff": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/microdiff/-/microdiff-1.5.0.tgz", + "integrity": "sha512-Drq+/THMvDdzRYrK0oxJmOKiC24ayUV8ahrt8l3oRK51PWt6gdtrIGrlIH3pT/lFh1z93FbAcidtsHcWbnRz8Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/mime": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", @@ -14146,6 +16237,16 @@ "dev": true, "license": "MIT" }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -14403,6 +16504,16 @@ "node": ">= 0.4" } }, + "node_modules/object-path": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.8.tgz", + "integrity": "sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.12.0" + } + }, "node_modules/object.assign": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", @@ -14499,6 +16610,19 @@ "dev": true, "license": "MIT" }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -14673,6 +16797,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/outdent": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/outdent/-/outdent-0.8.0.tgz", + "integrity": "sha512-KiOAIsdpUTcAXuykya5fnVVT+/5uS0Q1mrkRHcF89tpieSmY33O/tmc54CqwA+bfhbtEfZUNLHaPUiB9X3jt1A==", + "dev": true, + "license": "MIT" + }, "node_modules/own-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", @@ -14759,6 +16890,13 @@ "dev": true, "license": "BlueOak-1.0.0" }, + "node_modules/package-manager-detector": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz", + "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==", + "dev": true, + "license": "MIT" + }, "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -14864,6 +17002,16 @@ "dev": true, "license": "MIT" }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/patch-console": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/patch-console/-/patch-console-2.0.0.tgz", @@ -14874,6 +17022,13 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -14937,6 +17092,17 @@ "node": "20 || >=22" } }, + "node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -14953,6 +17119,13 @@ "dev": true, "license": "MIT" }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "dev": true, + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -14995,6 +17168,28 @@ "node": ">=12.13.0" } }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, "node_modules/playwright": { "version": "1.61.1", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.61.1.tgz", @@ -15042,6 +17237,16 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/pngjs": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", @@ -15090,6 +17295,112 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-discard-duplicates": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-7.0.2.tgz", + "integrity": "sha512-eTonaQvPZ/3i1ASDHOKkYwAybiM45zFIc7KXils4mQmHLqIswXD9XNOKEVxtTFnsmwYzF66u4LMgSr0abDlh5w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-discard-empty": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-7.0.1.tgz", + "integrity": "sha512-cFrJKZvcg/uxB6Ijr4l6qmn3pXQBna9zyrPC+sK0zjbkDUZew+6xDltSF7OeB7rAtzaaMVYSdbod+sZOCWnMOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-7.0.5.tgz", + "integrity": "sha512-x2/IvofHcdIrAm9Q+p06ZD1h6FPcQ32WtCRVodJLDR+WMn8EVHI1kvLxZuGKz/9EY5nAmI6lIQIrpo4tBy5+ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "postcss-selector-parser": "^7.1.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-nested": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-7.0.2.tgz", + "integrity": "sha512-5osppouFc0VR9/VYzYxO03VaDa3e8F23Kfd6/9qcZTUI8P58GIYlArOET2Wq0ywSl2o2PjELhYOFI4W7l5QHKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-7.0.1.tgz", + "integrity": "sha512-vsbgFHMFQrJBJKrUFJNZ2pgBeBkC2IvvoHjz1to0/0Xk7sII24T0qFOiJzG6Fu3zJoq/0yI4rKWi7WhApW+EFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-selector-parser": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.4.tgz", + "integrity": "sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -15229,6 +17540,20 @@ "node": ">=12.0.0" } }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -15255,6 +17580,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/qs": { + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -15289,6 +17631,36 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/range-parser": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz", + "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -15334,6 +17706,45 @@ "node": ">=0.10.0" } }, + "node_modules/react-aria": { + "version": "3.50.0", + "resolved": "https://registry.npmjs.org/react-aria/-/react-aria-3.50.0.tgz", + "integrity": "sha512-S0Os6QZk33fzUAKu1QLT9afoUaCBt1ZNdoiq0n2YMVgKIdNIQS8zxiZ8O9hYE6QyDkHKjD6q39LQZ+qaSAIgjw==", + "license": "Apache-2.0", + "dependencies": { + "@internationalized/date": "^3.12.2", + "@internationalized/number": "^3.6.7", + "@internationalized/string": "^3.2.9", + "@react-types/shared": "^3.36.0", + "@swc/helpers": "^0.5.0", + "aria-hidden": "^1.2.3", + "clsx": "^2.0.0", + "react-stately": "3.48.0", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/react-aria-components": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/react-aria-components/-/react-aria-components-1.19.0.tgz", + "integrity": "sha512-2smSS5nqJ8cGYMQezuUXveZm7eMyHCqTN6mDpylQBYLYbdF5dxCCuW1DHn1VKLe1DybSfPvX/cZtJlDmvFfn8A==", + "license": "Apache-2.0", + "dependencies": { + "@internationalized/date": "^3.12.2", + "@react-types/shared": "^3.36.0", + "@swc/helpers": "^0.5.0", + "client-only": "^0.0.1", + "react-aria": "3.50.0", + "react-stately": "3.48.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, "node_modules/react-clientside-effect": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/react-clientside-effect/-/react-clientside-effect-1.2.8.tgz", @@ -15513,6 +17924,23 @@ } } }, + "node_modules/react-stately": { + "version": "3.48.0", + "resolved": "https://registry.npmjs.org/react-stately/-/react-stately-3.48.0.tgz", + "integrity": "sha512-ImicSAG+lTotAe5izcs1fz49Zk48w7pDusqYg04WaPhCoej8BJ24soMu3iLXIrsi273s4P1gZrYGrqReMfgEEA==", + "license": "Apache-2.0", + "dependencies": { + "@internationalized/date": "^3.12.2", + "@internationalized/number": "^3.6.7", + "@internationalized/string": "^3.2.9", + "@react-types/shared": "^3.36.0", + "@swc/helpers": "^0.5.0", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, "node_modules/react-style-singleton": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", @@ -15775,8 +18203,18 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "license": "MIT", - "engines": { - "node": ">=4" + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, "node_modules/responselike": { @@ -15944,6 +18382,23 @@ "fsevents": "~2.3.2" } }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/run-applescript": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", @@ -16057,6 +18512,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, "node_modules/sax": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", @@ -16132,6 +18594,60 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/send/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/send/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/serialize-javascript": { "version": "7.0.7", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.0.7.tgz", @@ -16142,6 +18658,26 @@ "node": ">=20.0.0" } }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -16191,6 +18727,13 @@ "node": ">= 0.4" } }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -16506,6 +19049,16 @@ "dev": true, "license": "MIT" }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/std-env": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", @@ -16854,6 +19407,103 @@ "dev": true, "license": "MIT" }, + "node_modules/table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/table/node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/table/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/temp-dir": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", @@ -17179,6 +19829,16 @@ "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==", "license": "MIT" }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, "node_modules/token-types": { "version": "6.1.2", "resolved": "https://registry.npmjs.org/token-types/-/token-types-6.1.2.tgz", @@ -17237,6 +19897,52 @@ "typescript": ">=4.8.4" } }, + "node_modules/ts-evaluator": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ts-evaluator/-/ts-evaluator-1.2.0.tgz", + "integrity": "sha512-ncSGek1p92bj2ifB7s9UBgryHCkU9vwC5d+Lplt12gT9DH+e41X8dMoHRQjIMeAvyG7j9dEnuHmwgOtuRIQL+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.3", + "crosspath": "^2.0.0", + "object-path": "^0.11.8" + }, + "engines": { + "node": ">=14.19.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/wessberg/ts-evaluator?sponsor=1" + }, + "peerDependencies": { + "jsdom": ">=14.x || >=15.x || >=16.x || >=17.x || >=18.x || >=19.x || >=20.x || >=21.x || >=22.x", + "typescript": ">=3.2.x || >= 4.x || >= 5.x" + }, + "peerDependenciesMeta": { + "jsdom": { + "optional": true + } + } + }, + "node_modules/ts-morph": { + "version": "28.0.0", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-28.0.0.tgz", + "integrity": "sha512-Wp3tnZ2bzwxyTZMtgWVzXDfm7lB1Drz+y9DmmYH/L702PQhPyVrp3pkou3yIz4qjS14GY9kcpmLiOOMvl8oG1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ts-morph/common": "~0.29.0", + "code-block-writer": "^13.0.3" + } + }, + "node_modules/ts-pattern": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/ts-pattern/-/ts-pattern-5.9.0.tgz", + "integrity": "sha512-6s5V71mX8qBUmlgbrfL33xDUwO0fq48rxAu2LBE11WBeGdpCPOsXksQbZJHvHwhrd3QjUusd3mAOM5Gg0mFBLg==", + "dev": true, + "license": "MIT" + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -17269,6 +19975,66 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/type-is": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", + "dev": true, + "license": "MIT", + "dependencies": { + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/typed-array-buffer": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", @@ -17512,6 +20278,16 @@ "node": ">= 10.0.0" } }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/upath": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", @@ -17649,6 +20425,15 @@ } } }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/utif2": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/utif2/-/utif2-4.1.0.tgz", @@ -17680,6 +20465,16 @@ "uuid": "dist-node/bin/uuid" } }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/vite": { "version": "7.3.6", "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz", @@ -18657,6 +21452,16 @@ "node": ">=0.10.0" } }, + "node_modules/wordwrapjs": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-5.1.1.tgz", + "integrity": "sha512-0yweIbkINJodk27gX9LBGMzyQdBDan3s/dEAiwBOj+Mf0PPyWL6/rikalkv8EeD0E8jm4o5RXEOrFTP3NXbhJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.17" + } + }, "node_modules/workbox-background-sync": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-7.4.1.tgz", @@ -19327,6 +22132,16 @@ "funding": { "url": "https://github.com/sponsors/colinhacks" } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.2", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "dev": true, + "license": "ISC", + "peerDependencies": { + "zod": "^3.25.28 || ^4" + } } } } diff --git a/package.json b/package.json index 83d4144fc..0e9c4a30a 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", "@microbit/microbit-connection": "^1.0.0", + "@microbit/ui": "file:../ui/packages/ui", "@microbit/microbit-fs": "^0.10.0", "@sanity/block-content-to-react": "^3.0.0", "@sanity/image-url": "^1.0.1", @@ -50,6 +51,7 @@ "marked": "^4.0.15", "mobile-drag-drop": "^2.3.0-rc.2", "react": "^18.3.1", + "react-aria-components": "^1.19.0", "react-dom": "^18.3.1", "react-hotkeys-hook": "^4.5.0", "react-icons": "^4.12.0", @@ -63,7 +65,9 @@ }, "devDependencies": { "@chakra-ui/cli": "2.5.8", + "@csstools/postcss-cascade-layers": "^6.0.0", "@formatjs/cli": "^6.2.7", + "@pandacss/dev": "^1.11.4", "@playwright/test": "^1.58.2", "@testing-library/jest-dom": "^5.14.1", "@testing-library/react": "^14.0.0", @@ -93,6 +97,7 @@ }, "scripts": { "build": "vite build", + "prebuild": "npm run panda", "ci:update-version": "update-ci-version", "ci": "npm run typecheck && npm run test && npm run lint && npm run build", "deploy": "website-deploy-aws", @@ -102,13 +107,18 @@ "invalidate": "aws cloudfront create-invalidation --distribution-id $(printenv ${STAGE}_CLOUDFRONT_DISTRIBUTION_ID) --paths \"/*\"", "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "postinstall": "npm run theme", + "prepare": "npm run panda", + "panda": "panda codegen && panda cssgen --outfile src/styled-system.css && node ../ui/bin/unlayer-panda.mjs", + "panda:watch": "node ../ui/bin/panda-dev.mjs", "serve": "npx serve --no-clipboard -l 3000 -- build/", + "prestart": "npm run panda", "start": "vite dev", "test:e2e:headless": "playwright test", "test:e2e": "playwright test --ui", "test": "vitest", "theme:watch": "chakra-cli tokens src/deployment/default/theme.ts --watch", "theme": "chakra-cli tokens src/deployment/default/theme.ts", + "pretypecheck": "npm run panda", "typecheck": "tsc --noEmit", "typecheck:watch": "tsc --noEmit --watch" }, diff --git a/panda.config.ts b/panda.config.ts new file mode 100644 index 000000000..86b1504f5 --- /dev/null +++ b/panda.config.ts @@ -0,0 +1,57 @@ +/** + * (c) 2026, Micro:bit Educational Foundation and contributors + * + * SPDX-License-Identifier: MIT + */ +import { basePreset } from "@microbit/ui/base-preset"; +import { defineConfig } from "@pandacss/dev"; +import { appPreset } from "./src/deployment/default/panda-preset"; + +// Optionally pull in the private brand preset, mirroring the `theme-package` +// alias swap in vite.config.ts. When the private package is installed it +// overrides brand tokens (colour ramps, code palette, semantic tokens); +// otherwise the OSS default preset stands alone. Panda merges them at codegen +// time — the build-time equivalent of Chakra's runtime theme swap. +// +// Panda loads this config as CommonJS, so `require` is the real (sync) require; +// Node 24 resolves the ESM private package through it. +let brandPreset: unknown; +try { + // eslint-disable-next-line @typescript-eslint/no-require-imports + const mod = require("@microbit-foundation/python-editor-v3-microbit/panda-preset"); + brandPreset = (mod as { default: unknown }).default; +} catch { + brandPreset = undefined; +} + +export default defineConfig({ + // Coexistence: Chakra's global reset is still active, so keep Panda's + // preflight off until the kill-switch. During coexistence the CSS is produced + // by `panda cssgen` + unlayering (see the `panda` script), not the + // PostCSS/layers injection — Chakra/Emotion inject unlayered styles that would + // otherwise beat Panda's layered rules (see ../ui/bin/unlayer-panda.mjs). + preflight: false, + jsxFramework: "react", + // Drop Panda's default theme preset; the preset stack below supplies the full + // token system (ported from Chakra). preset-base still provides the utilities. + eject: true, + // Later presets override earlier ones: @microbit/ui's base preset (the + // complete design system + recipes, OSS default brand values), this app's + // own preset, then the optional private brand preset which overrides the OSS + // brand values. staticCss lives in the base preset. + presets: [ + "@pandacss/preset-base", + basePreset, + appPreset, + ...(brandPreset ? [brandPreset] : []), + ], + include: [ + "./src/**/*.{ts,tsx}", + // @microbit/ui ships as source; include it so Panda extracts the styles its + // components use. A glob that matches nothing fails silently (recipe styling + // still works via the preset's staticCss), so a wrong path shows up only as + // broken non-recipe styling — check the resolved node_modules path. + "./node_modules/@microbit/ui/src/**/*.{ts,tsx}", + ], + outdir: "styled-system", +}); diff --git a/postcss.config.cjs b/postcss.config.cjs new file mode 100644 index 000000000..717befd75 --- /dev/null +++ b/postcss.config.cjs @@ -0,0 +1,39 @@ +/* + * (c) 2026, Micro:bit Educational Foundation and contributors + * + * SPDX-License-Identifier: MIT + * + * PostCSS runs because vite.config.ts keeps Vite's default CSS transformer + * (not lightningcss, which would disable PostCSS). + * + * This app targets Safari/iOS 14 (see package.json "browserslist"), below the + * 15.4 floor where Panda's output works natively, so two TEMPORARY downleveling + * plugins run in PRODUCTION builds only (dev browsers are modern, and the + * flattened @layer output makes devtools tracing painful). Drop both — and + * raise the vite.config.ts build target — once support rises past those + * browsers. + * + * 1. expandLogicalShorthands (@microbit/ui/postcss-legacy-safari) — Safari 14.x + * silently drops logical *shorthands* whose value contains var() + * (`padding-inline: var(--…)` applies nothing). Panda emits these for its + * px/py/mx/my utilities. Expands each into its logical -start/-end longhands + * (which work), so RTL still flips. + * 2. @csstools/postcss-cascade-layers — Safari <15.4 drops @layer wholesale. + * A no-op during Chakra coexistence (the generated CSS is unlayered by + * ../ui/bin/unlayer-panda.mjs), but needed once layers return at the + * kill-switch. + * + * At the kill-switch, add `require("@pandacss/dev/postcss")()` as the FIRST + * plugin (it replaces the `panda cssgen` step) and drop the cssgen/unlayer + * wiring from package.json. + */ +const { + expandLogicalShorthands, +} = require("@microbit/ui/postcss-legacy-safari"); + +module.exports = (ctx) => ({ + plugins: + ctx.env === "production" + ? [expandLogicalShorthands(), require("@csstools/postcss-cascade-layers")] + : [], +}); diff --git a/src/deployment/default/panda-preset.ts b/src/deployment/default/panda-preset.ts new file mode 100644 index 000000000..41fd5bcb7 --- /dev/null +++ b/src/deployment/default/panda-preset.ts @@ -0,0 +1,64 @@ +/** + * (c) 2026, Micro:bit Educational Foundation and contributors + * + * SPDX-License-Identifier: MIT + */ +import { definePreset } from "@pandacss/dev"; + +/** + * The python-editor OSS app preset: this app's own styling decisions, merged + * after the shared-ui base preset (@microbit/ui) and before the optional + * private brand preset (see panda.config.ts). Kept minimal — the base preset + * already supplies the token scales, recipes, `radii.button`, focus shadows, + * Helvetica fonts and most semantic tokens. + * + * Values mirror the OSS Chakra theme (src/deployment/default) as converged + * during the semantic-token pre-work; the private brand preset overrides the + * brand-divergent token values. + */ +export const appPreset = definePreset({ + name: "python-editor-v3", + theme: { + extend: { + tokens: { + colors: { + // Syntax-highlight / code-block palette. Consumed outside React as + // CSS vars (CodeMirror highlight styles, structure highlighting), so + // it's an app-preset token category; the private preset overrides the + // values. OSS values are the Chakra defaults the old theme resolved. + code: { + blockBorder: { value: "#A0AEC0" }, // gray.400 + blockBackground: { value: "rgba(185, 185, 185, 0.1)" }, + blockBackgroundActive: { value: "rgba(255, 255, 237, 0.5)" }, + blockBorderActive: { value: "#4299e1" }, // blue.400 + comment: { value: "gray" }, + default: { value: "black" }, + keyword: { value: "darkblue" }, + literal: { value: "darkgreen" }, + string: { value: "green" }, + activeLine: { value: "#EDF2F7" }, // gray.100 + error: { value: "#E53E3E" }, // red.500 (matches default error toast) + }, + }, + }, + semanticTokens: { + colors: { + // Sidebar chrome: Container `sidebar-header` bg + the Tabs `sidebar` + // variant. OSS is flat black; the private preset uses brand colours / + // a gradient (see the private panda-preset). + sidebarHeaderBg: { value: "black" }, + sidebarTablistBg: { value: "black" }, + sidebarTabSelectedText: { value: "black" }, + sidebarTabSelectedBg: { value: "{colors.gray.50}" }, + // Button `language` variant text. The base preset defaults these to + // the grey brand2 ramp; python-editor uses the primary brand ramp, so + // the brand divergence flows through the brand ramp values. + languageText: { value: "{colors.brand.500}" }, + languageTextHover: { value: "{colors.brand.600}" }, + }, + }, + }, + }, +}); + +export default appPreset; diff --git a/src/index.tsx b/src/index.tsx index b5a372ef7..7406b4d2a 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -3,6 +3,10 @@ * * SPDX-License-Identifier: MIT */ +// Panda CSS (generated). Imported first so app/Chakra styles cascade after it. +// During Chakra coexistence this is the unlayered `panda cssgen` output (see +// the `panda` script); at the kill-switch it moves to the PostCSS/layers form. +import "./styled-system.css"; import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import App from "./App"; diff --git a/tsconfig.json b/tsconfig.json index 42339fc0a..01acfd8bf 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,6 +8,10 @@ /* Bundler mode */ "moduleResolution": "bundler", + "baseUrl": ".", + "paths": { + "styled-system/*": ["./styled-system/*"] + }, "allowImportingTsExtensions": true, "resolveJsonModule": true, "isolatedModules": true, diff --git a/tsconfig.node.json b/tsconfig.node.json index 42872c59f..adc05cd1e 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -6,5 +6,5 @@ "moduleResolution": "bundler", "allowSyntheticDefaultImports": true }, - "include": ["vite.config.ts"] + "include": ["vite.config.ts", "panda.config.ts"] } diff --git a/vite.config.ts b/vite.config.ts index 01e270f96..2cdc97650 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -205,6 +205,10 @@ export default defineConfig(({ mode }) => { "theme-package": fs.existsSync(external) ? theme : path.resolve(__dirname, internal), + // Resolve Panda's generated helpers for all importers, including + // @microbit/ui's source (consumed from node_modules). Mirrors the + // tsconfig `paths` entry. + "styled-system": path.resolve(__dirname, "styled-system"), }, }, }; From 85198b48f03fc7566cc3914b4e49cfbfa276be7a Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Mon, 27 Jul 2026 12:06:51 +0000 Subject: [PATCH 007/104] Update RAC migration doc: step 2 Panda foundation done Status-log step 2: preset stack + coexistence CSS wiring, legacy-Safari postcss, verification (panda/typecheck/build/lint clean, app unchanged on Chakra), the section-D differ improvement (base-preset merge; 55->13, residual = known brand-ramp divergence), and the deferral of providers/i18n to step 3. --- RAC-MIGRATION.md | 67 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 7 deletions(-) diff --git a/RAC-MIGRATION.md b/RAC-MIGRATION.md index 5f8f046fd..233fd9d59 100644 --- a/RAC-MIGRATION.md +++ b/RAC-MIGRATION.md @@ -1,12 +1,13 @@ # Chakra → react-aria-components + Panda CSS migration -Status: **semantic-token pre-work done on Chakra (2026-07-27) — all -structural OSS/private divergence converged onto shared component structure + -semantic tokens; differ shows zero structural diffs (only the -`withDefaultColorScheme` `defaultProps` diffs remain, by design). Static -checks green both repos; semantic-token CSS-var emission verified via -`toCSSVar`; sidebar gradient confirmed byte-identical to the live branded -deployment (`python.microbit.org/v/3`). Ready for review/PR.** +Status: **Step 2 (Panda foundation) done on Chakra (2026-07-27) — Panda + +preset stack (`@pandacss/preset-base` → `@microbit/ui/base-preset` → app +preset → private brand preset) installed in coexistence form (`preflight: +false`, cssgen + unlayer). Panda generates; typecheck/build/lint/prettier +green; the app still renders unchanged on Chakra (sidebar gradient still +byte-identical to live). No components ported yet. Pre-work (step 1) complete +before this. Next: step 3 (coexistence porting, area-by-area) — providers + +i18n land with the first shared component.** Method: follow the **migration playbook** in the `@microbit/ui` monorepo (`../ui/docs/migration-playbook.md`) — the sequence, the gotcha catalog @@ -337,6 +338,58 @@ Chakra Heading (they compose Text). with credentials (env userinfo alone → 407, bypass loopback for the local server), and vite dev needs `CI=true` (+ same-command lifetime) to stay up. +- 2026-07-27 (step 2 — Panda foundation): **installed the Panda + preset + stack in coexistence form; app unchanged on Chakra.** No components ported. + - **Consumption:** `@microbit/ui` linked via `file:../ui/packages/ui` (it + ships as source); survives installs. The private brand preset is consumed + through the existing `node_modules/@microbit-foundation/python-editor-v3-microbit` + symlink (manual — re-create after `npm install`, it's not a dep). + - **Presets:** `panda.config.ts` (`eject: true`, `preflight: false`, + `jsxFramework: react`, include app + `@microbit/ui/src`); app preset + `src/deployment/default/panda-preset.ts` (the `code.*` palette + the + sidebar/language semantic tokens the base preset lacks); private + `src/panda-preset.ts` (brand/purple/teal/blimpTeal/gray ramps, `code.*`, + and the brand-divergent semantic-token overrides — incl. the gradient + `sidebarTablistBg`). Verified via cssgen: `brand.500` → `#6c4bc1`, and the + gradient token interpolates `{colors…}` refs into + `linear-gradient(var(--colors-brand-500) … var(--colors-blimp-teal-400))`. + - **CSS (coexistence):** `panda` script = `panda codegen && panda cssgen + --outfile src/styled-system.css && node ../ui/bin/unlayer-panda.mjs`; + `panda:watch` = `panda-dev.mjs`; `prestart`/`prebuild`/`pretypecheck`/ + `prepare` regenerate. `styled-system.css` imported first in + `src/index.tsx`. `styled-system` alias in tsconfig `paths` + vite. Output + git/eslint/prettier-ignored; `panda.config.ts` added to + `tsconfig.node.json`. + - **Legacy Safari (required — targets Safari/iOS 14):** `postcss.config.cjs` + runs `@microbit/ui/postcss-legacy-safari` (`expandLogicalShorthands`) + + `@csstools/postcss-cascade-layers` in production only. Kept esbuild as the + CSS minifier (existing `build.target` already pins the legacy floor), so no + minifier switch was needed. At the kill-switch, prepend + `@pandacss/dev/postcss` and drop the cssgen/unlayer wiring. + - **Providers + i18n: deferred to step 3.** Nothing imports `@microbit/ui` + at runtime yet (only the build-time base preset + postcss plugin), so + `ToastProvider` and the `@microbit/ui` catalog compile land with the first + shared component port, keeping this foundation behaviour-neutral. + - **Verification:** `npm run panda` clean; `tsc --noEmit` clean (the two old + codemirror errors vanished after the node_modules reinstall — dep bump); + `npm run build` clean (8.9s); lint + prettier clean; headless re-render of + the branded app shows the sidebar gradient unchanged. Two benign + `sheet:process` empty-rule warnings during cssgen (extraction artifacts; + the emitted CSS is clean) — likely gotcha #17 territory to tidy during + porting. + - **Differ improvement (`../ui`):** section D (Panda cross-check) now loads + and deep-merges `@microbit/ui/base-preset`, so OSS tokens resolve as base + ⊕ app (private as base ⊕ app ⊕ private) — without this, base-provided + ramps read as `undefined` and false-mismatch. Result here: 55 → 13 + mismatches. The private (branded) `brand.100–800`/gray/teal/purple/code + values all verify. The residual 13 are known and not preset bugs: the + OSS-side `brand` reads blue (the family base default) vs the old OSS + `brand`=gray, plus the parked brand-ramp shape asymmetry at + `brand.10/25/50/900`, plus one whole-ramp differ artifact for `blimpTeal` + (exists only in the private theme). Sandbox note: run needs Chromium + pointed at the auth proxy and a `node_modules` reinstall for + platform-native binaries (see the earlier fidelity notes). + ## Notes to revisit later Parked items surfaced during pre-work — out of scope for the convergence From 5dd5f2a97310983ab8d4b0f45a195826c925a0c5 Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Mon, 27 Jul 2026 12:37:05 +0000 Subject: [PATCH 008/104] Port ConfirmDialog to @microbit/ui (first coexistence port) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RAC/Panda migration step 3, pilot area. Replace Chakra AlertDialog/Button/Text with @microbit/ui Modal(role=alertdialog)+Button; onClick->onPress; cancel = default (outline), destructive = warningSolid. Drop leastDestructiveRef (gotcha #15) for autoFocus on cancel. - App preset: add python-editor's outline button variant + defaultVariants (outline), the census-flagged per-app default (base recipe defaults to secondary). staticCss [*] covers it. - vite resolve.dedupe for react/react-dom/react-aria-* — @microbit/ui is dev-linked as source, so its react imports otherwise resolve to the ui monorepo copy (two Reacts -> invalid-hook crash; gotcha #19). Verified byte-identical to live python.microbit.org/v/3: cancel brand.500 outline, replace white-on-red.500, both pill radius. --- src/common/ConfirmDialog.tsx | 62 +++++++++----------------- src/deployment/default/panda-preset.ts | 22 +++++++++ vite.config.ts | 11 +++++ 3 files changed, 55 insertions(+), 40 deletions(-) diff --git a/src/common/ConfirmDialog.tsx b/src/common/ConfirmDialog.tsx index c057e794f..807c3c292 100644 --- a/src/common/ConfirmDialog.tsx +++ b/src/common/ConfirmDialog.tsx @@ -4,16 +4,13 @@ * SPDX-License-Identifier: MIT */ import { - AlertDialog, - AlertDialogBody, - AlertDialogContent, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogOverlay, Button, - Text, -} from "@chakra-ui/react"; -import { ReactNode, useRef } from "react"; + Modal, + ModalBody, + ModalFooter, + ModalHeader, +} from "@microbit/ui"; +import { ReactNode } from "react"; import { FormattedMessage } from "react-intl"; export interface ConfirmDialogProps { @@ -32,37 +29,22 @@ export const ConfirmDialog = ({ actionLabel, callback, }: ConfirmDialogProps) => { - const leastDestructiveRef = useRef(null); return ( - callback(false)} - preserveScrollBarGap={false} - > - - - - - {header} - - - {body} - - - - - - - + callback(false)}> + + {header} + + {body} + + {/* Least-destructive initial focus: RAC honours autoFocus within the + dialog's FocusScope, replacing Chakra's leastDestructiveRef. */} + + + + ); }; diff --git a/src/deployment/default/panda-preset.ts b/src/deployment/default/panda-preset.ts index 41fd5bcb7..b5cd5f752 100644 --- a/src/deployment/default/panda-preset.ts +++ b/src/deployment/default/panda-preset.ts @@ -57,6 +57,28 @@ export const appPreset = definePreset({ languageTextHover: { value: "{colors.brand.600}" }, }, }, + recipes: { + // python-editor's default button variant is `outline` (census: the + // OSS theme applies withDefaultVariant("outline"); the family base + // recipe defaults to `secondary`). Ported from the Chakra `outline` + // variant, resolved at the brand colorScheme (the app applies + // withDefaultColorScheme("brand")): brand text over a transparent, + // brand-bordered button. Non-brand outline cases use `warning`. + button: { + variants: { + variant: { + outline: { + borderWidth: "2px", + borderColor: "currentColor", + color: "brand.500", + bg: "transparent", + _hover: { color: "brand.600", bg: "transparent" }, + }, + }, + }, + defaultVariants: { variant: "outline" }, + }, + }, }, }, }); diff --git a/vite.config.ts b/vite.config.ts index 2cdc97650..ffdcab8a2 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -210,6 +210,17 @@ export default defineConfig(({ mode }) => { // tsconfig `paths` entry. "styled-system": path.resolve(__dirname, "styled-system"), }, + // @microbit/ui is consumed as source via a file: symlink, so its + // `import "react"` etc. would otherwise resolve to the ui monorepo's own + // copies — two Reacts → invalid-hook "useContext of null" crashes. Force + // a single copy (the app's) for React and the react-aria stack. + dedupe: [ + "react", + "react-dom", + "react-aria-components", + "react-aria", + "react-stately", + ], }, }; return config; From d4ae21cac393a02d51d0c64e16cae97adddde110 Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Mon, 27 Jul 2026 12:37:11 +0000 Subject: [PATCH 009/104] Update RAC migration doc: step 3 started, ConfirmDialog pilot Log the first coexistence port (ConfirmDialog -> @microbit/ui Modal), the per-app outline button default, gotcha #19 (dual React from dev-linking), and the byte-identical-to-live verification. --- RAC-MIGRATION.md | 52 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/RAC-MIGRATION.md b/RAC-MIGRATION.md index 233fd9d59..1b4ebb63f 100644 --- a/RAC-MIGRATION.md +++ b/RAC-MIGRATION.md @@ -1,13 +1,10 @@ # Chakra → react-aria-components + Panda CSS migration -Status: **Step 2 (Panda foundation) done on Chakra (2026-07-27) — Panda + -preset stack (`@pandacss/preset-base` → `@microbit/ui/base-preset` → app -preset → private brand preset) installed in coexistence form (`preflight: -false`, cssgen + unlayer). Panda generates; typecheck/build/lint/prettier -green; the app still renders unchanged on Chakra (sidebar gradient still -byte-identical to live). No components ported yet. Pre-work (step 1) complete -before this. Next: step 3 (coexistence porting, area-by-area) — providers + -i18n land with the first shared component.** +Status: **Step 3 (coexistence porting) started (2026-07-27) — pilot port +`common/ConfirmDialog.tsx` onto `@microbit/ui` Modal (alertdialog) + Button, +verified byte-identical to the live branded deployment. Steps 1 (semantic- +token pre-work) and 2 (Panda foundation) complete. Porting continues +area-by-area.** Method: follow the **migration playbook** in the `@microbit/ui` monorepo (`../ui/docs/migration-playbook.md`) — the sequence, the gotcha catalog @@ -390,6 +387,45 @@ Chakra Heading (they compose Text). pointed at the auth proxy and a `node_modules` reinstall for platform-native binaries (see the earlier fidelity notes). +- 2026-07-27 (step 3 — first port, pilot): **`common/ConfirmDialog.tsx` + ported to `@microbit/ui`; renders byte-identical to live.** Established the + porting pattern and shook out one critical integration gotcha. + - **The port:** Chakra `AlertDialog`/`Button`/`Text` → `@microbit/ui` + `Modal` (`role="alertdialog"`, controlled `isOpen`) + `ModalHeader`/ + `ModalBody`/`ModalFooter` + `Button`. `onClick` → RAC `onPress`. Cancel = + default variant (now `outline`); destructive = `variant="warningSolid"` + (the base recipe's danger-solid). Dropped the `leastDestructiveRef` focus + machinery (gotcha #15) — least-destructive initial focus is now + `autoFocus` on the cancel button (RAC's FocusScope honours it). Header + `fontSize`/`level` set via css to match the old `Text as="h2" lg bold`. + - **App preset button vocabulary (deferred from step 2, done here):** added + python-editor's `outline` variant to the app preset's button recipe and + set `defaultVariants.variant: "outline"` (census: OSS applies + `withDefaultVariant("outline")`; the base recipe defaults to `secondary`). + Verified the base `staticCss: { button: ["*"] }` covers the app-added + variant (no extra staticCss needed). + - **Gotcha #19 (new — dual React from dev-linking):** the ported dialog + crashed at runtime (`useContext of null`) because `@microbit/ui` is + consumed via `file:` symlink, so its `import "react"` resolved to the ui + monorepo's copy — two Reacts. Fixed with `resolve.dedupe: ["react", + "react-dom", "react-aria-components", "react-aria", "react-stately"]` in + `vite.config.ts`. Typecheck + build passed regardless (runtime-only); + added to the playbook gotcha catalog. A published package wouldn't hit it. + - **Verified:** typecheck/build clean; drove the confirm-replace dialog + (type → Project tab → Reset project) headless on the local branded build + and live `python.microbit.org/v/3`. Both buttons byte-identical: Cancel + `rgb(108,75,193)` (brand.500) 2px outline, Replace white-on- + `rgb(229,62,62)` (red.500/danger), both 32px pill radius; layout matches. + - **Minor, accepted:** the library's dialog footer uses a house-style + `gap: 5` vs the old `ml={3}` — a slightly wider button gap, standardised + across dialogs; visually within tolerance (override per-site if needed). + - **Providers:** none needed yet — ConfirmDialog doesn't toast, and Modal's + intl (close label) uses the existing `IntlProvider`. `ToastProvider` + + `@microbit/ui` catalog compile still land with the first toast-using port. + - Sandbox notes for re-running the visual check: `resolve.dedupe` requires + clearing `node_modules/.vite` once; live needs the cookie-consent **and** + welcome dialogs dismissed before driving the flow (local shows neither). + ## Notes to revisit later Parked items surfaced during pre-work — out of scope for the convergence From 2a58f9c96ce38205242eb293e20cd10f383dcefe Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Mon, 27 Jul 2026 13:00:40 +0000 Subject: [PATCH 010/104] Port GenericDialog shell + footer to @microbit/ui Modal RAC/Panda migration step 3, dialog infrastructure. The shared GenericDialog (shell for 8 dialogs) and GenericDialogFooter move onto @microbit/ui Modal + Button + Panda HStack. Props API preserved, so the consumer dialogs are untouched and render their (still-Chakra) content inside the RAC Modal during coexistence. - Modal/ModalOverlay/ModalContent -> Modal + ModalCloseButton/Header/Body/ Footer; minWidth via contentCss + isCentered. - returnFocusOnClose is now a no-op (RAC restores focus; gotcha #15), kept for API compat; finalFocusRef still wired. - Footer: HStack from styled-system/jsx; don't-show-again Link->Button variant=link; close solid->primary. Verified typecheck/build clean and the PostSaveDialog (exercises shell + footer) visually identical to live python.microbit.org/v/3. --- src/common/GenericDialog.tsx | 61 ++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/src/common/GenericDialog.tsx b/src/common/GenericDialog.tsx index e1670b488..5466bd780 100644 --- a/src/common/GenericDialog.tsx +++ b/src/common/GenericDialog.tsx @@ -5,28 +5,29 @@ */ import { Button, - HStack, - Link, Modal, ModalBody, - ModalContent, + ModalCloseButton, ModalFooter, ModalHeader, - ModalOverlay, - Text, -} from "@chakra-ui/react"; -import { ThemingProps } from "@chakra-ui/styled-system"; + ModalSize, +} from "@microbit/ui"; import { ReactNode } from "react"; import { FormattedMessage } from "react-intl"; -import ModalCloseButton from "./ModalCloseButton"; +import { HStack } from "styled-system/jsx"; import { FinalFocusRef } from "../project/project-actions"; export interface GenericDialogProps { header?: ReactNode; body: ReactNode; footer: ReactNode; - size?: ThemingProps<"Button">["size"]; + size?: ModalSize; onClose: () => void; + /** + * Accepted for API compatibility but no longer wired: react-aria restores + * focus to the trigger on close by default (see the migration playbook, + * gotcha #15). Use `finalFocusRef` to redirect focus explicitly. + */ returnFocusOnClose?: boolean; finalFocusRef?: FinalFocusRef; } @@ -37,7 +38,6 @@ export const GenericDialog = ({ footer, size, onClose, - returnFocusOnClose = true, finalFocusRef = undefined, }: GenericDialogProps) => { return ( @@ -45,24 +45,18 @@ export const GenericDialog = ({ isOpen onClose={onClose} size={size} - returnFocusOnClose={returnFocusOnClose} + isCentered finalFocusRef={finalFocusRef} - preserveScrollBarGap={false} + contentCss={{ minWidth: "560px" }} > - - - - {header && ( - - - {header} - - - )} - {body} - {footer} - - + + {header && ( + + {header} + + )} + {body} + {footer} ); }; @@ -82,20 +76,19 @@ export const GenericDialogFooter = ({ }: GenericDialogFooterProps) => { return ( {!dialogNormallyHidden && !shownByRequest && ( - - + )} - From 9297b23b74ee12f35f18b186a9ba15a28f78df42 Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Mon, 27 Jul 2026 13:00:40 +0000 Subject: [PATCH 011/104] Update RAC migration doc: GenericDialog ported --- RAC-MIGRATION.md | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/RAC-MIGRATION.md b/RAC-MIGRATION.md index 1b4ebb63f..a28ba0670 100644 --- a/RAC-MIGRATION.md +++ b/RAC-MIGRATION.md @@ -1,9 +1,9 @@ # Chakra → react-aria-components + Panda CSS migration -Status: **Step 3 (coexistence porting) started (2026-07-27) — pilot port -`common/ConfirmDialog.tsx` onto `@microbit/ui` Modal (alertdialog) + Button, -verified byte-identical to the live branded deployment. Steps 1 (semantic- -token pre-work) and 2 (Panda foundation) complete. Porting continues +Status: **Step 3 (coexistence porting) in progress (2026-07-27) — dialog +infrastructure ported to `@microbit/ui` Modal: `ConfirmDialog` (pilot) and +the shared `GenericDialog` shell/footer (used by 8 dialogs), both verified +against the live branded deployment. Steps 1–2 complete. Porting continues area-by-area.** Method: follow the **migration playbook** in the `@microbit/ui` monorepo @@ -426,6 +426,38 @@ Chakra Heading (they compose Text). clearing `node_modules/.vite` once; live needs the cookie-consent **and** welcome dialogs dismissed before driving the flow (local shows neither). +- 2026-07-27 (step 3 — dialog infrastructure): **ported the shared + `common/GenericDialog.tsx` shell + `GenericDialogFooter` onto `@microbit/ui` + Modal; the 8 consumer dialogs are untouched and render through it.** + - **Shell:** Chakra `Modal`/`ModalOverlay`/`ModalContent` → `@microbit/ui` + `Modal` + `ModalCloseButton`/`ModalHeader`/`ModalBody`/`ModalFooter`. + Props API preserved (`header`/`body`/`footer`/`size`/`onClose`/ + `finalFocusRef`), so the consumers pass their still-Chakra content + unchanged — it renders inside the RAC Modal fine during coexistence. + `ModalContent minWidth 560px my="auto"` → `contentCss={{ minWidth }}` + + `isCentered`. `size` typed as `ModalSize`. + - **`returnFocusOnClose` is now a no-op** (kept in the props for API compat): + RAC restores focus to the trigger by default (gotcha #15); `finalFocusRef` + redirects it. Two consumers (NotFoundDialog, FirmwareDialog) still pass it; + behaviour to spot-check if focus-return matters there. + - **Footer:** `HStack` → Panda `styled-system/jsx` `HStack` (layout is Panda + patterns now); the "don't show again" `Link as="button"` → `Button + variant="link"` (css `color: brand.500`); the close `Button variant="solid"` + → `variant="primary"`. + - **Verified:** typecheck/build clean; `css`-prop + `HStack` styles confirmed + present in the generated CSS (no gotcha #9 silent miss). Drove the + PostSaveDialog (Save → name dialog → "Project saved", which exercises both + the shell and `GenericDialogFooter`) headless on local branded vs live + `python.microbit.org/v/3` — visually identical (header, body + purple + "follow these steps" link, footer link + primary Close; ~5px vertical + offset from `isCentered`, negligible). No console errors. + - En route, confirmed the still-Chakra `InputDialog` ("Name your project") + renders correctly in coexistence — good coexistence signal. + - Build warning noted: an esbuild CSS-minifier `Expected identifier but + found "0"` on the sidebar-gradient background shorthand; the gradient + itself already renders byte-identical to live (step 2), so cosmetic — keep + an eye on it at the kill-switch when CSS handling changes. + ## Notes to revisit later Parked items surfaced during pre-work — out of scope for the convergence From 1354af935b144eef05b477389655b4b804a931b4 Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Mon, 27 Jul 2026 13:17:40 +0000 Subject: [PATCH 012/104] Port common dialog contents to @microbit/ui + Panda RAC/Panda migration step 3. Finish the shared common/ dialogs: - PostSaveDialog/MultipleFilesDialog bodies: Chakra VStack/Text/Link -> Panda styled-system/jsx VStack + @microbit/ui Text/Link. - InputDialog: own Modal -> @microbit/ui Modal + Panda styled.form; shared submit() (form onSubmit for Enter, footer Button onPress); primary action, isDisabled when invalid. - ProgressDialog: own Modal -> @microbit/ui Modal + ProgressBar (aria-label from 'loading'); non-dismissable during the operation. Typecheck/build/lint clean; smoke-tested Save -> InputDialog -> PostSaveDialog on the local branded build (renders, no errors, body matches live). --- src/common/InputDialog.tsx | 87 ++++++++++++++---------------- src/common/MultipleFilesDialog.tsx | 9 ++-- src/common/PostSaveDialog.tsx | 10 ++-- src/common/ProgressDialog.tsx | 57 +++++++++----------- 4 files changed, 78 insertions(+), 85 deletions(-) diff --git a/src/common/InputDialog.tsx b/src/common/InputDialog.tsx index 1025b6a08..fd777a4c0 100644 --- a/src/common/InputDialog.tsx +++ b/src/common/InputDialog.tsx @@ -4,20 +4,16 @@ * SPDX-License-Identifier: MIT */ import { - Box, Button, Modal, ModalBody, - ModalContent, ModalFooter, ModalHeader, - ModalOverlay, - Text, - VStack, -} from "@chakra-ui/react"; -import { ThemeTypings } from "@chakra-ui/styled-system"; + ModalSize, +} from "@microbit/ui"; import { ReactNode, useCallback, useState } from "react"; import { FormattedMessage } from "react-intl"; +import { styled, VStack } from "styled-system/jsx"; import { FinalFocusRef } from "../project/project-actions"; export interface InputValidationResult { @@ -40,7 +36,7 @@ export interface InputDialogProps { Body: React.FC>; initialValue: T; actionLabel: string; - size?: ThemeTypings["components"]["Modal"]["sizes"]; + size?: ModalSize; validate?: (input: T) => InputValidationResult; finalFocusRef?: FinalFocusRef; callback: (value: ValueOrCancelled) => void; @@ -65,50 +61,49 @@ export const InputDialog = ({ const [validationResult, setValidationResult] = useState(validate(initialValue)); const onCancel = useCallback(() => callback(undefined), [callback]); - const handleSubmit = (e: React.FormEvent) => { - e.preventDefault(); + const submit = useCallback(() => { if (validationResult.ok) { callback(value); } + }, [validationResult.ok, callback, value]); + const handleFormSubmit = (e: React.FormEvent) => { + e.preventDefault(); + submit(); }; return ( - - - - - - {header} - - - - - - - - - - - - - - - + + + {header} + + + + {/* The form gives Enter-to-submit; the footer button calls submit + directly (it renders outside the form). */} + + + + + + + + + ); }; diff --git a/src/common/MultipleFilesDialog.tsx b/src/common/MultipleFilesDialog.tsx index b14c9bfc8..e1b1333e9 100644 --- a/src/common/MultipleFilesDialog.tsx +++ b/src/common/MultipleFilesDialog.tsx @@ -3,7 +3,8 @@ * * SPDX-License-Identifier: MIT */ -import { Text, VStack } from "@chakra-ui/react"; +import { Text } from "@microbit/ui"; +import { VStack } from "styled-system/jsx"; import { ReactNode } from "react"; import { FormattedMessage } from "react-intl"; import { GenericDialog, GenericDialogFooter } from "../common/GenericDialog"; @@ -49,9 +50,9 @@ const MultipleFilesDialogBody = () => { width="auto" ml="auto" mr="auto" - p={5} - pb={0} - spacing={5} + p="5" + pb="0" + gap="5" alignItems="flex-start" > diff --git a/src/common/PostSaveDialog.tsx b/src/common/PostSaveDialog.tsx index 5fdbcc14e..84cac5b49 100644 --- a/src/common/PostSaveDialog.tsx +++ b/src/common/PostSaveDialog.tsx @@ -3,7 +3,8 @@ * * SPDX-License-Identifier: MIT */ -import { Link, Text, VStack } from "@chakra-ui/react"; +import { Link, Text } from "@microbit/ui"; +import { VStack } from "styled-system/jsx"; import { ReactNode, useCallback } from "react"; import { FormattedMessage } from "react-intl"; import { GenericDialog, GenericDialogFooter } from "../common/GenericDialog"; @@ -71,9 +72,9 @@ const PostSaveDialogBody = ({ width="auto" ml="auto" mr="auto" - p={5} - pb={0} - spacing={5} + p="5" + pb="0" + gap="5" alignItems="flex-start" > @@ -126,6 +127,7 @@ const PostSaveDialogBody = ({ color="brand.500" onClick={handleShowTransferHexHelp} href="" + cursor="pointer" > {chunks} diff --git a/src/common/ProgressDialog.tsx b/src/common/ProgressDialog.tsx index c50c003d3..a849708ac 100644 --- a/src/common/ProgressDialog.tsx +++ b/src/common/ProgressDialog.tsx @@ -3,17 +3,10 @@ * * SPDX-License-Identifier: MIT */ -import { - Modal, - ModalBody, - ModalContent, - ModalHeader, - ModalOverlay, - Progress, - Text, - VStack, -} from "@chakra-ui/react"; +import { Modal, ModalBody, ModalHeader, ProgressBar } from "@microbit/ui"; import { ReactNode } from "react"; +import { useIntl } from "react-intl"; +import { VStack } from "styled-system/jsx"; const doNothing = () => {}; @@ -36,34 +29,36 @@ const ProgressDialog = ({ body, progress, }: ProgressDialogProps) => { + const intl = useIntl(); return ( - - - - - {header} - - - - - {body} - - - - + + {header} + + + + {body} + + + ); }; From 4e9581c8c83f8998d3ba79be016d7878bb39d4d2 Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Mon, 27 Jul 2026 13:17:40 +0000 Subject: [PATCH 013/104] Update RAC migration doc: common dialog contents ported --- RAC-MIGRATION.md | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/RAC-MIGRATION.md b/RAC-MIGRATION.md index a28ba0670..b74de393b 100644 --- a/RAC-MIGRATION.md +++ b/RAC-MIGRATION.md @@ -1,10 +1,11 @@ # Chakra → react-aria-components + Panda CSS migration -Status: **Step 3 (coexistence porting) in progress (2026-07-27) — dialog -infrastructure ported to `@microbit/ui` Modal: `ConfirmDialog` (pilot) and -the shared `GenericDialog` shell/footer (used by 8 dialogs), both verified -against the live branded deployment. Steps 1–2 complete. Porting continues -area-by-area.** +Status: **Step 3 (coexistence porting) in progress (2026-07-27) — the shared +`common/` dialogs are ported to `@microbit/ui`: ConfirmDialog, GenericDialog +(shell for 8), InputDialog, ProgressDialog, PostSaveDialog, MultipleFilesDialog. +Steps 1–2 complete. Verification for later batches is typecheck/build + a +runtime smoke check; full visual pass deferred (per owner) until more is +converted. Porting continues area-by-area.** Method: follow the **migration playbook** in the `@microbit/ui` monorepo (`../ui/docs/migration-playbook.md`) — the sequence, the gotcha catalog @@ -458,6 +459,30 @@ Chakra Heading (they compose Text). itself already renders byte-identical to live (step 2), so cosmetic — keep an eye on it at the kill-switch when CSS handling changes. +- 2026-07-27 (step 3 — common dialog contents): **ported the remaining shared + `common/` dialogs' contents.** Verification bar for this and later batches: + typecheck + build + a runtime smoke check (full visual pass deferred per + owner). + - **PostSaveDialog / MultipleFilesDialog:** bodies only (shell = ported + GenericDialog). Chakra `VStack`/`Text`/`Link` → Panda `styled-system/jsx` + `VStack` + `@microbit/ui` `Text`/`Link`; `spacing`→`gap`, `p={5}`→`p="5"`. + - **InputDialog:** own Modal → `@microbit/ui` Modal + form. `Box as="form"` + → Panda `styled.form`; submit refactored to a shared `submit()` (form + `onSubmit` for Enter; footer Button `onPress` since it renders outside the + form — RAC `onPress`, not a fake FormEvent). Cancel = default (outline), + action = `primary`, `isDisabled` when invalid. `size` typed `ModalSize`. + - **ProgressDialog:** own Modal → `@microbit/ui` Modal + `ProgressBar` + (needs a required `aria-label` — used the `loading` message); + `isDismissable={false}` + `isKeyboardDismissDisabled` (can't dismiss mid + operation); Chakra `Progress` → `ProgressBar` (value 0–100, full width). + - **Verified:** typecheck/build/lint clean; drove Save → the ported + InputDialog ("Name your project") → the ported PostSaveDialog on the local + branded build — both render, no console errors, PostSaveDialog body + (Text/link) matches live. ProgressDialog not runtime-triggered (needs a + flashing/device flow); static checks only. + - `common/ModalCloseButton.tsx` may now be dead (GenericDialog/InputDialog + use `@microbit/ui` ModalCloseButton) — grep + remove when convenient. + ## Notes to revisit later Parked items surfaced during pre-work — out of scope for the convergence From 4168bc507fc67f1d83095ad55f1ce4bf26b100f6 Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Mon, 27 Jul 2026 13:32:02 +0000 Subject: [PATCH 014/104] Port connect-dialogs family to @microbit/ui + Panda RAC/Panda migration step 3. All 9 workbench/connect-dialogs/ files (ConnectCableDialog, Overlay, WebUSBErrorDialog, TransferHexDialog, ConnectDialog, WebUSBDialog, FirmwareDialog, NotFoundDialog, ConnectHelpDialog) move off Chakra: Text/Link/Image -> @microbit/ui, layout -> styled-system/jsx, Button solid->primary / default->outline, onClick->onPress, useMediaQuery->useBreakpointValue, useDisclosure->useState. FirmwareDialog uses an with button() recipe classes (no LinkButton primitive yet - flagged for the library). No @chakra-ui imports remain in the folder; tsc/build/lint clean; smoke-tested 'Send to micro:bit' -> ConnectDialog renders correctly. --- .../connect-dialogs/ConnectCableDialog.tsx | 9 ++-- .../connect-dialogs/ConnectDialog.tsx | 22 ++++---- .../connect-dialogs/ConnectHelpDialog.tsx | 27 +++++----- .../connect-dialogs/FirmwareDialog.tsx | 51 +++++++++++-------- .../connect-dialogs/NotFoundDialog.tsx | 44 +++++++--------- src/workbench/connect-dialogs/Overlay.tsx | 26 +++++----- .../connect-dialogs/TransferHexDialog.tsx | 11 ++-- .../connect-dialogs/WebUSBDialog.tsx | 25 ++++----- .../connect-dialogs/WebUSBErrorDialog.tsx | 13 ++--- 9 files changed, 113 insertions(+), 115 deletions(-) diff --git a/src/workbench/connect-dialogs/ConnectCableDialog.tsx b/src/workbench/connect-dialogs/ConnectCableDialog.tsx index d6bf0563e..e25a62989 100644 --- a/src/workbench/connect-dialogs/ConnectCableDialog.tsx +++ b/src/workbench/connect-dialogs/ConnectCableDialog.tsx @@ -3,8 +3,9 @@ * * SPDX-License-Identifier: MIT */ -import { Flex, Image, Text, VStack } from "@chakra-ui/react"; +import { Image, Text } from "@microbit/ui"; import { FormattedMessage } from "react-intl"; +import { Flex, VStack } from "styled-system/jsx"; import connectCable from "./connect-cable.gif"; const ConnectCableDialogBody = () => { @@ -13,9 +14,9 @@ const ConnectCableDialogBody = () => { width="auto" ml="auto" mr="auto" - p={5} - pb={0} - spacing={5} + p="5" + pb="0" + gap="5" alignItems="flex-start" > diff --git a/src/workbench/connect-dialogs/ConnectDialog.tsx b/src/workbench/connect-dialogs/ConnectDialog.tsx index 0e4aba6cc..36ade6af5 100644 --- a/src/workbench/connect-dialogs/ConnectDialog.tsx +++ b/src/workbench/connect-dialogs/ConnectDialog.tsx @@ -3,9 +3,10 @@ * * SPDX-License-Identifier: MIT */ -import { Button, HStack, Link } from "@chakra-ui/react"; +import { Button } from "@microbit/ui"; import { useCallback, useState } from "react"; import { FormattedMessage } from "react-intl"; +import { HStack } from "styled-system/jsx"; import { GenericDialog } from "../../common/GenericDialog"; import ConnectCableDialogBody from "./ConnectCableDialog"; import ConnectHelpDialogBody from "./ConnectHelpDialog"; @@ -93,30 +94,29 @@ const ConnectDialogFooter = ({ }: ConnectDialogFooterProps) => { return ( {!dialogNormallyHidden && !shownByRequest && ( - - + )} {stage === Stage.ConnectCable ? ( - ) : ( - )} - diff --git a/src/workbench/connect-dialogs/ConnectHelpDialog.tsx b/src/workbench/connect-dialogs/ConnectHelpDialog.tsx index 7ac0280c0..f1fd8264e 100644 --- a/src/workbench/connect-dialogs/ConnectHelpDialog.tsx +++ b/src/workbench/connect-dialogs/ConnectHelpDialog.tsx @@ -4,30 +4,29 @@ * SPDX-License-Identifier: MIT */ import { - Box, - Flex, Image, List, ListItem, Text, - useMediaQuery, + useBreakpointValue, VisuallyHidden, - VStack, -} from "@chakra-ui/react"; +} from "@microbit/ui"; import { FormattedMessage, useIntl } from "react-intl"; +import { Box, Flex, VStack } from "styled-system/jsx"; import selectMicrobit from "./select-microbit.png"; const ConnectHelpDialogBody = () => { const intl = useIntl(); - const [isDesktop] = useMediaQuery("(min-width: 768px)", { ssr: false }); + // Was useMediaQuery("(min-width: 768px)"); 768px is the `md` breakpoint. + const isDesktop = useBreakpointValue({ base: false, md: true }); return ( @@ -36,11 +35,11 @@ const ConnectHelpDialogBody = () => { {intl.formatMessage({ @@ -60,8 +59,10 @@ const ConnectHelpDialogBody = () => { position="absolute" left="495px" top="61px" + display="flex" + flexDirection="column" alignItems="flex-start" - spacing={2} + gap="2" > diff --git a/src/workbench/connect-dialogs/FirmwareDialog.tsx b/src/workbench/connect-dialogs/FirmwareDialog.tsx index 6a8fee1c5..87c64a3df 100644 --- a/src/workbench/connect-dialogs/FirmwareDialog.tsx +++ b/src/workbench/connect-dialogs/FirmwareDialog.tsx @@ -3,11 +3,13 @@ * * SPDX-License-Identifier: MIT */ -import { Button, HStack, Image, Link, Text, VStack } from "@chakra-ui/react"; -import { Icon } from "@chakra-ui/icons"; +import { Button, Icon, Image, Link, Text } from "@microbit/ui"; import { ReactNode, useCallback, useState } from "react"; import { RiExternalLinkLine } from "react-icons/ri"; import { FormattedMessage } from "react-intl"; +import { css, cx } from "styled-system/css"; +import { HStack, VStack } from "styled-system/jsx"; +import { button } from "styled-system/recipes"; import { GenericDialog } from "../../common/GenericDialog"; import firmwareUpgrade from "./firmware-upgrade.svg"; import { FinalFocusRef } from "../../project/project-actions"; @@ -51,9 +53,9 @@ const FirmwareDialogBody = () => { width="auto" ml="auto" mr="auto" - p={5} - pb={0} - spacing={5} + p="5" + pb="0" + gap="5" alignItems="flex-start" > @@ -62,9 +64,9 @@ const FirmwareDialogBody = () => { - - - + + + { href="https://microbit.org/get-started/user-guide/firmware/" > {chunks} - + ), }} @@ -96,7 +98,7 @@ const FirmwareDialogBody = () => { href="https://support.microbit.org/support/solutions/articles/19000105428-webusb-troubleshooting" > - + ); @@ -113,25 +115,32 @@ const FirmwareDialogFooter = ({ }: FirmwareDialogFooterProps) => { const buttonWidth = "8.1rem"; return ( - - - - + + ); }; diff --git a/src/workbench/connect-dialogs/NotFoundDialog.tsx b/src/workbench/connect-dialogs/NotFoundDialog.tsx index f591afaf2..ecf7bfe88 100644 --- a/src/workbench/connect-dialogs/NotFoundDialog.tsx +++ b/src/workbench/connect-dialogs/NotFoundDialog.tsx @@ -3,20 +3,11 @@ * * SPDX-License-Identifier: MIT */ -import { - Box, - Button, - Flex, - HStack, - Icon, - Image, - Link, - Text, - VStack, -} from "@chakra-ui/react"; +import { Button, Icon, Image, Link, Text } from "@microbit/ui"; import { ReactNode, useCallback, useState } from "react"; import { RiDownload2Line, RiExternalLinkLine } from "react-icons/ri"; import { FormattedMessage } from "react-intl"; +import { Box, Flex, HStack, VStack } from "styled-system/jsx"; import { GenericDialog } from "../../common/GenericDialog"; import SaveButton from "../../project/SaveButton"; import { ConnectErrorChoice } from "./FirmwareDialog"; @@ -79,9 +70,9 @@ const NotFoundDialogBody = ({ width="auto" ml="auto" mr="auto" - p={5} - pb={0} - spacing={5} + p="5" + pb="0" + gap="5" alignItems="flex-start" > @@ -90,9 +81,9 @@ const NotFoundDialogBody = ({ - - - + + + {chunks} - + ), strong: (chunks: ReactNode) => ( @@ -150,7 +141,7 @@ const NotFoundDialogBody = ({ href="https://support.microbit.org/support/solutions/articles/19000105428-webusb-troubleshooting" > - + @@ -158,11 +149,14 @@ const NotFoundDialogBody = ({ width="100%" background="blimpTeal.50" alignItems="center" - py={3} - px={5} + py="3" + px="5" borderRadius="xl" > - + @@ -184,11 +178,11 @@ const NotFoundDialogFooter = ({ onTryAgain, }: NotFoundDialogFooterProps) => { return ( - - - diff --git a/src/workbench/connect-dialogs/Overlay.tsx b/src/workbench/connect-dialogs/Overlay.tsx index aa61c7e07..b6371e3c4 100644 --- a/src/workbench/connect-dialogs/Overlay.tsx +++ b/src/workbench/connect-dialogs/Overlay.tsx @@ -3,20 +3,16 @@ * * SPDX-License-Identifier: MIT */ -import { Box, useDisclosure } from "@chakra-ui/react"; -import { useCallback, useEffect } from "react"; +import { useCallback, useEffect, useState } from "react"; +import { Box } from "styled-system/jsx"; import { zIndexOverlay } from "../../common/zIndex"; import { useDevice } from "../../device/device-hooks"; const Overlay = () => { - const selectingDevice = useDisclosure(); + const [isOpen, setIsOpen] = useState(false); const device = useDevice(); - const showOverlay = useCallback(() => { - selectingDevice.onOpen(); - }, [selectingDevice]); - const hideOverlay = useCallback(() => { - selectingDevice.onClose(); - }, [selectingDevice]); + const showOverlay = useCallback(() => setIsOpen(true), []); + const hideOverlay = useCallback(() => setIsOpen(false), []); useEffect(() => { device.addEventListener("beforerequestdevice", showOverlay); device.addEventListener("afterrequestdevice", hideOverlay); @@ -27,14 +23,16 @@ const Overlay = () => { }, [device, showOverlay, hideOverlay]); return ( ); }; diff --git a/src/workbench/connect-dialogs/TransferHexDialog.tsx b/src/workbench/connect-dialogs/TransferHexDialog.tsx index 6abd79107..1c042793f 100644 --- a/src/workbench/connect-dialogs/TransferHexDialog.tsx +++ b/src/workbench/connect-dialogs/TransferHexDialog.tsx @@ -3,10 +3,11 @@ * * SPDX-License-Identifier: MIT */ -import { Flex, HStack, Icon, Image, Text, VStack } from "@chakra-ui/react"; +import { Icon, Image, Text } from "@microbit/ui"; import { ReactNode } from "react"; import { RiInformationLine } from "react-icons/ri"; import { FormattedMessage } from "react-intl"; +import { Flex, HStack, VStack } from "styled-system/jsx"; import { GenericDialog, GenericDialogFooter } from "../../common/GenericDialog"; import transferHexMac from "./transfer-hex-mac.gif"; import transferHexWin from "./transfer-hex-win.gif"; @@ -57,9 +58,9 @@ const TransferHexDialogBody = () => { width="auto" ml="auto" mr="auto" - p={5} - pb={0} - spacing={5} + p="5" + pb="0" + gap="5" alignItems="flex-start" > @@ -78,7 +79,7 @@ const TransferHexDialogBody = () => { }} /> - + ( width="auto" ml="auto" mr="auto" - p={8} - pb={0} - spacing={5} + p="8" + pb="0" + gap="5" alignItems="flex-start" > {children} @@ -86,7 +79,7 @@ const Chrome105ErrorBody = () => { There is an issue with Chrome OS version 105 and WebUSB* - + Unfortunately “Send to micro:bit” does not work in this particular @@ -108,7 +101,7 @@ const Chrome105ErrorBody = () => { height="100%" src={chromeOSErrorImage} alt="" - pb={3} + pb="3" /> @@ -122,8 +115,8 @@ interface WebUSBDialogFooterProps { const WebUSBDialogFooter = ({ onCancel }: WebUSBDialogFooterProps) => { return ( - - diff --git a/src/workbench/connect-dialogs/WebUSBErrorDialog.tsx b/src/workbench/connect-dialogs/WebUSBErrorDialog.tsx index 55bb00588..84abfa5d5 100644 --- a/src/workbench/connect-dialogs/WebUSBErrorDialog.tsx +++ b/src/workbench/connect-dialogs/WebUSBErrorDialog.tsx @@ -3,9 +3,10 @@ * * SPDX-License-Identifier: MIT */ -import { Button, HStack, Text, VStack } from "@chakra-ui/react"; +import { Button, Text } from "@microbit/ui"; import { ReactNode, useCallback } from "react"; import { FormattedMessage } from "react-intl"; +import { HStack, VStack } from "styled-system/jsx"; import { GenericDialog } from "../../common/GenericDialog"; import { FinalFocusRef } from "../../project/project-actions"; @@ -46,9 +47,9 @@ const WebUSBErrorBody = ({ title, description }: WebUSBErrorBodyProps) => ( width="auto" ml="auto" mr="auto" - p={8} - pb={0} - spacing={5} + p="8" + pb="0" + gap="5" alignItems="flex-start" > {typeof title === "string" ? ( @@ -70,8 +71,8 @@ const WebUSBErrorDialogFooter = ({ onCancel, }: WebUSBErrorDialogFooterProps) => { return ( - - From bf0cf053d88f1a0169c56c04ebb98aa716de2089 Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Mon, 27 Jul 2026 13:32:02 +0000 Subject: [PATCH 015/104] Update RAC migration doc: connect-dialogs ported --- RAC-MIGRATION.md | 46 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/RAC-MIGRATION.md b/RAC-MIGRATION.md index b74de393b..87ed643d0 100644 --- a/RAC-MIGRATION.md +++ b/RAC-MIGRATION.md @@ -1,11 +1,10 @@ # Chakra → react-aria-components + Panda CSS migration -Status: **Step 3 (coexistence porting) in progress (2026-07-27) — the shared -`common/` dialogs are ported to `@microbit/ui`: ConfirmDialog, GenericDialog -(shell for 8), InputDialog, ProgressDialog, PostSaveDialog, MultipleFilesDialog. -Steps 1–2 complete. Verification for later batches is typecheck/build + a -runtime smoke check; full visual pass deferred (per owner) until more is -converted. Porting continues area-by-area.** +Status: **Step 3 (coexistence porting) in progress (2026-07-27) — all shared +`common/` dialogs + the whole `workbench/connect-dialogs/` family (9 files) +ported to `@microbit/ui`. Steps 1–2 complete. Verification bar: typecheck/ +build/lint + a runtime smoke check; full visual pass deferred (per owner). +Porting continues area-by-area.** Method: follow the **migration playbook** in the `@microbit/ui` monorepo (`../ui/docs/migration-playbook.md`) — the sequence, the gotcha catalog @@ -480,8 +479,39 @@ Chakra Heading (they compose Text). branded build — both render, no console errors, PostSaveDialog body (Text/link) matches live. ProgressDialog not runtime-triggered (needs a flashing/device flow); static checks only. - - `common/ModalCloseButton.tsx` may now be dead (GenericDialog/InputDialog - use `@microbit/ui` ModalCloseButton) — grep + remove when convenient. + - `common/ModalCloseButton.tsx` is NOT dead yet — WelcomeDialog, + FeedbackForm and AboutDialog (still Chakra) import it; retire it when + those port. + +- 2026-07-27 (step 3 — connect-dialogs family): **ported all 9 + `workbench/connect-dialogs/` files** (ConnectCableDialog, Overlay, + WebUSBErrorDialog, TransferHexDialog, ConnectDialog, WebUSBDialog, + FirmwareDialog, NotFoundDialog, ConnectHelpDialog). Same mapping as the + common dialogs (Text/Link/Image → `@microbit/ui`; layout → Panda + `styled-system/jsx`; Button `solid`→`primary`, default→`outline`, + `onClick`→`onPress`). Done via a context-sharing fork; verified by me. + - **Verified:** no `@chakra-ui` imports remain in the folder; tsc/build/ + lint clean; the one gotcha #9 risk (`css={{ minWidth: buttonWidth }}`) + is safe — `buttonWidth` is a same-file literal const, and `min-width: + 8.1rem` is present in the generated CSS. Smoke-tested "Send to micro:bit" + → the ported ConnectDialog "Connect cable" renders correctly (illustration + Image, "Don't show this again" link + outline Cancel + primary Next), no + console errors. + - **Flags for later:** + - **FirmwareDialog** has a link-styled-as-primary-button (`` + + `button({ variant: "primary" })` classes) — there's no `@microbit/ui` + link-button primitive. **Candidate for a shared `LinkButton` in + `@microbit/ui`** (other apps will want it too). + - **ConnectHelpDialog** `useMediaQuery("(min-width:768px)")` → + `useBreakpointValue({ base:false, md:true })`. `useBreakpointValue` can + return `undefined` on first render (mobile-first) — worth a look that the + desktop layout appears correctly in the eventual visual pass. + - `returnFocus` state in FirmwareDialog/NotFoundDialog is now effectively + dead (GenericDialog's `returnFocusOnClose` is a no-op) — harmless, left + to minimise the diff; remove later. + - **SaveButton** (used inside NotFoundDialog) is still a Chakra app + component — renders fine inside the ported dialog during coexistence; + ports with the rest of the app chrome. ## Notes to revisit later From 763e0949b29a77c5cc131fe1ec84599d041de25e Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Mon, 27 Jul 2026 14:13:41 +0000 Subject: [PATCH 016/104] Port workbench dialogs to @microbit/ui; retire ModalCloseButton RAC/Panda migration step 3. WelcomeDialog, FeedbackForm, AboutDialog move off Chakra; common/ModalCloseButton deleted (all dialogs use @microbit/ui's). - AboutDialog -> Panda styled HTML table (app-side, owner decision). - AspectRatio -> native aspectRatio CSS (gotcha #11). - Kept Chakra Collapse (AboutDialog read-more; library gap), inlined useClipboard, SimpleGrid->Grid, useDisclosure->useState. - Modals without a header got a (localized) aria-label for RAC. tsc/build/lint clean; smoke-tested Help->About renders correctly (table, images, buttons, collapse), no console errors. --- src/common/ModalCloseButton.tsx | 22 -- src/workbench/AboutDialog/AboutDialog.tsx | 367 ++++++++++++---------- src/workbench/FeedbackForm.tsx | 35 +-- src/workbench/WelcomeDialog.tsx | 117 ++++--- 4 files changed, 264 insertions(+), 277 deletions(-) delete mode 100644 src/common/ModalCloseButton.tsx diff --git a/src/common/ModalCloseButton.tsx b/src/common/ModalCloseButton.tsx deleted file mode 100644 index dd8d56234..000000000 --- a/src/common/ModalCloseButton.tsx +++ /dev/null @@ -1,22 +0,0 @@ -/** - * (c) 2022, Micro:bit Educational Foundation and contributors - * - * SPDX-License-Identifier: MIT - */ -import { - ModalCloseButton as ChakraModalCloseButton, - CloseButtonProps, -} from "@chakra-ui/react"; -import { useIntl } from "react-intl"; - -const ModalCloseButton = (props: CloseButtonProps) => { - const intl = useIntl(); - return ( - - ); -}; - -export default ModalCloseButton; diff --git a/src/workbench/AboutDialog/AboutDialog.tsx b/src/workbench/AboutDialog/AboutDialog.tsx index ec2f1722a..f35b55068 100644 --- a/src/workbench/AboutDialog/AboutDialog.tsx +++ b/src/workbench/AboutDialog/AboutDialog.tsx @@ -3,39 +3,26 @@ * * SPDX-License-Identifier: MIT */ +// Collapse has no @microbit/ui/Panda equivalent yet (roadmap: Collapse/Fade +// are planned library primitives); kept on Chakra during coexistence. +import { Collapse } from "@chakra-ui/react"; import { - AspectRatio, - Box, - BoxProps, Button, - Collapse, - Flex, - HStack, Icon, Image, Link, Modal, ModalBody, - ModalContent, + ModalCloseButton, ModalFooter, - ModalOverlay, - SimpleGrid, - Table, - TableCaption, - Tbody, - Td, Text, - Tr, - useDisclosure, VisuallyHidden, - VStack, -} from "@chakra-ui/react"; -import { useClipboard } from "@chakra-ui/hooks"; -import { ReactNode } from "react"; +} from "@microbit/ui"; +import { ReactNode, useCallback, useState } from "react"; import { RiFileCopy2Line, RiGithubFill } from "react-icons/ri"; import { FormattedMessage, useIntl } from "react-intl"; +import { Box, Flex, Grid, HStack, styled, VStack } from "styled-system/jsx"; import ExpandCollapseIcon from "../../common/ExpandCollapseIcon"; -import ModalCloseButton from "../../common/ModalCloseButton"; import { useDeployment } from "../../deployment"; import { microPythonConfig } from "../../micropython/micropython"; import comicImage from "./comic.png"; @@ -60,6 +47,17 @@ const clipboardVersion = versionInfo .map((x) => `${x.name} ${x.value}`) .join("\n"); +// Minimal replacement for Chakra's useClipboard (a library-gap hook). +const useClipboard = (text: string) => { + const [hasCopied, setHasCopied] = useState(false); + const onCopy = useCallback(() => { + void navigator.clipboard?.writeText(text); + setHasCopied(true); + window.setTimeout(() => setHasCopied(false), 1500); + }, [text]); + return { hasCopied, onCopy }; +}; + interface AboutDialogProps { isOpen: boolean; onClose: () => void; @@ -74,7 +72,7 @@ interface AboutDialogProps { const AboutDialog = ({ isOpen, onClose, finalFocusRef }: AboutDialogProps) => { const { hasCopied, onCopy } = useClipboard(clipboardVersion); const deployment = useDeployment(); - const micropythonSection = useDisclosure(); + const [micropythonOpen, setMicropythonOpen] = useState(false); const intl = useIntl(); return ( { onClose={onClose} size="4xl" finalFocusRef={finalFocusRef} - preserveScrollBarGap={false} + aria-label={intl.formatMessage({ id: "about" })} > - - - - - - - {deployment.horizontalLogo && ( - - {deployment.horizontalLogo} - - )} - - {/* No need to translate */} - - - - - - + + + + + {deployment.horizontalLogo && ( + + {deployment.horizontalLogo} + + )} + + {/* No need to translate */} + + + + + + - - ( - - {chunks} - - ), - }} - /> - - - - - - - - -
- - {versionInfo.map((v) => ( - - - - - - ))} - - - - -
{v.name}{v.value} - {/* Move padding so we get a reasonable click target. */} - - - GitHub - -
- - - - - ( - - {chunks} - - ), - }} - />{" "} - - + + + + {versionInfo.map((v) => ( + + + {v.name} + + + {v.value} + + + {/* Move padding so we get a reasonable click target. */} + + + GitHub + + + + ))} + + + - - {/* Avoid stack spacing here but match space so it doesn't change after the animation */} - - - - - - - - +
+ + + {/* Avoid stack spacing here but match space so it doesn't change after the animation */} + + + + + +
); }; -const MicroPythonSection = (props: BoxProps) => { +const MicroPythonSection = () => { const intl = useIntl(); return ( - - + + {intl.formatMessage({ - - + + { - + ); }; diff --git a/src/workbench/FeedbackForm.tsx b/src/workbench/FeedbackForm.tsx index 7e2f292c1..d498cb52a 100644 --- a/src/workbench/FeedbackForm.tsx +++ b/src/workbench/FeedbackForm.tsx @@ -3,9 +3,9 @@ * * SPDX-License-Identifier: MIT */ -import { Modal, ModalBody, ModalContent, ModalOverlay } from "@chakra-ui/react"; +import { Modal, ModalBody, ModalCloseButton } from "@microbit/ui"; import { useEffect, useRef } from "react"; -import ModalCloseButton from "../common/ModalCloseButton"; +import { useIntl } from "react-intl"; interface FeedbackFormProps { isOpen: boolean; @@ -21,6 +21,7 @@ const FeedbackForm = ({ onClose, finalFocusRef = undefined, }: FeedbackFormProps) => { + const intl = useIntl(); const iframeRef = useRef(null); useEffect(() => { const listener = (message: MessageEvent) => { @@ -47,24 +48,20 @@ const FeedbackForm = ({ onClose={onClose} size="2xl" finalFocusRef={finalFocusRef} - preserveScrollBarGap={false} + aria-label={intl.formatMessage({ id: "feedback" })} > - - - - -