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 => (
+
+
+
+ Workspace actions
+
+
+
+
+
+ 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: () => (
+
+
+
+ Workspace actions
+
+
+
+ {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: (
+
+ Stop
+
+ ),
+ },
+};
+
+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