diff --git a/.storybook/global.css b/.storybook/global.css index 873c54f41e..77cea19e46 100644 --- a/.storybook/global.css +++ b/.storybook/global.css @@ -1,6 +1,7 @@ /* Storybook stand-ins for what the VS Code host provides outside the webview document: the sidebar surface color and viewport sizing. - Typography and text color come from themes/generated/default-styles.css. */ + Typography and text color come from themes/generated/default-styles.css, + applied on body so portalled content (menus, tooltips) inherits it. */ html, #storybook-preview-wrapper { @@ -18,6 +19,12 @@ html body { overflow: auto; } +/* Shrink the root from a full-width block to its content so Pixel's + autofit crop stays tight. */ +#storybook-root { + width: fit-content; +} + #root { max-width: 100%; /* arbitrary size choice for the rough VSCode sidebar size; stories diff --git a/.storybook/preview.ts b/.storybook/preview.ts index 49eedb8258..51d3c6c9f3 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -70,10 +70,54 @@ function applyTheme(requested: string): void { document.body.setAttribute("data-vscode-theme-kind", `vscode-${slug}`); } +/* Pixel's autofit crop follows in-flow layout, but portalled overlays + (menus, tooltips) are out of flow and would be cropped away. Grow the + story root to cover any element portalled to body. Relies on the + padded (top-left anchored) layout: growth only extends right and + down, so already-positioned overlays never move. */ +function fitRootToPortals(): void { + const root = document.getElementById("root"); + if (!root) { + return; + } + const origin = root.getBoundingClientRect(); + let right = 0; + let bottom = 0; + for (const el of document.body.children) { + // Skip Storybook chrome (root, loaders, error display, a11y helpers) + if ( + !(el instanceof HTMLElement) || + el.id.startsWith("storybook-") || + el.classList.contains("sb-wrapper") + ) { + continue; + } + const rect = el.getBoundingClientRect(); + if (rect.width === 0 || rect.height === 0) { + continue; + } + right = Math.max(right, rect.right - origin.left); + bottom = Math.max(bottom, rect.bottom - origin.top); + } + if (right > 0 && bottom > 0) { + // Slack keeps shadows and focus outlines in frame + root.style.minWidth = `${Math.ceil(right) + 16}px`; + root.style.minHeight = `${Math.ceil(bottom) + 16}px`; + } +} + const preview: Preview = { parameters: { - layout: "centered", + // Top-left anchored; fitRootToPortals depends on this + layout: "padded", + }, + beforeEach: () => { + // Undo fitRootToPortals sizing when dev story switches reuse the root + const root = document.getElementById("root"); + root?.style.removeProperty("min-width"); + root?.style.removeProperty("min-height"); }, + afterEach: fitRootToPortals, globalTypes: { theme: { description: "Global theme for components", diff --git a/packages/ui/README.md b/packages/ui/README.md index 03ed7566a1..bc548386f4 100644 --- a/packages/ui/README.md +++ b/packages/ui/README.md @@ -22,14 +22,67 @@ import "@repo/ui/codicon.css"; Component CSS is inherit-first: typography and text color come from the webview (`font: inherit`), and controls center content with a fixed height -plus the shared `.ui-control` flex base in `components/control.css` — never -with line-height or vertical padding math, which drifts off-center with -font metrics. +plus the shared `.ui-control` flex base in `components/control.css`. +Line-height and vertical padding math drift off-center with font metrics, +so components avoid them. Every component forwards `className` and `style` to its root element, and default rules use single-class specificity, so a consumer class imported after the library overrides any default (width, height, spacing). +## Overlays + +`Tooltip`, `ContextMenu`, and `DropdownMenu` wrap the Radix primitives, +styled to match the native VS Code menu and hover widgets. Menus expose +Radix's compound parts as flat named exports (`DropdownMenuTrigger`, +`DropdownMenuItem`, …); `Tooltip` is a single component taking a `content` +prop, with a 500ms show delay matching VS Code's `workbench.hover.delay` +default. + +Overlay content is portalled to `body`, inherits webview typography from +there, and shares the `.ui-overlay` base for stacking, border, shadow, +and scrolling. Menus fade in like native menus, gated on `data-state` so +an interrupted entry animation cannot delay unmounting. High contrast, +`forced-colors`, and `prefers-reduced-motion` are handled. + +## Known gaps + +Deliberate deferrals, fine to fix later. + +Overlays: + +- Menus only support plain action items; Radix's checkbox/radio items, + group labels, and keybinding hints have no styled wrappers yet. +- Moving the pointer from one tooltip trigger straight to another replays + the full 500ms delay, where native shows the next hover instantly. The + fix is one shared `TooltipProvider` per app instead of one per + `Tooltip`. +- Overlay shadows are darker than native in dark themes: menus in VS Code + use `shadow-lg`, which webviews cannot read, so the closest available + `widget.shadow` stands in. +- A very tall tooltip fills most of the viewport before it scrolls, where + native hovers stop at half the window height. + +Package-wide: + +- There is no `Button`; the VS Code button style exists only inside the + state panels, and secondary-button colors have no `--ui-*` tokens. +- Only the Empty and Error panels ship; a Loading panel would need the + shared panel skeleton, which stays internal. +- The token layer maps what shipped components need: there are no + list/selection-row, spacing, typography, or z-index tokens, and the + `--ui-radius-*` tokens are only adopted by the overlays, with older + controls hardcoding their radii. +- `--ui-background` assumes a sidebar webview; a webview hosted in an + editor tab or panel renders on the sidebar color. +- `useVscodeTheme` reports the theme kind only; switching between two + themes of the same kind does not notify subscribers. +- Under `prefers-reduced-motion` the indeterminate `ProgressBar` renders + as a full bar and the `Spinner` as a static ring, with no other + activity cue. +- Story helpers compile against root-hoisted Storybook packages; a + standalone split needs its own Storybook devDependencies. + ## Codicons `CodiconName` is derived directly from the installed @@ -39,8 +92,10 @@ without a generated source file or a runtime list in the public API. ## Isolation ESLint rejects `@repo/*` imports and relative cross-package imports in -`packages/ui` TypeScript and TSX source. `react` remains a peer dependency, and -public consumers import from the package root or its declared CSS exports. +`packages/ui` TypeScript and TSX source. `react` remains a peer dependency; +the only runtime dependencies are the Radix overlay primitives and +`@vscode/codicons`. Public consumers import from the package root or its +declared CSS exports. Shared internals are reached through `package.json` subpath imports (`#cx`, `#codicons`, `#storybook`). These resolve only inside this package and ship diff --git a/packages/ui/package.json b/packages/ui/package.json index 7497d9f8b0..8f64bb0e86 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -4,6 +4,10 @@ "description": "Shared component library for VS Code webviews", "private": true, "type": "module", + "sideEffects": [ + "**/*.css", + "./storybook.preview.ts" + ], "exports": { ".": { "types": "./src/index.ts", @@ -15,21 +19,26 @@ "imports": { "#cx": "./src/cx.ts", "#codicons": "./src/codicons.ts", - "#storybook": "./src/storybook.ts" + "#storybook": "./src/storybook.tsx" }, "scripts": { "typecheck": "tsc --noEmit" }, "dependencies": { + "@radix-ui/react-context-menu": "^2.3.7", + "@radix-ui/react-dropdown-menu": "^2.1.24", + "@radix-ui/react-tooltip": "^1.2.16", "@vscode/codicons": "catalog:" }, "peerDependencies": { - "react": "catalog:" + "react": "catalog:", + "react-dom": "catalog:" }, "devDependencies": { "@types/react": "catalog:", "@vscode-elements/react-elements": "catalog:", "react": "catalog:", + "react-dom": "catalog:", "typescript": "catalog:" } } diff --git a/packages/ui/src/components/ContextMenu/ContextMenu.stories.tsx b/packages/ui/src/components/ContextMenu/ContextMenu.stories.tsx new file mode 100644 index 0000000000..aa7814c504 --- /dev/null +++ b/packages/ui/src/components/ContextMenu/ContextMenu.stories.tsx @@ -0,0 +1,79 @@ +import { userEvent, within } from "storybook/test"; + +import { openSubmenuByKeyboard, PIXEL_ALL_THEMES } from "#storybook"; + +import { Icon } from "../Icon/Icon"; + +import { + ContextMenu, + ContextMenuContent, + ContextMenuItem, + ContextMenuSeparator, + ContextMenuSub, + ContextMenuSubContent, + ContextMenuSubTrigger, + ContextMenuTrigger, +} from "./ContextMenu"; + +import type { Meta, StoryObj } from "@storybook/react-vite"; + +const TARGET_STYLE: React.CSSProperties = { + display: "grid", + placeItems: "center", + width: 240, + height: 120, + border: "1px dashed var(--ui-description-foreground)", +}; + +const MenuExample = (): React.JSX.Element => ( + + +
Right-click here
+
+ + + + Start workspace + + + + Stop + + + + More actions + + Open logs + Edit settings + + + +
+); + +const meta: Meta = { + title: "UI/ContextMenu", + component: MenuExample, +}; + +export default meta; +type Story = StoryObj; + +export const Open: Story = { + parameters: { pixel: PIXEL_ALL_THEMES }, + play: async ({ canvasElement }) => { + const target = within(canvasElement).getByText("Right-click here"); + /* Right-click at the target's center; without coords the menu + opens at (0,0), detached from the target. */ + const rect = target.getBoundingClientRect(); + await userEvent.pointer({ + keys: "[MouseRight]", + target, + coords: { + clientX: rect.left + rect.width / 2, + clientY: rect.top + rect.height / 2, + }, + }); + await openSubmenuByKeyboard("Open logs"); + }, +}; diff --git a/packages/ui/src/components/ContextMenu/ContextMenu.tsx b/packages/ui/src/components/ContextMenu/ContextMenu.tsx new file mode 100644 index 0000000000..3a6ea7c058 --- /dev/null +++ b/packages/ui/src/components/ContextMenu/ContextMenu.tsx @@ -0,0 +1,105 @@ +import * as ContextMenuPrimitive from "@radix-ui/react-context-menu"; + +import { cx } from "#cx"; + +import { Icon } from "../Icon/Icon"; +import "../menu.css"; +import "../overlay.css"; + +import type { ComponentPropsWithRef } from "react"; + +/** Root state container; wraps the trigger and content. */ +export const ContextMenu = ContextMenuPrimitive.Root; + +/** The right-click target area; renders its child element via `asChild`. */ +export const ContextMenuTrigger = ContextMenuPrimitive.Trigger; + +/** Scopes one submenu; wraps its sub trigger and sub content. */ +export const ContextMenuSub = ContextMenuPrimitive.Sub; + +/** The floating menu surface, portalled to `body` at the pointer. */ +export function ContextMenuContent({ + className, + ...props +}: ComponentPropsWithRef< + typeof ContextMenuPrimitive.Content +>): React.JSX.Element { + return ( + + + + ); +} + +/** The floating submenu surface, opened by `ContextMenuSubTrigger`. */ +export function ContextMenuSubContent({ + className, + ...props +}: ComponentPropsWithRef< + typeof ContextMenuPrimitive.SubContent +>): React.JSX.Element { + return ( + + + + ); +} + +/** One selectable action row; a leading `Icon` sits in the gutter. */ +export function ContextMenuItem({ + className, + ...props +}: ComponentPropsWithRef): React.JSX.Element { + return ( + + ); +} + +/** The row that opens its submenu; renders a trailing chevron. */ +export function ContextMenuSubTrigger({ + className, + children, + ...props +}: ComponentPropsWithRef< + typeof ContextMenuPrimitive.SubTrigger +>): React.JSX.Element { + return ( + + {children} + + + ); +} + +/** Thin rule between groups of items. */ +export function ContextMenuSeparator({ + className, + ...props +}: ComponentPropsWithRef< + typeof ContextMenuPrimitive.Separator +>): React.JSX.Element { + return ( + + ); +} diff --git a/packages/ui/src/components/DropdownMenu/DropdownMenu.stories.tsx b/packages/ui/src/components/DropdownMenu/DropdownMenu.stories.tsx new file mode 100644 index 0000000000..2eef395388 --- /dev/null +++ b/packages/ui/src/components/DropdownMenu/DropdownMenu.stories.tsx @@ -0,0 +1,95 @@ +import { expect, screen, userEvent, waitFor, within } from "storybook/test"; + +import { + openSubmenuByKeyboard, + PIXEL_ALL_THEMES, + STORY_TRIGGER_CLASS, +} from "#storybook"; + +import { Icon } from "../Icon/Icon"; + +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuTrigger, +} from "./DropdownMenu"; + +import type { Meta, StoryObj } from "@storybook/react-vite"; + +const MenuExample = (): React.JSX.Element => ( + + + + + + + + Start workspace + + + + Stop + + + + More actions + + Open logs + Edit settings + + + + +); + +const meta: Meta = { + title: "UI/DropdownMenu", + component: MenuExample, +}; + +export default meta; +type Story = StoryObj; + +export const Open: Story = { + parameters: { pixel: PIXEL_ALL_THEMES }, + play: async ({ canvasElement }) => { + await userEvent.click( + within(canvasElement).getByRole("button", { name: "Workspace actions" }), + ); + await openSubmenuByKeyboard("Open logs"); + }, +}; + +/* Long menus cap to the viewport by default; the story lowers the cap. */ +export const ManyItems: Story = { + render: () => ( + + + + + + {Array.from({ length: 40 }, (_, i) => ( + Workspace {i + 1} + ))} + + + ), + play: async ({ canvasElement }) => { + await userEvent.click( + within(canvasElement).getByRole("button", { name: "Workspace actions" }), + ); + const menu = await screen.findByRole("menu"); + await waitFor(() => + expect(menu.scrollHeight).toBeGreaterThan(menu.clientHeight), + ); + }, +}; diff --git a/packages/ui/src/components/DropdownMenu/DropdownMenu.tsx b/packages/ui/src/components/DropdownMenu/DropdownMenu.tsx new file mode 100644 index 0000000000..b02daab587 --- /dev/null +++ b/packages/ui/src/components/DropdownMenu/DropdownMenu.tsx @@ -0,0 +1,109 @@ +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; + +import { cx } from "#cx"; + +import { Icon } from "../Icon/Icon"; +import "../menu.css"; +import "../overlay.css"; + +import type { ComponentPropsWithRef } from "react"; + +/** Root state container; wraps the trigger and content. */ +export const DropdownMenu = DropdownMenuPrimitive.Root; + +/** Opens the menu on click; renders its child element via `asChild`. */ +export const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger; + +/** Scopes one submenu; wraps its sub trigger and sub content. */ +export const DropdownMenuSub = DropdownMenuPrimitive.Sub; + +/** The floating menu surface, portalled to `body`. */ +export function DropdownMenuContent({ + className, + ...props +}: ComponentPropsWithRef< + typeof DropdownMenuPrimitive.Content +>): React.JSX.Element { + return ( + + + + ); +} + +/** The floating submenu surface, opened by `DropdownMenuSubTrigger`. */ +export function DropdownMenuSubContent({ + className, + ...props +}: ComponentPropsWithRef< + typeof DropdownMenuPrimitive.SubContent +>): React.JSX.Element { + return ( + + + + ); +} + +/** One selectable action row; a leading `Icon` sits in the gutter. */ +export function DropdownMenuItem({ + className, + ...props +}: ComponentPropsWithRef< + typeof DropdownMenuPrimitive.Item +>): React.JSX.Element { + return ( + + ); +} + +/** The row that opens its submenu; renders a trailing chevron. */ +export function DropdownMenuSubTrigger({ + className, + children, + ...props +}: ComponentPropsWithRef< + typeof DropdownMenuPrimitive.SubTrigger +>): React.JSX.Element { + return ( + + {children} + + + ); +} + +/** Thin rule between groups of items. */ +export function DropdownMenuSeparator({ + className, + ...props +}: ComponentPropsWithRef< + typeof DropdownMenuPrimitive.Separator +>): React.JSX.Element { + return ( + + ); +} diff --git a/packages/ui/src/components/Tooltip/Tooltip.css b/packages/ui/src/components/Tooltip/Tooltip.css new file mode 100644 index 0000000000..54f651fae4 --- /dev/null +++ b/packages/ui/src/components/Tooltip/Tooltip.css @@ -0,0 +1,15 @@ +/* Matches the native workbench hover widget; typography inherits from + the webview body. */ +.ui-tooltip { + --ui-overlay-border: var(--ui-tooltip-border); + --ui-overlay-available-height: var(--radix-tooltip-content-available-height); + + max-width: min(700px, var(--radix-tooltip-content-available-width)); + padding: 4px 8px; + color: var(--ui-tooltip-foreground); + background: var(--ui-tooltip-background); + /* Native hover: 13px/19px type and a 5px radius, not cornerRadius-large */ + line-height: 19px; + border-radius: 5px; + overflow-wrap: break-word; +} diff --git a/packages/ui/src/components/Tooltip/Tooltip.stories.tsx b/packages/ui/src/components/Tooltip/Tooltip.stories.tsx new file mode 100644 index 0000000000..4166157b30 --- /dev/null +++ b/packages/ui/src/components/Tooltip/Tooltip.stories.tsx @@ -0,0 +1,65 @@ +import { expect, screen, userEvent, waitFor } from "storybook/test"; + +import { PIXEL_ALL_THEMES, STORY_TRIGGER_CLASS } from "#storybook"; + +import { Tooltip } from "./Tooltip"; + +import type { Meta, StoryObj } from "@storybook/react-vite"; + +const LONG_TEXT = + "This workspace has been running for 14 days without a rebuild. " + + "Stopping it frees compute resources, and any unsaved changes in " + + "the home volume are preserved until the next start."; + +const meta: Meta = { + title: "UI/Tooltip", + component: Tooltip, + args: { + content: "Stops the workspace", + // Instant in stories; the component default is 500ms + delayDuration: 0, + children: ( + + ), + }, +}; + +export default meta; +type Story = StoryObj; + +/* findByRole("tooltip") matches Radix's visually hidden a11y copy, so + open assertions target the visible .ui-tooltip bubble instead. */ +async function openTooltipWithKeyboard(): Promise { + await userEvent.tab(); + await screen.findByRole("tooltip"); + const tooltip = document.querySelector(".ui-tooltip"); + if (!tooltip) { + throw new Error("visible tooltip content not found"); + } + await waitFor(() => expect(tooltip).toBeVisible()); + return tooltip; +} + +export const Open: Story = { + parameters: { pixel: PIXEL_ALL_THEMES }, + play: async () => { + await openTooltipWithKeyboard(); + }, +}; + +/* Long content wraps at the hover width cap and scrolls once the story + lowers the height cap. */ +export const Overflow: Story = { + args: { + content: Array.from({ length: 8 }, () => LONG_TEXT).join(" "), + style: { maxHeight: 160 }, + }, + play: async () => { + const tooltip = await openTooltipWithKeyboard(); + await waitFor(() => + expect(tooltip.scrollHeight).toBeGreaterThan(tooltip.clientHeight), + ); + }, +}; diff --git a/packages/ui/src/components/Tooltip/Tooltip.tsx b/packages/ui/src/components/Tooltip/Tooltip.tsx new file mode 100644 index 0000000000..fc3ca6d061 --- /dev/null +++ b/packages/ui/src/components/Tooltip/Tooltip.tsx @@ -0,0 +1,47 @@ +import * as TooltipPrimitive from "@radix-ui/react-tooltip"; + +import { cx } from "#cx"; + +import "../overlay.css"; + +import "./Tooltip.css"; + +import type { ComponentPropsWithRef, ReactNode } from "react"; + +export interface TooltipProps extends Omit< + ComponentPropsWithRef, + "content" +> { + content: ReactNode; + /** The trigger element; must accept a forwarded ref (asChild). */ + children: ReactNode; + /** Show delay in ms. Defaults to VS Code's workbench.hover.delay. */ + delayDuration?: number; +} + +export function Tooltip({ + content, + children, + className, + delayDuration = 500, + ...props +}: TooltipProps): React.JSX.Element { + return ( + + + {children} + + + {content} + + + + + ); +} diff --git a/packages/ui/src/components/menu.css b/packages/ui/src/components/menu.css new file mode 100644 index 0000000000..935590dfc1 --- /dev/null +++ b/packages/ui/src/components/menu.css @@ -0,0 +1,103 @@ +/* Shared ContextMenu/DropdownMenu surface matching the native menu + widget; typography inherits from the webview body. */ +.ui-menu { + --ui-menu-gutter: 2em; + --ui-overlay-border: var(--ui-menu-border); + /* Radix names the available-height variable per primitive */ + --ui-overlay-available-height: var( + --radix-dropdown-menu-content-available-height, + var(--radix-context-menu-content-available-height) + ); + + min-width: 160px; + padding: 4px; + color: var(--ui-menu-foreground); + background: var(--ui-menu-background); + outline: 0; +} + +.ui-menu__item { + position: relative; + display: flex; + align-items: center; + height: 24px; + /* Native label inset; the gutters double as the check/icon columns. */ + padding: 0 var(--ui-menu-gutter); + line-height: 1; + white-space: nowrap; + border-radius: var(--ui-radius-medium); + cursor: default; + user-select: none; + outline: 1px solid transparent; + outline-offset: -1px; +} + +/* Selection border only resolves in high contrast; an open submenu + keeps its parent highlighted, like native. */ +.ui-menu__item[data-highlighted], +.ui-menu__item[data-state="open"] { + forced-color-adjust: none; + color: var(--ui-menu-highlight-foreground); + background: var(--ui-menu-highlight-background); + outline-color: var(--ui-menu-selection-border); +} + +.ui-menu__item[data-disabled] { + color: var(--ui-disabled-foreground); +} + +/* Leading icons sit in the left gutter so labels stay aligned */ +.ui-menu__item > .ui-icon:not(.ui-menu__submenu-indicator) { + position: absolute; + left: 0; + width: var(--ui-menu-gutter); + text-align: center; +} + +/* Chevron in the right gutter, like the native indicator */ +.ui-menu__submenu-indicator { + position: absolute; + right: 0; + width: var(--ui-menu-gutter); + text-align: center; +} + +.ui-menu__item[data-disabled] .ui-menu__submenu-indicator { + opacity: var(--ui-disabled-opacity); +} + +.ui-menu__separator { + height: 1px; + margin: 5px 0; + background: var(--ui-menu-separator); +} + +/* Entry fade like native menus. Gated on data-state so an interrupted + entry animation cannot block Radix from unmounting the closed menu. */ +@media (prefers-reduced-motion: no-preference) { + .ui-menu:not([data-state="closed"]) { + animation: ui-menu-fade-in 83ms linear; + } +} + +@keyframes ui-menu-fade-in { + from { + opacity: 0; + } +} + +@media (forced-colors: active) { + .ui-menu__item[data-highlighted], + .ui-menu__item[data-state="open"] { + color: HighlightText; + background: Highlight; + } + + .ui-menu__item[data-disabled] { + color: GrayText; + } + + .ui-menu__separator { + background: CanvasText; + } +} diff --git a/packages/ui/src/components/overlay.css b/packages/ui/src/components/overlay.css new file mode 100644 index 0000000000..f7e6c5e041 --- /dev/null +++ b/packages/ui/src/components/overlay.css @@ -0,0 +1,19 @@ +/* Shared base for portalled overlay surfaces (menus, tooltips). Surfaces + map their border color and their primitive's Radix available-height + variable onto the --ui-overlay-* properties. */ +.ui-overlay { + box-sizing: border-box; + /* Cap to the space Radix reports so oversized content scrolls */ + max-height: var(--ui-overlay-available-height, none); + overflow-y: auto; + border: 1px solid var(--ui-overlay-border, transparent); + border-radius: var(--ui-radius-large); + box-shadow: var(--ui-widget-shadow); + z-index: 40; +} + +@media (forced-colors: active) { + .ui-overlay { + border-color: CanvasText; + } +} diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index bb84f45455..a62e0e3b93 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -26,4 +26,25 @@ export { type StatusPillTone, } from "./components/StatusPill/StatusPill"; export type { CodiconName } from "./codicons"; +export { + ContextMenu, + ContextMenuContent, + ContextMenuItem, + ContextMenuSeparator, + ContextMenuSub, + ContextMenuSubContent, + ContextMenuSubTrigger, + ContextMenuTrigger, +} from "./components/ContextMenu/ContextMenu"; +export { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuTrigger, +} from "./components/DropdownMenu/DropdownMenu"; +export { Tooltip, type TooltipProps } from "./components/Tooltip/Tooltip"; export { useVscodeTheme, type VscodeThemeKind } from "./useVscodeTheme"; diff --git a/packages/ui/src/storybook.css b/packages/ui/src/storybook.css new file mode 100644 index 0000000000..181ac87273 --- /dev/null +++ b/packages/ui/src/storybook.css @@ -0,0 +1,20 @@ +/* Story stand-in: a VS Code secondary button like consuming webviews + render; secondary button colors have no --ui-* tokens yet. */ +.story-trigger { + padding: 0.4em 1em; + border: 1px solid var(--ui-button-border); + border-radius: 2px; + background: var(--vscode-button-secondaryBackground); + color: var(--vscode-button-secondaryForeground); + font: inherit; + cursor: pointer; +} + +.story-trigger:hover { + background: var(--vscode-button-secondaryHoverBackground); +} + +.story-trigger:focus-visible { + outline: 1px solid var(--ui-focus-border); + outline-offset: 2px; +} diff --git a/packages/ui/src/storybook.ts b/packages/ui/src/storybook.ts deleted file mode 100644 index 7625fb663f..0000000000 --- a/packages/ui/src/storybook.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Pixel matrix override (`parameters.pixel`) that snapshots a story in every - * captured VS Code theme; the base matrix in pixel.jsonc is light/dark only. - */ -export const PIXEL_ALL_THEMES = { - matrix: { - themes: ["light", "dark", "high-contrast", "high-contrast-light"], - }, -} as const; diff --git a/packages/ui/src/storybook.tsx b/packages/ui/src/storybook.tsx new file mode 100644 index 0000000000..06957f165b --- /dev/null +++ b/packages/ui/src/storybook.tsx @@ -0,0 +1,24 @@ +import { expect, screen, userEvent, waitFor } from "storybook/test"; + +import "./storybook.css"; + +/** + * Pixel matrix override (`parameters.pixel`) that snapshots a story in every + * captured VS Code theme; the base matrix in pixel.jsonc is light/dark only. + */ +export const PIXEL_ALL_THEMES = { + matrix: { + themes: ["light", "dark", "high-contrast", "high-contrast-light"], + }, +} as const; + +/* Story stand-in for a webview-styled button; styled in storybook.css. */ +export const STORY_TRIGGER_CLASS = "story-trigger"; + +/* Opens the focused menu's submenu; keyboard skips the hover-open delay. */ +export async function openSubmenuByKeyboard(itemName: string): Promise { + const menu = await screen.findByRole("menu"); + await waitFor(() => expect(menu.contains(document.activeElement)).toBe(true)); + await userEvent.keyboard("{End}{ArrowRight}"); + await screen.findByRole("menuitem", { name: itemName }); +} diff --git a/packages/ui/src/tokens.css b/packages/ui/src/tokens.css index d2fa466503..6ab9b09e1c 100644 --- a/packages/ui/src/tokens.css +++ b/packages/ui/src/tokens.css @@ -90,6 +90,44 @@ var(--ui-foreground) ); + /* Disabled text */ + --ui-disabled-foreground: var(--vscode-disabledForeground); + + /* Mirrors the native menu shadow; widget.shadow is null in high + contrast, hiding the shadow like native */ + --ui-widget-shadow: var( + --vscode-shadow-lg, + 0 0 12px var(--vscode-widget-shadow, transparent) + ); + + /* Corner radii; fallbacks predate the host's corner radius tokens */ + --ui-radius-large: var(--vscode-cornerRadius-large, 5px); + --ui-radius-medium: var(--vscode-cornerRadius-medium, 4px); + + /* Menus */ + --ui-menu-background: var(--vscode-menu-background); + --ui-menu-foreground: var(--vscode-menu-foreground); + --ui-menu-border: var( + --vscode-menu-border, + var(--vscode-editorWidget-border, transparent) + ); + /* Native menus highlight with the list hover colors (defaultMenuStyles) */ + --ui-menu-highlight-background: var( + --vscode-list-hoverBackground, + transparent + ); + --ui-menu-highlight-foreground: var( + --vscode-list-hoverForeground, + var(--ui-menu-foreground) + ); + --ui-menu-selection-border: var(--vscode-menu-selectionBorder, transparent); + --ui-menu-separator: var(--vscode-menu-separatorBackground); + + /* Tooltip (native workbench hover widget) */ + --ui-tooltip-background: var(--vscode-editorHoverWidget-background); + --ui-tooltip-foreground: var(--vscode-editorHoverWidget-foreground); + --ui-tooltip-border: var(--vscode-editorHoverWidget-border); + /* Only defined by high contrast themes; transparent elsewhere */ --ui-contrast-border: var(--vscode-contrastBorder, transparent); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 375792c2bd..543215dd05 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,8 +38,8 @@ catalogs: specifier: ^2.4.0 version: 2.4.0 '@vscode/codicons': - specifier: ^0.0.45 - version: 0.0.45 + specifier: 0.0.46-24 + version: 0.0.46-24 babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -213,7 +213,7 @@ importers: version: 4.1.10(vitest@4.1.10) '@vscode/codicons': specifier: 'catalog:' - version: 0.0.45 + version: 0.0.46-24 '@vscode/test-cli': specifier: ^0.0.15 version: 0.0.15 @@ -394,10 +394,10 @@ importers: version: 5.101.4(react@19.2.8) '@vscode-elements/react-elements': specifier: 'catalog:' - version: 2.4.0(@types/react@19.2.17)(@vscode/codicons@0.0.45)(react-dom@19.2.8)(react@19.2.8) + version: 2.4.0(@types/react@19.2.17)(@vscode/codicons@0.0.46-24)(react-dom@19.2.8)(react@19.2.8) '@vscode/codicons': specifier: 'catalog:' - version: 0.0.45 + version: 0.0.46-24 date-fns: specifier: 'catalog:' version: 4.4.0 @@ -438,19 +438,31 @@ importers: packages/ui: dependencies: + '@radix-ui/react-context-menu': + specifier: ^2.3.7 + version: 2.3.7(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-dropdown-menu': + specifier: ^2.1.24 + version: 2.1.24(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-tooltip': + specifier: ^1.2.16 + version: 1.2.16(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) '@vscode/codicons': specifier: 'catalog:' - version: 0.0.45 + version: 0.0.46-24 devDependencies: '@types/react': specifier: 'catalog:' version: 19.2.17 '@vscode-elements/react-elements': specifier: 'catalog:' - version: 2.4.0(@types/react@19.2.17)(@vscode/codicons@0.0.45)(react-dom@19.2.8)(react@19.2.8) + version: 2.4.0(@types/react@19.2.17)(@vscode/codicons@0.0.46-24)(react-dom@19.2.8)(react@19.2.8) react: specifier: 'catalog:' version: 19.2.8 + react-dom: + specifier: 'catalog:' + version: 19.2.8(react@19.2.8) typescript: specifier: 'catalog:' version: 6.0.3 @@ -472,7 +484,7 @@ importers: version: 1.57.5 '@vscode-elements/react-elements': specifier: 'catalog:' - version: 2.4.0(@types/react@19.2.17)(@vscode/codicons@0.0.45)(react-dom@19.2.8)(react@19.2.8) + version: 2.4.0(@types/react@19.2.17)(@vscode/codicons@0.0.46-24)(react-dom@19.2.8)(react@19.2.8) react: specifier: 'catalog:' version: 19.2.8 @@ -493,10 +505,10 @@ importers: version: 5.101.4(react@19.2.8) '@vscode-elements/react-elements': specifier: 'catalog:' - version: 2.4.0(@types/react@19.2.17)(@vscode/codicons@0.0.45)(react-dom@19.2.8)(react@19.2.8) + version: 2.4.0(@types/react@19.2.17)(@vscode/codicons@0.0.46-24)(react-dom@19.2.8)(react@19.2.8) '@vscode/codicons': specifier: 'catalog:' - version: 0.0.45 + version: 0.0.46-24 date-fns: specifier: 'catalog:' version: 4.4.0 @@ -1032,6 +1044,21 @@ packages: '@noble/hashes': optional: true + '@floating-ui/core@1.8.0': + resolution: {integrity: sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==} + + '@floating-ui/dom@1.8.0': + resolution: {integrity: sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==} + + '@floating-ui/react-dom@2.1.9': + resolution: {integrity: sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.12': + resolution: {integrity: sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==} + '@humanfs/core@0.19.2': resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} engines: {node: '>=18.18.0'} @@ -1528,6 +1555,311 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@radix-ui/primitive@1.1.7': + resolution: {integrity: sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q==} + + '@radix-ui/react-arrow@1.1.15': + resolution: {integrity: sha512-v4zggRcjadnI+ClKDuijlQEW4tw3NoaeHc/PwpKnLoLLKNUG4InLegkstooLcRIUWCs+8L22dGURCVuFfOKfnA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collection@1.1.15': + resolution: {integrity: sha512-9W+B9NPF0NaaPh/1NJd3+KqsnlLqU9H7T2rvww+fp+T/evVXdNAyYcnfRQZFOjkR1ajQp3yORlqnI8soawLvNA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-compose-refs@1.1.5': + resolution: {integrity: sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context-menu@2.3.7': + resolution: {integrity: sha512-CtXP35dxaB5T3zXSd+E3uHe/QpXcpYnZmxp6OaIbfthtfW4wyb77M23BG+bwIJDtsMwEP/YssdsmNyZu7jhWew==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-context@1.2.2': + resolution: {integrity: sha512-RHCUGwKHDr0hDGg4X7ma4JG4/+12qxw8rkh5QKdDldlCvtja6nUx1Ef/8HVrJze81lEsgLQlqjzjGNHantgnQA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-direction@1.1.4': + resolution: {integrity: sha512-5pzg4FGQNpExhnhT2zlrP1wZFaYCd1K0nYWoFAdcYoYK868IEigqMX3B3f8yIoRlAhAeDWciLI6ZdCKHF9P4Vg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dismissable-layer@1.1.19': + resolution: {integrity: sha512-8g4pfOL9HoKKLWGiypT+dphVqjFfmcXO5GBnhsG6zI+lxAx/8feQpr+1LSN8Re3hiZ+XkLNS4O9ztK11/LzQ6w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-dropdown-menu@2.1.24': + resolution: {integrity: sha512-geq8l2rJkxvkXsT9RMgtUE3P8pITFpTsvYpbySi1IH4fZEABD/Gp85myayFgxk0ktljGMJnCbeFkyTusvSvv7g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.1.6': + resolution: {integrity: sha512-RNOJjfZMTyBM6xYmV3IVGXkPjIhcBAuv48POevAXwrGJhkWZ9p1rFoIS1JFooPuT193AZmRsCPhpoVJxx6OPoQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.1.16': + resolution: {integrity: sha512-wmRZ2WWLvmt6KHy2rNPOdPUjwq5xOHY02+m+udwJTn0aNIox/rkskAvJTyTLGhPK6KgrUjlJUJpgmx/+wFiFIQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-id@1.1.4': + resolution: {integrity: sha512-TMQp2llA+RYn7JcjnrMnz7wN4pcVttPZnRZo52PLQsoLVKzNlVwUeHmfePgTgRluXFvlD3GD5g5MOVVTJCO0qA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-menu@2.1.24': + resolution: {integrity: sha512-uW7RVuU6Lp/ZtfeY4b3kL32zccgEWvPv1+cf17ubYzHa9cL8AHokmk36cG/XEiH/smbQvumnieXX9j/e9RqJWA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popper@1.3.7': + resolution: {integrity: sha512-UsJrrd7w4wuKKTdvd/DNERVlwSlUcyXzjhyDwBk+3aPOsCjOY6ZSbxuw8E6lZTjjfP8Cpd0J8VVkrYUWyGYXyg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.1.17': + resolution: {integrity: sha512-vKQLcWypUnwZVvfV7UkGahH2g6ySe8M8R+zYBwPrv5byZ9QAW6cQVvNKo7GgmD+p8aYb6D9JBuvy8/WhOno2wQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.10': + resolution: {integrity: sha512-3wyzCQ6+ubRA+D4uv9m95JYLXxmOHp05qjrkjeA7uKHHtjpPggQzc6DAb0URl7j67oR0K2foO4ip27TiX037Bw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.10': + resolution: {integrity: sha512-MucOnzh6hR5mid6VpkbglRAMYMjKLqRnGBbjXkzjK52fuQDd1qbkx78a5P40mkcnVXJdEVxm26E9OPAiUq7nBg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-roving-focus@1.1.19': + resolution: {integrity: sha512-V9jI6hDjT7l3jsCQD9bLNvDLM3tH/gdbOTp7Tefp3hbbgCGQoK7tUvrWiRlcoBHIZ809ElXwNQwVo0B98LuTXQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.3.3': + resolution: {integrity: sha512-qx7oqnYbxnK9kYI9m317qmFmEgo6ywqWvbTogdj7cL9p3/yx4M48p7Rnw5z3H890cL/ow/EeWJsuTykeZVXP5Q==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-tooltip@1.2.16': + resolution: {integrity: sha512-6EamKFRRnlpdadndbZ6LMwycfwkwPte1B42hs6QA0gYhjaOKqW4PZ4pjaW9UrlDX5eVt/OjncE7BFTPL5nmZhg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-use-callback-ref@1.1.4': + resolution: {integrity: sha512-R6OUY2e2fA6Yn6s+VSx5KBV6Nx8LQEhu+cz7LCej18rQ1HLyg9PSC9jP/ZNx0o6FAIK9c0F1kHylzSxKsdlkrQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.2.6': + resolution: {integrity: sha512-uEQJGT97ZA/TgP/Hydw47lHu+/vQj6z/0jA+WeTbK1o9Rx45GImjpD0tc3W5ad3D6XTSR6e1yEO0FvGq6WQfVQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.5': + resolution: {integrity: sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-is-hydrated@0.1.3': + resolution: {integrity: sha512-umO/aJ+82CpOnhDZUTbILCQf7kU/g0iv+oGs/Q8jw7IkhWBzaEP4sA268PhFAJTFetbwp3ICc6ktpI4TqtxcIw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.4': + resolution: {integrity: sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-rect@1.1.4': + resolution: {integrity: sha512-cSOCh6JlkmfjLyNcLiu2nB4v+nm+dkZ+Q5KHWk/soo4U7ZLiEQFKHK9/YmtBHjfCEaU43IBKQOc4/uJmCaiCTQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.1.4': + resolution: {integrity: sha512-D3anSY15EJoxrihpsXI6SMrmmonnQtR2ni7arO+Lfdg3O95b9hNXxONk8jA5C8ANdF/h5HMAxejgs8PWJ6rlhw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-visually-hidden@1.2.11': + resolution: {integrity: sha512-NFS86RYYZb4/exihaESBGOpMJFz8MGLAfu3mOBSGByVnVPC9JPASfYubxd/8KbkQK0sYAv8lVQDEQukDX/qXvQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/rect@1.1.3': + resolution: {integrity: sha512-JtyZR+mqgBibTo8xea3B6ZRmzZiM/YeVBtUkas6zMuXjAlfIFIW2FgqeM9eLyvEaYX66vr6DJMK+4U6LV0KhNw==} + '@rolldown/binding-android-arm64@1.1.5': resolution: {integrity: sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -2244,8 +2576,8 @@ packages: react: 17 || 18 || 19 react-dom: 17 || 18 || 19 - '@vscode/codicons@0.0.45': - resolution: {integrity: sha512-1KAZ7XCMagp5Gdrlr4bbbcAqgcIL623iO1wW6rfcSVGAVUQvR0WP7bQx1SbJ11gmV3fdQTSEFIJQ/5C+HuVasw==} + '@vscode/codicons@0.0.46-24': + resolution: {integrity: sha512-KIDWUYxG6eh+DHRg+3G4bS487T+g1ZkLfB4HylOBbCcHsvLdfLMRM/m92DS1Ljhi8nglLr9ucwwWhHTEAC+DpA==} '@vscode/test-cli@0.0.15': resolution: {integrity: sha512-nAxk2X79wuXS7aOhyFFhFcCqd7EBUoMesu7ZgsYE/4eFjyBMuyIweVE94BxdKH1RieN8eOz2SIrljrZt6Lk9fQ==} @@ -2367,6 +2699,10 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + aria-query@5.3.0: resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} @@ -2773,6 +3109,9 @@ packages: resolution: {integrity: sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + detect-node@2.1.0: resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} @@ -3239,6 +3578,10 @@ packages: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + get-port-please@3.1.2: resolution: {integrity: sha512-Gxc29eLs1fbn6LQ4jSU4vXjlwyZhF5HsGuMAa7gqBP4Rw4yxxltyDUuF5MBclFzDTXO+ACchGQoeela4DSfzdQ==} @@ -4364,6 +4707,36 @@ packages: react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.7.2: + resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + react@19.2.8: resolution: {integrity: sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==} engines: {node: '>=0.10.0'} @@ -4936,6 +5309,26 @@ packages: url-join@4.0.1: resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + use-sync-external-store@1.6.0: resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} peerDependencies: @@ -5794,6 +6187,23 @@ snapshots: '@exodus/bytes@1.15.1': {} + '@floating-ui/core@1.8.0': + dependencies: + '@floating-ui/utils': 0.2.12 + + '@floating-ui/dom@1.8.0': + dependencies: + '@floating-ui/core': 1.8.0 + '@floating-ui/utils': 0.2.12 + + '@floating-ui/react-dom@2.1.9(react-dom@19.2.8)(react@19.2.8)': + dependencies: + '@floating-ui/dom': 1.8.0 + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + + '@floating-ui/utils@0.2.12': {} + '@humanfs/core@0.19.2': dependencies: '@humanfs/types': 0.15.0 @@ -6267,6 +6677,290 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true + '@radix-ui/primitive@1.1.7': {} + + '@radix-ui/react-arrow@1.1.15(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8)': + dependencies: + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-collection@1.1.15(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-slot': 1.3.3(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-compose-refs@1.1.5(@types/react@19.2.17)(react@19.2.8)': + dependencies: + react: 19.2.8 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-context-menu@2.3.7(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8)': + dependencies: + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-context': 1.2.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-menu': 2.1.24(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-context@1.2.2(@types/react@19.2.17)(react@19.2.8)': + dependencies: + react: 19.2.8 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-direction@1.1.4(@types/react@19.2.17)(react@19.2.8)': + dependencies: + react: 19.2.8 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-dismissable-layer@1.1.19(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8)': + dependencies: + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-effect-event': 0.0.5(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-dropdown-menu@2.1.24(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8)': + dependencies: + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-id': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-menu': 2.1.24(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-focus-guards@1.1.6(@types/react@19.2.17)(react@19.2.8)': + dependencies: + react: 19.2.8 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-focus-scope@1.1.16(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-id@1.1.4(@types/react@19.2.17)(react@19.2.8)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-menu@2.1.24(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8)': + dependencies: + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-direction': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-focus-guards': 1.1.6(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-id': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-slot': 1.3.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.17)(react@19.2.8) + aria-hidden: 1.2.6 + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.8) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-popper@1.3.7(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8)': + dependencies: + '@floating-ui/react-dom': 2.1.9(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-arrow': 1.1.15(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-rect': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-size': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/rect': 1.1.3 + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-portal@1.1.17(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8)': + dependencies: + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-presence@1.1.10(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-primitive@2.1.10(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8)': + dependencies: + '@radix-ui/react-slot': 1.3.3(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-roving-focus@1.1.19(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8)': + dependencies: + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-direction': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-id': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-is-hydrated': 0.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-slot@1.3.3(@types/react@19.2.17)(react@19.2.8)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-tooltip@1.2.16(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8)': + dependencies: + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-id': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + '@radix-ui/react-slot': 1.3.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-visually-hidden': 1.2.11(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-use-callback-ref@1.1.4(@types/react@19.2.17)(react@19.2.8)': + dependencies: + react: 19.2.8 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-controllable-state@1.2.6(@types/react@19.2.17)(react@19.2.8)': + dependencies: + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-use-effect-event': 0.0.5(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-effect-event@0.0.5(@types/react@19.2.17)(react@19.2.8)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-is-hydrated@0.1.3(@types/react@19.2.17)(react@19.2.8)': + dependencies: + react: 19.2.8 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-layout-effect@1.1.4(@types/react@19.2.17)(react@19.2.8)': + dependencies: + react: 19.2.8 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-rect@1.1.4(@types/react@19.2.17)(react@19.2.8)': + dependencies: + '@radix-ui/rect': 1.1.3 + react: 19.2.8 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-size@1.1.4(@types/react@19.2.17)(react@19.2.8)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.17)(react@19.2.8) + react: 19.2.8 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-visually-hidden@1.2.11(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8)': + dependencies: + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3)(@types/react@19.2.17)(react-dom@19.2.8)(react@19.2.8) + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/rect@1.1.3': {} + '@rolldown/binding-android-arm64@1.1.5': optional: true @@ -7022,23 +7716,23 @@ snapshots: convert-source-map: 2.0.0 tinyrainbow: 3.1.0 - '@vscode-elements/elements@2.5.1(@vscode/codicons@0.0.45)': + '@vscode-elements/elements@2.5.1(@vscode/codicons@0.0.46-24)': dependencies: '@lit/context': 1.1.6 - '@vscode/codicons': 0.0.45 + '@vscode/codicons': 0.0.46-24 lit: 3.3.3 - '@vscode-elements/react-elements@2.4.0(@types/react@19.2.17)(@vscode/codicons@0.0.45)(react-dom@19.2.8)(react@19.2.8)': + '@vscode-elements/react-elements@2.4.0(@types/react@19.2.17)(@vscode/codicons@0.0.46-24)(react-dom@19.2.8)(react@19.2.8)': dependencies: '@lit/react': 1.0.8(@types/react@19.2.17) - '@vscode-elements/elements': 2.5.1(@vscode/codicons@0.0.45) + '@vscode-elements/elements': 2.5.1(@vscode/codicons@0.0.46-24) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) transitivePeerDependencies: - '@types/react' - '@vscode/codicons' - '@vscode/codicons@0.0.45': {} + '@vscode/codicons@0.0.46-24': {} '@vscode/test-cli@0.0.15': dependencies: @@ -7189,6 +7883,10 @@ snapshots: argparse@2.0.1: {} + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + aria-query@5.3.0: dependencies: dequal: 2.0.3 @@ -7600,6 +8298,8 @@ snapshots: detect-newline@4.0.1: {} + detect-node-es@1.1.0: {} + detect-node@2.1.0: optional: true @@ -8158,6 +8858,8 @@ snapshots: hasown: 2.0.4 math-intrinsics: 1.1.0 + get-nonce@1.0.1: {} + get-port-please@3.1.2: {} get-proto@1.0.1: @@ -9572,6 +10274,33 @@ snapshots: react-is@17.0.2: {} + react-remove-scroll-bar@2.3.8(@types/react@19.2.17)(react@19.2.8): + dependencies: + react: 19.2.8 + react-style-singleton: 2.2.3(@types/react@19.2.17)(react@19.2.8) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.17 + + react-remove-scroll@2.7.2(@types/react@19.2.17)(react@19.2.8): + dependencies: + react: 19.2.8 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.17)(react@19.2.8) + react-style-singleton: 2.2.3(@types/react@19.2.17)(react@19.2.8) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.2.17)(react@19.2.8) + use-sidecar: 1.1.3(@types/react@19.2.17)(react@19.2.8) + optionalDependencies: + '@types/react': 19.2.17 + + react-style-singleton@2.2.3(@types/react@19.2.17)(react@19.2.8): + dependencies: + get-nonce: 1.0.1 + react: 19.2.8 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.17 + react@19.2.8: {} read-pkg@9.0.1: @@ -10208,6 +10937,21 @@ snapshots: url-join@4.0.1: {} + use-callback-ref@1.3.3(@types/react@19.2.17)(react@19.2.8): + dependencies: + react: 19.2.8 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.17 + + use-sidecar@1.1.3(@types/react@19.2.17)(react@19.2.8): + dependencies: + detect-node-es: 1.1.0 + react: 19.2.8 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.17 + use-sync-external-store@1.6.0(react@19.2.8): dependencies: react: 19.2.8 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 0d6f484a73..df06481594 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -12,7 +12,7 @@ catalog: "@types/vscode-webview": ^1.57.5 "@vitejs/plugin-react": ^6.0.4 "@vscode-elements/react-elements": ^2.4.0 - "@vscode/codicons": ^0.0.45 + "@vscode/codicons": 0.0.46-24 babel-plugin-react-compiler: ^1.0.0 coder: github:coder/coder#v2.34.1 date-fns: ^4.4.0