-
{children({
id,
diff --git a/packages/ui/src/components/ui/form-error.tsx b/packages/ui/src/components/ui/form-error.tsx
new file mode 100644
index 0000000..b7e8981
--- /dev/null
+++ b/packages/ui/src/components/ui/form-error.tsx
@@ -0,0 +1,27 @@
+import { AlertCircle } from 'lucide-react';
+
+import { cn } from '../../lib/utils';
+
+import { Alert, AlertDescription } from './alert';
+
+/**
+ * The one way this product shows a form or request error.
+ *
+ * Twenty-seven files had grown their own `
`, which is *almost* right — the role is there — but they differed in
+ * size, spacing and whether an icon appeared, so the same failure looked like
+ * three different severities depending on the screen.
+ *
+ * Renders nothing when there is no message, so callers can drop it in
+ * unconditionally instead of repeating a ternary.
+ */
+export function FormError({ message, className }: { message?: string | null; className?: string }) {
+ if (!message) return null;
+
+ return (
+
+
+ {message}
+
+ );
+}
diff --git a/packages/ui/src/components/ui/label.tsx b/packages/ui/src/components/ui/label.tsx
new file mode 100644
index 0000000..01a2d8c
--- /dev/null
+++ b/packages/ui/src/components/ui/label.tsx
@@ -0,0 +1,21 @@
+'use client';
+
+import { Label as LabelPrimitive } from 'radix-ui';
+import * as React from 'react';
+
+import { cn } from '../../lib/utils';
+
+function Label({ className, ...props }: React.ComponentProps) {
+ return (
+
+ );
+}
+
+export { Label };
diff --git a/packages/ui/src/components/ui/pagination.tsx b/packages/ui/src/components/ui/pagination.tsx
new file mode 100644
index 0000000..310374d
--- /dev/null
+++ b/packages/ui/src/components/ui/pagination.tsx
@@ -0,0 +1,118 @@
+import { ChevronLeftIcon, ChevronRightIcon, MoreHorizontalIcon } from 'lucide-react';
+import * as React from 'react';
+
+import { cn } from '../../lib/utils';
+
+import { buttonVariants, type Button } from './button';
+
+function Pagination({ className, ...props }: React.ComponentProps<'nav'>) {
+ return (
+
+ );
+}
+
+function PaginationContent({ className, ...props }: React.ComponentProps<'ul'>) {
+ return (
+
+ );
+}
+
+function PaginationItem({ ...props }: React.ComponentProps<'li'>) {
+ return ;
+}
+
+type PaginationLinkProps = {
+ isActive?: boolean;
+} & Pick, 'size'> &
+ React.ComponentProps<'a'>;
+
+// `children` is destructured rather than left in `...props` purely so
+// jsx-a11y/anchor-has-content can see it — the registry spreads it, and the
+// rule cannot follow that. Behaviour is unchanged.
+function PaginationLink({
+ className,
+ isActive,
+ size = 'icon',
+ children,
+ ...props
+}: PaginationLinkProps) {
+ return (
+
+ {children}
+
+ );
+}
+
+function PaginationPrevious({ className, ...props }: React.ComponentProps) {
+ return (
+
+
+ Previous
+
+ );
+}
+
+function PaginationNext({ className, ...props }: React.ComponentProps) {
+ return (
+
+ Next
+
+
+ );
+}
+
+function PaginationEllipsis({ className, ...props }: React.ComponentProps<'span'>) {
+ return (
+
+
+ More pages
+
+ );
+}
+
+export {
+ Pagination,
+ PaginationContent,
+ PaginationLink,
+ PaginationItem,
+ PaginationPrevious,
+ PaginationNext,
+ PaginationEllipsis,
+};
diff --git a/packages/ui/src/components/ui/popover.tsx b/packages/ui/src/components/ui/popover.tsx
new file mode 100644
index 0000000..d92f332
--- /dev/null
+++ b/packages/ui/src/components/ui/popover.tsx
@@ -0,0 +1,74 @@
+'use client';
+
+import { Popover as PopoverPrimitive } from 'radix-ui';
+import * as React from 'react';
+
+import { cn } from '../../lib/utils';
+
+function Popover({ ...props }: React.ComponentProps) {
+ return ;
+}
+
+function PopoverTrigger({ ...props }: React.ComponentProps) {
+ return ;
+}
+
+function PopoverContent({
+ className,
+ align = 'center',
+ sideOffset = 4,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+ );
+}
+
+function PopoverAnchor({ ...props }: React.ComponentProps) {
+ return ;
+}
+
+function PopoverHeader({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ );
+}
+
+function PopoverTitle({ className, ...props }: React.ComponentProps<'h2'>) {
+ return ;
+}
+
+function PopoverDescription({ className, ...props }: React.ComponentProps<'p'>) {
+ return (
+
+ );
+}
+
+export {
+ Popover,
+ PopoverTrigger,
+ PopoverContent,
+ PopoverAnchor,
+ PopoverHeader,
+ PopoverTitle,
+ PopoverDescription,
+};
diff --git a/packages/ui/src/components/ui/radio-group.tsx b/packages/ui/src/components/ui/radio-group.tsx
new file mode 100644
index 0000000..205626d
--- /dev/null
+++ b/packages/ui/src/components/ui/radio-group.tsx
@@ -0,0 +1,45 @@
+'use client';
+
+import { CircleIcon } from 'lucide-react';
+import { RadioGroup as RadioGroupPrimitive } from 'radix-ui';
+import * as React from 'react';
+
+import { cn } from '../../lib/utils';
+
+function RadioGroup({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function RadioGroupItem({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+
+
+ );
+}
+
+export { RadioGroup, RadioGroupItem };
diff --git a/packages/ui/src/components/ui/segmented-control.tsx b/packages/ui/src/components/ui/segmented-control.tsx
index 2ab09e9..eb9ef70 100644
--- a/packages/ui/src/components/ui/segmented-control.tsx
+++ b/packages/ui/src/components/ui/segmented-control.tsx
@@ -8,18 +8,25 @@ export interface SegmentedOption {
}
/**
- * A row of mutually exclusive filters.
+ * A row of mutually exclusive filters, as one joined pill.
*
- * Extracted from seven near-identical copies across the admin (discounts,
- * reviews, content, orders, products) that had drifted: some used
- * `aria-pressed`, some nothing; none had a focus ring; padding varied between
- * them. A filter control is exactly the kind of thing that must look and
- * behave the same everywhere, because an operator learns it once.
+ * Hand-rolled ARIA rather than shadcn's `RadioGroup`, and this is the third
+ * attempt — the first two are worth recording so nobody repeats them:
*
- * `radiogroup` rather than a row of toggle buttons: the options are mutually
- * exclusive, and that is what tells a screen reader "pick one of these" rather
- * than "here are five independent switches". Arrow keys move between options,
- * which is the native behaviour keyboard users expect from a radio group.
+ * 1. shadcn's `RadioGroupItem` hard-codes its children as a circular
+ * indicator and *ignores* anything passed to it. The labels rendered as
+ * blank 16px boxes.
+ * 2. Dropping to `RadioGroupPrimitive` fixed the labels, and then every item
+ * came out with `tabIndex="-1"` — Radix's roving focus did not initialise,
+ * so the whole control became unreachable by keyboard. Worse than what it
+ * replaced, and invisible unless you actually measure it.
+ *
+ * So the roving tabindex is explicit here. It is about fifteen lines, it is
+ * verifiable, and it does what a radio group is supposed to do: one tab stop
+ * for the group, arrows to move within it.
+ *
+ * This is the exception, not the pattern. Everything the registry covers well
+ * — dialogs, selects, tooltips, tables — uses the registry.
*/
export function SegmentedControl({
value,
@@ -32,8 +39,8 @@ export function SegmentedControl({
value: T;
onChange: (value: T) => void;
options: readonly SegmentedOption[];
- /** Names the group for assistive tech. Required — an unlabelled filter row
- * is announced as a bare list of buttons. */
+ /** Names the group. Required — an unlabelled filter row is announced as a
+ * bare list of buttons. */
label: string;
size?: 'sm' | 'md';
className?: string;
@@ -43,7 +50,7 @@ export function SegmentedControl({
if (delta === 0) return;
event.preventDefault();
- // Wraps, which is what a radio group does natively.
+ // Wraps, the way a native radio group does.
const next = options[(index + delta + options.length) % options.length];
if (next) onChange(next.value);
}
@@ -69,8 +76,8 @@ export function SegmentedControl({
onClick={() => onChange(option.value)}
onKeyDown={(event) => handleKeyDown(event, index)}
className={cn(
- 'duration-(--duration-base) cursor-pointer transition-colors',
- 'focus-visible:outline-ink-950 focus-visible:z-10 focus-visible:outline-2',
+ 'duration-(--duration-base) cursor-pointer whitespace-nowrap transition-colors',
+ 'focus-visible:ring-ring/50 focus-visible:z-10 focus-visible:outline-none focus-visible:ring-[3px]',
size === 'sm' ? 'px-2.5 py-1.5 text-xs' : 'px-3 py-2 text-sm',
active ? 'bg-ink-950 text-white' : 'hover:bg-ink-100 bg-white',
)}
diff --git a/packages/ui/src/components/ui/select.tsx b/packages/ui/src/components/ui/select.tsx
new file mode 100644
index 0000000..4d00434
--- /dev/null
+++ b/packages/ui/src/components/ui/select.tsx
@@ -0,0 +1,175 @@
+'use client';
+
+import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from 'lucide-react';
+import { Select as SelectPrimitive } from 'radix-ui';
+import * as React from 'react';
+
+import { cn } from '../../lib/utils';
+
+function Select({ ...props }: React.ComponentProps) {
+ return ;
+}
+
+function SelectGroup({ ...props }: React.ComponentProps) {
+ return ;
+}
+
+function SelectValue({ ...props }: React.ComponentProps) {
+ return ;
+}
+
+function SelectTrigger({
+ className,
+ size = 'default',
+ children,
+ ...props
+}: React.ComponentProps & {
+ size?: 'sm' | 'default';
+}) {
+ return (
+
+ {children}
+
+
+
+
+ );
+}
+
+function SelectContent({
+ className,
+ children,
+ position = 'item-aligned',
+ align = 'center',
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+
+ {children}
+
+
+
+
+ );
+}
+
+function SelectLabel({ className, ...props }: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function SelectItem({
+ className,
+ children,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+
+
+
+ {children}
+
+ );
+}
+
+function SelectSeparator({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function SelectScrollUpButton({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+ );
+}
+
+function SelectScrollDownButton({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+ );
+}
+
+export {
+ Select,
+ SelectContent,
+ SelectGroup,
+ SelectItem,
+ SelectLabel,
+ SelectScrollDownButton,
+ SelectScrollUpButton,
+ SelectSeparator,
+ SelectTrigger,
+ SelectValue,
+};
diff --git a/packages/ui/src/components/ui/separator.tsx b/packages/ui/src/components/ui/separator.tsx
new file mode 100644
index 0000000..76f0368
--- /dev/null
+++ b/packages/ui/src/components/ui/separator.tsx
@@ -0,0 +1,28 @@
+'use client';
+
+import { Separator as SeparatorPrimitive } from 'radix-ui';
+import * as React from 'react';
+
+import { cn } from '../../lib/utils';
+
+function Separator({
+ className,
+ orientation = 'horizontal',
+ decorative = true,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+export { Separator };
diff --git a/packages/ui/src/components/ui/sonner.tsx b/packages/ui/src/components/ui/sonner.tsx
new file mode 100644
index 0000000..9a029c6
--- /dev/null
+++ b/packages/ui/src/components/ui/sonner.tsx
@@ -0,0 +1,40 @@
+'use client';
+
+import {
+ CircleCheckIcon,
+ InfoIcon,
+ Loader2Icon,
+ OctagonXIcon,
+ TriangleAlertIcon,
+} from 'lucide-react';
+import { useTheme } from 'next-themes';
+import { Toaster as Sonner, type ToasterProps } from 'sonner';
+
+const Toaster = ({ ...props }: ToasterProps) => {
+ const { theme = 'system' } = useTheme();
+
+ return (
+ ,
+ info: ,
+ warning: ,
+ error: ,
+ loading: ,
+ }}
+ style={
+ {
+ '--normal-bg': 'var(--popover)',
+ '--normal-text': 'var(--popover-foreground)',
+ '--normal-border': 'var(--border)',
+ '--border-radius': 'var(--radius)',
+ } as React.CSSProperties
+ }
+ {...props}
+ />
+ );
+};
+
+export { Toaster };
diff --git a/packages/ui/src/components/ui/switch.tsx b/packages/ui/src/components/ui/switch.tsx
new file mode 100644
index 0000000..cfec123
--- /dev/null
+++ b/packages/ui/src/components/ui/switch.tsx
@@ -0,0 +1,35 @@
+'use client';
+
+import { Switch as SwitchPrimitive } from 'radix-ui';
+import * as React from 'react';
+
+import { cn } from '../../lib/utils';
+
+function Switch({
+ className,
+ size = 'default',
+ ...props
+}: React.ComponentProps & {
+ size?: 'sm' | 'default';
+}) {
+ return (
+
+
+
+ );
+}
+
+export { Switch };
diff --git a/packages/ui/src/components/ui/table.tsx b/packages/ui/src/components/ui/table.tsx
new file mode 100644
index 0000000..6b9705a
--- /dev/null
+++ b/packages/ui/src/components/ui/table.tsx
@@ -0,0 +1,92 @@
+'use client';
+
+import * as React from 'react';
+
+import { cn } from '../../lib/utils';
+
+function Table({ className, ...props }: React.ComponentProps<'table'>) {
+ return (
+
+ );
+}
+
+function TableHeader({ className, ...props }: React.ComponentProps<'thead'>) {
+ return ;
+}
+
+function TableBody({ className, ...props }: React.ComponentProps<'tbody'>) {
+ return (
+
+ );
+}
+
+function TableFooter({ className, ...props }: React.ComponentProps<'tfoot'>) {
+ return (
+ tr]:last:border-b-0', className)}
+ {...props}
+ />
+ );
+}
+
+function TableRow({ className, ...props }: React.ComponentProps<'tr'>) {
+ return (
+
+ );
+}
+
+function TableHead({ className, ...props }: React.ComponentProps<'th'>) {
+ return (
+ [role=checkbox]]:translate-y-[2px]',
+ className,
+ )}
+ {...props}
+ />
+ );
+}
+
+function TableCell({ className, ...props }: React.ComponentProps<'td'>) {
+ return (
+ | [role=checkbox]]:translate-y-[2px]',
+ className,
+ )}
+ {...props}
+ />
+ );
+}
+
+function TableCaption({ className, ...props }: React.ComponentProps<'caption'>) {
+ return (
+
+ );
+}
+
+export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption };
diff --git a/packages/ui/src/components/ui/textarea.tsx b/packages/ui/src/components/ui/textarea.tsx
new file mode 100644
index 0000000..eb8d5d5
--- /dev/null
+++ b/packages/ui/src/components/ui/textarea.tsx
@@ -0,0 +1,18 @@
+import * as React from 'react';
+
+import { cn } from '../../lib/utils';
+
+function Textarea({ className, ...props }: React.ComponentProps<'textarea'>) {
+ return (
+
+ );
+}
+
+export { Textarea };
diff --git a/packages/ui/src/components/ui/tooltip.tsx b/packages/ui/src/components/ui/tooltip.tsx
new file mode 100644
index 0000000..7de7e34
--- /dev/null
+++ b/packages/ui/src/components/ui/tooltip.tsx
@@ -0,0 +1,53 @@
+'use client';
+
+import { Tooltip as TooltipPrimitive } from 'radix-ui';
+import * as React from 'react';
+
+import { cn } from '../../lib/utils';
+
+function TooltipProvider({
+ delayDuration = 0,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function Tooltip({ ...props }: React.ComponentProps) {
+ return ;
+}
+
+function TooltipTrigger({ ...props }: React.ComponentProps) {
+ return ;
+}
+
+function TooltipContent({
+ className,
+ sideOffset = 0,
+ children,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+ {children}
+
+
+
+ );
+}
+
+export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts
index f4d5aab..46e726e 100644
--- a/packages/ui/src/index.ts
+++ b/packages/ui/src/index.ts
@@ -91,10 +91,93 @@ export { Tabs, TabsContent, TabsList, TabsTrigger, tabsListVariants } from './co
* that had already drifted across the storefront and the admin. They live here
* rather than in either app because both use them.
*/
+/**
+ * ---- shadcn registry -------------------------------------------------------
+ *
+ * Added with `npx shadcn@latest add …` and kept as close to the registry as
+ * possible, so anything copied from ui.shadcn.com works unedited.
+ *
+ * TWO EDITS ARE APPLIED TO EVERY COMPONENT THE CLI WRITES, and they are not
+ * optional:
+ *
+ * 1. `@/lib/utils` becomes a relative import. These files are compiled by the
+ * *apps* via `transpilePackages`, where `@/*` resolves to the app's own
+ * `src` — so the alias silently points at the wrong file.
+ * 2. Quotes and semicolons are normalised by Prettier; the registry ships a
+ * different style.
+ *
+ * Re-running the CLI over an existing component OVERWRITES it. `button.tsx`
+ * carries deliberate departures (square corners, the volt `accent` variant, a
+ * transparent `outline` that stays legible on the dark hero) and was silently
+ * reverted once already. Use `--overwrite` only when you mean it, and re-check
+ * the diff afterwards.
+ */
+export { Alert, AlertDescription, AlertTitle } from './components/ui/alert';
+export { Avatar, AvatarFallback, AvatarImage } from './components/ui/avatar';
+export {
+ Breadcrumb,
+ BreadcrumbEllipsis,
+ BreadcrumbItem,
+ BreadcrumbLink,
+ BreadcrumbList,
+ BreadcrumbPage,
+ BreadcrumbSeparator,
+} from './components/ui/breadcrumb';
+export {
+ Card,
+ CardAction,
+ CardContent,
+ CardDescription,
+ CardFooter,
+ CardHeader,
+ CardTitle,
+} from './components/ui/card';
+export { Checkbox } from './components/ui/checkbox';
+export { Label } from './components/ui/label';
+export {
+ Pagination,
+ PaginationContent,
+ PaginationEllipsis,
+ PaginationItem,
+ PaginationLink,
+ PaginationNext,
+ PaginationPrevious,
+} from './components/ui/pagination';
+export { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from './components/ui/popover';
+export { RadioGroup, RadioGroupItem } from './components/ui/radio-group';
+export {
+ Select,
+ SelectContent,
+ SelectGroup,
+ SelectItem,
+ SelectLabel,
+ SelectScrollDownButton,
+ SelectScrollUpButton,
+ SelectSeparator,
+ SelectTrigger,
+ SelectValue,
+} from './components/ui/select';
+export { Separator } from './components/ui/separator';
+export { Toaster } from './components/ui/sonner';
+export { Switch } from './components/ui/switch';
+export {
+ Table,
+ TableBody,
+ TableCaption,
+ TableCell,
+ TableFooter,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from './components/ui/table';
+export { Textarea } from './components/ui/textarea';
+export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './components/ui/tooltip';
+
export { SegmentedControl } from './components/ui/segmented-control';
export type { SegmentedOption } from './components/ui/segmented-control';
export { Rating } from './components/ui/rating';
export { EmptyState } from './components/ui/empty-state';
+export { FormError } from './components/ui/form-error';
export { Field } from './components/ui/field';
export { SkipLink } from './components/ui/skip-link';
export {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 415060a..d90d1b9 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -444,9 +444,15 @@ importers:
lucide-react:
specifier: 1.31.0
version: 1.31.0(react@19.2.8)
+ next-themes:
+ specifier: ^0.4.6
+ version: 0.4.6(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
radix-ui:
specifier: 1.6.7
version: 1.6.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
+ sonner:
+ specifier: ^2.0.8
+ version: 2.0.8(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
tailwind-merge:
specifier: ^3.4.0
version: 3.6.0
@@ -5252,6 +5258,12 @@ packages:
typescript:
optional: true
+ next-themes@0.4.6:
+ resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==}
+ peerDependencies:
+ react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
+
next@16.3.0:
resolution: {integrity: sha512-NEdGOzH+08eTXMUp9UYkA99Nhi5N6Thrhc1jgFOQgfgnGK/dA2hRwBpXep+exdFQrnwlRf/3Wixyp8lLBUpE2A==}
engines: {node: '>=20.9.0'}
@@ -5905,6 +5917,16 @@ packages:
sonic-boom@4.2.1:
resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==}
+ sonner@2.0.8:
+ resolution: {integrity: sha512-UM/ByIoFra8yzV75n1o0Puu0bw5U/9UNnDacrJNspekBewIfsQ3D6ez1nvlWpt7aTsO6rujQtifBpycwIivqlg==}
+ peerDependencies:
+ '@types/react': ^18.0.0 || ^19.0.0
+ react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
+ react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
source-map-js@1.2.1:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
@@ -11901,6 +11923,11 @@ snapshots:
transitivePeerDependencies:
- '@swc/helpers'
+ next-themes@0.4.6(react-dom@19.2.8(react@19.2.8))(react@19.2.8):
+ dependencies:
+ react: 19.2.8
+ react-dom: 19.2.8(react@19.2.8)
+
next@16.3.0(@types/node@22.20.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8):
dependencies:
'@next/env': 16.3.0
@@ -12676,6 +12703,13 @@ snapshots:
dependencies:
atomic-sleep: 1.0.0
+ sonner@2.0.8(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8):
+ dependencies:
+ react: 19.2.8
+ react-dom: 19.2.8(react@19.2.8)
+ optionalDependencies:
+ '@types/react': 19.2.18
+
source-map-js@1.2.1: {}
source-map-support@0.5.13:
|