@vendure-io/ui 1.3.0 → 2.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/README.md +5 -5
  2. package/package.json +9 -4
  3. package/src/components/{ui → atoms}/alert-dialog.tsx +4 -4
  4. package/src/components/{ui → atoms}/badge.tsx +6 -3
  5. package/src/components/{ui → atoms}/button-group.tsx +1 -2
  6. package/src/components/{ui → atoms}/button.tsx +8 -2
  7. package/src/components/{ui → atoms}/calendar.tsx +1 -1
  8. package/src/components/{ui → atoms}/card.tsx +2 -3
  9. package/src/components/{ui → atoms}/carousel.tsx +1 -1
  10. package/src/components/atoms/checkbox.tsx +29 -0
  11. package/src/components/{ui → atoms}/combobox.tsx +3 -4
  12. package/src/components/{ui → atoms}/command.tsx +2 -2
  13. package/src/components/{ui → atoms}/context-menu.tsx +1 -1
  14. package/src/components/{ui → atoms}/dialog.tsx +4 -4
  15. package/src/components/{ui → atoms}/drawer.tsx +3 -3
  16. package/src/components/{ui → atoms}/dropdown-menu.tsx +3 -2
  17. package/src/components/{ui → atoms}/empty.tsx +1 -1
  18. package/src/components/{ui → atoms}/field.tsx +2 -2
  19. package/src/components/{ui → atoms}/hover-card.tsx +1 -1
  20. package/src/components/{ui → atoms}/input-group.tsx +3 -4
  21. package/src/components/{ui → atoms}/input-otp.tsx +0 -1
  22. package/src/components/{ui → atoms}/input.tsx +0 -1
  23. package/src/components/{ui → atoms}/item.tsx +2 -2
  24. package/src/components/{ui → atoms}/menubar.tsx +3 -4
  25. package/src/components/{ui → atoms}/native-select.tsx +0 -1
  26. package/src/components/{ui → atoms}/navigation-menu.tsx +7 -4
  27. package/src/components/{ui → atoms}/pagination.tsx +1 -1
  28. package/src/components/{ui → atoms}/popover.tsx +2 -2
  29. package/src/components/{ui → atoms}/select.tsx +22 -4
  30. package/src/components/{ui → atoms}/sheet.tsx +4 -4
  31. package/src/components/{ui → atoms}/sidebar.tsx +6 -6
  32. package/src/components/atoms/skeleton.tsx +16 -0
  33. package/src/components/{ui → atoms}/slider.tsx +0 -1
  34. package/src/components/{ui → atoms}/sonner.tsx +1 -1
  35. package/src/components/{ui → atoms}/switch.tsx +0 -1
  36. package/src/components/{ui → atoms}/tabs.tsx +6 -4
  37. package/src/components/{ui → atoms}/textarea.tsx +0 -1
  38. package/src/components/{ui → atoms}/toggle-group.tsx +3 -3
  39. package/src/components/{ui → atoms}/toggle.tsx +0 -1
  40. package/src/components/{ui → atoms}/tooltip.tsx +2 -1
  41. package/src/components/molecules/anonymized-token.tsx +170 -0
  42. package/src/components/molecules/chip.tsx +85 -0
  43. package/src/components/{custom → molecules}/combobox-free-text.tsx +7 -3
  44. package/src/components/molecules/confirm-dialog.tsx +108 -0
  45. package/src/components/molecules/copyable-text.tsx +102 -0
  46. package/src/components/molecules/data-table/data-table-bulk-actions.tsx +69 -0
  47. package/src/components/molecules/data-table/data-table-column-header.tsx +61 -0
  48. package/src/components/molecules/data-table/data-table-filters.tsx +198 -0
  49. package/src/components/molecules/data-table/data-table-helpers.tsx +73 -0
  50. package/src/components/molecules/data-table/data-table-types.tsx +241 -0
  51. package/src/components/molecules/data-table/data-table-view-options.tsx +73 -0
  52. package/src/components/molecules/data-table/data-table.tsx +500 -0
  53. package/src/components/molecules/data-table/list-header.tsx +53 -0
  54. package/src/components/molecules/data-table/table-pagination.tsx +263 -0
  55. package/src/components/molecules/date-time.tsx +73 -0
  56. package/src/components/molecules/description-list.tsx +120 -0
  57. package/src/components/molecules/format-provider.tsx +46 -0
  58. package/src/components/molecules/id-chip.tsx +79 -0
  59. package/src/components/molecules/illustrations/access-denied.tsx +55 -0
  60. package/src/components/molecules/illustrations/empty-collection.tsx +66 -0
  61. package/src/components/molecules/illustrations/empty-database.tsx +44 -0
  62. package/src/components/molecules/illustrations/empty-media.tsx +68 -0
  63. package/src/components/molecules/illustrations/error.tsx +64 -0
  64. package/src/components/molecules/illustrations/first-run.tsx +55 -0
  65. package/src/components/molecules/illustrations/illustration-types.tsx +9 -0
  66. package/src/components/molecules/illustrations/no-activity.tsx +49 -0
  67. package/src/components/molecules/illustrations/no-deployments.tsx +49 -0
  68. package/src/components/molecules/illustrations/no-documents.tsx +67 -0
  69. package/src/components/molecules/illustrations/no-keys.tsx +50 -0
  70. package/src/components/molecules/illustrations/no-logs.tsx +53 -0
  71. package/src/components/molecules/illustrations/no-members.tsx +56 -0
  72. package/src/components/molecules/illustrations/no-notifications.tsx +52 -0
  73. package/src/components/molecules/illustrations/no-orders.tsx +48 -0
  74. package/src/components/molecules/illustrations/no-plugins.tsx +72 -0
  75. package/src/components/molecules/illustrations/no-results.tsx +69 -0
  76. package/src/components/molecules/illustrations/not-found.tsx +48 -0
  77. package/src/components/molecules/illustrations/offline.tsx +43 -0
  78. package/src/components/molecules/illustrations/pending-approval.tsx +56 -0
  79. package/src/components/molecules/illustrations/upload-dropzone.tsx +59 -0
  80. package/src/components/molecules/money.tsx +91 -0
  81. package/src/components/{custom → molecules}/multi-select.tsx +2 -2
  82. package/src/components/molecules/page-header.tsx +80 -0
  83. package/src/components/molecules/password-input.tsx +47 -0
  84. package/src/components/molecules/relative-time.tsx +81 -0
  85. package/src/components/molecules/stat-card.tsx +134 -0
  86. package/src/components/molecules/state-views/empty-state.tsx +75 -0
  87. package/src/components/molecules/state-views/error-state.tsx +91 -0
  88. package/src/components/molecules/state-views/loading-state.tsx +80 -0
  89. package/src/components/molecules/status-badge.tsx +100 -0
  90. package/src/hooks/use-copy.ts +51 -0
  91. package/src/lib/base-ui.ts +1 -1
  92. package/src/lib/format-relative.ts +41 -0
  93. package/src/lib/state-dictionary.ts +137 -0
  94. package/src/components/ui/checkbox.tsx +0 -30
  95. package/src/components/ui/skeleton.tsx +0 -13
  96. /package/src/components/{ui → atoms}/accordion.tsx +0 -0
  97. /package/src/components/{ui → atoms}/alert.tsx +0 -0
  98. /package/src/components/{ui → atoms}/aspect-ratio.tsx +0 -0
  99. /package/src/components/{ui → atoms}/avatar.tsx +0 -0
  100. /package/src/components/{ui → atoms}/breadcrumb.tsx +0 -0
  101. /package/src/components/{ui → atoms}/chart.tsx +0 -0
  102. /package/src/components/{ui → atoms}/collapsible.tsx +0 -0
  103. /package/src/components/{ui → atoms}/direction.tsx +0 -0
  104. /package/src/components/{ui → atoms}/kbd.tsx +0 -0
  105. /package/src/components/{ui → atoms}/label.tsx +0 -0
  106. /package/src/components/{ui → atoms}/progress.tsx +0 -0
  107. /package/src/components/{ui → atoms}/radio-group.tsx +0 -0
  108. /package/src/components/{ui → atoms}/resizable.tsx +0 -0
  109. /package/src/components/{ui → atoms}/scroll-area.tsx +0 -0
  110. /package/src/components/{ui → atoms}/separator.tsx +0 -0
  111. /package/src/components/{ui → atoms}/spinner.tsx +0 -0
  112. /package/src/components/{ui → atoms}/table.tsx +0 -0
package/README.md CHANGED
@@ -18,7 +18,7 @@ Optional peers: `next`, `next-themes`, `react-hook-form`
18
18
  ## Usage
19
19
 
20
20
  ```tsx
21
- import { Button } from "@vendure-io/ui/components/ui/button";
21
+ import { Button } from "@vendure-io/ui/components/atoms/button";
22
22
  import { cn } from "@vendure-io/ui/lib/utils";
23
23
  ```
24
24
 
@@ -26,15 +26,15 @@ import { cn } from "@vendure-io/ui/lib/utils";
26
26
 
27
27
  | Export | Description |
28
28
  |--------|-------------|
29
- | `@vendure-io/ui/components/ui/*` | shadcn/ui primitives (button, dialog, input, etc.) |
30
- | `@vendure-io/ui/components/custom/*` | Vendure-specific components |
29
+ | `@vendure-io/ui/components/atoms/*` | shadcn/ui primitives (button, dialog, input, etc.) |
30
+ | `@vendure-io/ui/components/molecules/*` | Hand-written composed Vendure components |
31
31
  | `@vendure-io/ui/lib/*` | Utilities (`cn`, etc.) |
32
32
  | `@vendure-io/ui/lib/base-ui` | `@base-ui/react` primitive namespaces (see below) |
33
33
  | `@vendure-io/ui/hooks/*` | Shared React hooks |
34
34
 
35
35
  ## Customizing wrapper components
36
36
 
37
- The components under `components/ui/*` are thin wrappers around [`@base-ui/react`](https://base-ui.com/) primitives. To override a single subcomponent (e.g. swap `DialogTitle` for one with a different font) while re-using the rest, import the underlying primitive namespace from `@vendure-io/ui/lib/base-ui` rather than from `@base-ui/react` directly:
37
+ The components under `components/atoms/*` are thin wrappers around [`@base-ui/react`](https://base-ui.com/) primitives. To override a single subcomponent (e.g. swap `DialogTitle` for one with a different font) while re-using the rest, import the underlying primitive namespace from `@vendure-io/ui/lib/base-ui` rather than from `@base-ui/react` directly:
38
38
 
39
39
  ```tsx
40
40
  // In your own dialog.tsx
@@ -49,7 +49,7 @@ import {
49
49
  DialogOverlay,
50
50
  DialogPortal,
51
51
  DialogTrigger,
52
- } from "@vendure-io/ui/components/ui/dialog";
52
+ } from "@vendure-io/ui/components/atoms/dialog";
53
53
 
54
54
  export {
55
55
  Dialog,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vendure-io/ui",
3
- "version": "1.3.0",
3
+ "version": "2.0.0-beta.0",
4
4
  "description": "React component library for Vendure, built on shadcn/ui and Tailwind v4",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "homepage": "https://github.com/vendurehq/design/tree/main/packages/ui",
@@ -12,18 +12,22 @@
12
12
  "type": "module",
13
13
  "sideEffects": false,
14
14
  "exports": {
15
- "./components/ui/*": "./src/components/ui/*.tsx",
16
- "./components/custom/*": "./src/components/custom/*.tsx",
15
+ "./components/atoms/*": "./src/components/atoms/*.tsx",
16
+ "./components/molecules/*": "./src/components/molecules/*.tsx",
17
17
  "./lib/*": "./src/lib/*.ts",
18
18
  "./hooks/*": "./src/hooks/*.ts"
19
19
  },
20
20
  "files": [
21
21
  "src",
22
+ "!src/**/*.test.ts",
23
+ "!src/**/*.test.tsx",
22
24
  "README.md"
23
25
  ],
24
26
  "scripts": {
25
27
  "lint": "biome check src/",
26
- "check-types": "tsc --noEmit"
28
+ "check-types": "tsc --noEmit",
29
+ "test": "bun test",
30
+ "pack:check": "bun pm pack --dry-run"
27
31
  },
28
32
  "peerDependencies": {
29
33
  "react": ">=19",
@@ -45,6 +49,7 @@
45
49
  },
46
50
  "dependencies": {
47
51
  "@base-ui/react": "^1.2.0",
52
+ "@tanstack/react-table": "^8.21.3",
48
53
  "@vendure-io/design-tokens": "^1.2.0",
49
54
  "class-variance-authority": "^0.7.1",
50
55
  "clsx": "^2.1.1",
@@ -4,7 +4,7 @@ import * as React from "react"
4
4
  import { AlertDialog as AlertDialogPrimitive } from "@base-ui/react/alert-dialog"
5
5
 
6
6
  import { cn } from "@vendure-io/ui/lib/utils"
7
- import { Button } from "@vendure-io/ui/components/ui/button"
7
+ import { Button } from "@vendure-io/ui/components/atoms/button"
8
8
 
9
9
  function AlertDialog({ ...props }: AlertDialogPrimitive.Root.Props) {
10
10
  return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />
@@ -30,7 +30,7 @@ function AlertDialogOverlay({
30
30
  <AlertDialogPrimitive.Backdrop
31
31
  data-slot="alert-dialog-overlay"
32
32
  className={cn(
33
- "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs",
33
+ "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 fixed inset-0 isolate z-50 bg-black/10 motion-reduce:animate-none data-open:duration-(--transition-duration-normal) data-open:ease-(--ease-out) data-closed:duration-(--transition-duration-fast) data-closed:ease-(--ease-in) supports-backdrop-filter:backdrop-blur-xs",
34
34
  className
35
35
  )}
36
36
  {...props}
@@ -52,7 +52,7 @@ function AlertDialogContent({
52
52
  data-slot="alert-dialog-content"
53
53
  data-size={size}
54
54
  className={cn(
55
- "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 bg-background ring-foreground/10 group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-6 rounded-xl p-6 ring-1 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-lg",
55
+ "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 bg-overlay ring-foreground/10 group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-6 rounded-xl p-6 ring-1 motion-reduce:animate-none data-open:duration-(--transition-duration-normal) data-open:ease-(--ease-out) data-closed:duration-(--transition-duration-fast) data-closed:ease-(--ease-in) outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-lg",
56
56
  className
57
57
  )}
58
58
  {...props}
@@ -117,7 +117,7 @@ function AlertDialogTitle({
117
117
  <AlertDialogPrimitive.Title
118
118
  data-slot="alert-dialog-title"
119
119
  className={cn(
120
- "text-lg font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2",
120
+ "text-style-section-title sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2",
121
121
  className
122
122
  )}
123
123
  {...props}
@@ -9,9 +9,12 @@ const badgeVariants = cva(
9
9
  {
10
10
  variants: {
11
11
  variant: {
12
- default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
13
- secondary:
14
- "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
12
+ // Neutral by default: brand is a signature, not a wallpaper. Solid
13
+ // brand is an explicit opt-in via the `brand` variant (ui v2).
14
+ default:
15
+ "bg-neutral-subtle text-neutral-subtle-foreground border-neutral-border [a]:hover:bg-neutral-subtle/80",
16
+ primary: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
17
+ brand: "bg-brand text-brand-foreground [a]:hover:bg-brand/80",
15
18
  destructive:
16
19
  "bg-destructive/10 [a]:hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 text-destructive dark:bg-destructive/20",
17
20
  outline:
@@ -3,7 +3,7 @@ import { useRender } from "@base-ui/react/use-render"
3
3
  import { cva, type VariantProps } from "class-variance-authority"
4
4
 
5
5
  import { cn } from "@vendure-io/ui/lib/utils"
6
- import { Separator } from "@vendure-io/ui/components/ui/separator"
6
+ import { Separator } from "@vendure-io/ui/components/atoms/separator"
7
7
 
8
8
  const buttonGroupVariants = cva(
9
9
  "has-[>[data-slot=button-group]]:gap-2 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md flex w-fit items-stretch *:focus-visible:z-10 *:focus-visible:relative [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
@@ -38,7 +38,6 @@ function ButtonGroup({
38
38
  )
39
39
  }
40
40
 
41
- // [vendure] shadow removed for flat look — restore if overwritten by shadcn upgrade
42
41
  function ButtonGroupText({
43
42
  className,
44
43
  render,
@@ -5,9 +5,8 @@ import { cva, type VariantProps } from "class-variance-authority"
5
5
 
6
6
  import { cn } from "@vendure-io/ui/lib/utils"
7
7
 
8
- // [vendure] shadow removed for flat look — restore if overwritten by shadcn upgrade
9
8
  const buttonVariants = cva(
10
- "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-md border border-transparent bg-clip-padding text-sm font-medium focus-visible:ring-3 aria-invalid:ring-3 [&_svg:not([class*='size-'])]:size-4 inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none",
9
+ "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-md border border-transparent bg-clip-padding text-sm font-medium focus-visible:ring-3 aria-invalid:ring-3 [&_svg:not([class*='size-'])]:size-4 inline-flex items-center justify-center whitespace-nowrap transition-all duration-(--transition-duration-fast) ease-(--ease-default) data-pressed:brightness-95 dark:data-pressed:brightness-110 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none",
11
10
  {
12
11
  variants: {
13
12
  variant: {
@@ -47,12 +46,19 @@ function Button({
47
46
  className,
48
47
  variant = "default",
49
48
  size = "default",
49
+ render,
50
+ nativeButton,
50
51
  ...props
51
52
  }: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {
52
53
  return (
53
54
  <ButtonPrimitive
54
55
  data-slot="button"
55
56
  className={cn(buttonVariants({ variant, size, className }))}
57
+ // Base UI warns when `render` swaps in a non-native element unless
58
+ // nativeButton is false. Default it off when rendering as something else
59
+ // (e.g. an anchor) so consumers don't have to pass it every time.
60
+ render={render}
61
+ nativeButton={render ? (nativeButton ?? false) : nativeButton}
56
62
  {...props}
57
63
  />
58
64
  )
@@ -9,7 +9,7 @@ import {
9
9
  } from "react-day-picker"
10
10
 
11
11
  import { cn } from "@vendure-io/ui/lib/utils"
12
- import { Button, buttonVariants } from "@vendure-io/ui/components/ui/button"
12
+ import { Button, buttonVariants } from "@vendure-io/ui/components/atoms/button"
13
13
  import { ChevronLeftIcon, ChevronRightIcon, ChevronDownIcon } from "lucide-react"
14
14
 
15
15
  function Calendar({
@@ -2,7 +2,6 @@ import * as React from "react"
2
2
 
3
3
  import { cn } from "@vendure-io/ui/lib/utils"
4
4
 
5
- // [vendure] shadow removed for flat look — restore if overwritten by shadcn upgrade
6
5
  function Card({
7
6
  className,
8
7
  size = "default",
@@ -13,7 +12,7 @@ function Card({
13
12
  data-slot="card"
14
13
  data-size={size}
15
14
  className={cn(
16
- "ring-foreground/10 bg-card text-card-foreground group/card flex flex-col gap-6 overflow-hidden rounded-xl py-6 text-sm ring-1 has-[>img:first-child]:pt-0 data-[size=sm]:gap-4 data-[size=sm]:py-4 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
15
+ "bg-card text-card-foreground group/card flex flex-col gap-6 overflow-hidden rounded-xl py-6 text-sm has-[>img:first-child]:pt-0 data-[size=sm]:gap-4 data-[size=sm]:py-4 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
17
16
  className
18
17
  )}
19
18
  {...props}
@@ -39,7 +38,7 @@ function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
39
38
  <div
40
39
  data-slot="card-title"
41
40
  className={cn(
42
- "text-base leading-normal font-medium group-data-[size=sm]/card:text-sm",
41
+ "text-style-card-title group-data-[size=sm]/card:text-sm",
43
42
  className
44
43
  )}
45
44
  {...props}
@@ -6,7 +6,7 @@ import useEmblaCarousel, {
6
6
  } from "embla-carousel-react"
7
7
 
8
8
  import { cn } from "@vendure-io/ui/lib/utils"
9
- import { Button } from "@vendure-io/ui/components/ui/button"
9
+ import { Button } from "@vendure-io/ui/components/atoms/button"
10
10
  import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react"
11
11
 
12
12
  type CarouselApi = UseEmblaCarouselType[1]
@@ -0,0 +1,29 @@
1
+ "use client"
2
+
3
+ import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox"
4
+
5
+ import { cn } from "@vendure-io/ui/lib/utils"
6
+ import { CheckIcon, MinusIcon } from "lucide-react"
7
+
8
+ function Checkbox({ className, indeterminate, ...props }: CheckboxPrimitive.Root.Props) {
9
+ return (
10
+ <CheckboxPrimitive.Root
11
+ data-slot="checkbox"
12
+ className={cn(
13
+ "border-input dark:bg-input/30 data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary data-checked:border-primary data-indeterminate:bg-primary data-indeterminate:text-primary-foreground dark:data-indeterminate:bg-primary data-indeterminate:border-primary aria-invalid:aria-checked:border-primary aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 peer relative flex size-4 shrink-0 items-center justify-center rounded-[4px] border transition-shadow outline-none group-has-disabled/field:opacity-50 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:ring-3 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-3",
14
+ className
15
+ )}
16
+ indeterminate={indeterminate}
17
+ {...props}
18
+ >
19
+ <CheckboxPrimitive.Indicator
20
+ data-slot="checkbox-indicator"
21
+ className="grid place-content-center text-current transition-none [&>svg]:size-3.5"
22
+ >
23
+ {indeterminate ? <MinusIcon /> : <CheckIcon />}
24
+ </CheckboxPrimitive.Indicator>
25
+ </CheckboxPrimitive.Root>
26
+ )
27
+ }
28
+
29
+ export { Checkbox }
@@ -4,13 +4,13 @@ import * as React from "react"
4
4
  import { Combobox as ComboboxPrimitive } from "@base-ui/react"
5
5
 
6
6
  import { cn } from "@vendure-io/ui/lib/utils"
7
- import { Button } from "@vendure-io/ui/components/ui/button"
7
+ import { Button } from "@vendure-io/ui/components/atoms/button"
8
8
  import {
9
9
  InputGroup,
10
10
  InputGroupAddon,
11
11
  InputGroupButton,
12
12
  InputGroupInput,
13
- } from "@vendure-io/ui/components/ui/input-group"
13
+ } from "@vendure-io/ui/components/atoms/input-group"
14
14
  import { ChevronDownIcon, XIcon, CheckIcon } from "lucide-react"
15
15
 
16
16
  const Combobox = ComboboxPrimitive.Root
@@ -110,7 +110,7 @@ function ComboboxContent({
110
110
  <ComboboxPrimitive.Popup
111
111
  data-slot="combobox-content"
112
112
  data-chips={!!anchor}
113
- className={cn("bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 *:data-[slot=input-group]:bg-input/30 *:data-[slot=input-group]:border-input/30 data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2 group/combobox-content relative max-h-(--available-height) w-(--anchor-width) max-w-(--available-width) min-w-[calc(var(--anchor-width)+--spacing(7))] origin-(--transform-origin) overflow-hidden rounded-md shadow-md ring-1 duration-100 data-[chips=true]:min-w-(--anchor-width) *:data-[slot=input-group]:m-1 *:data-[slot=input-group]:mb-0 *:data-[slot=input-group]:h-8 *:data-[slot=input-group]:shadow-none", className )}
113
+ className={cn("bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 *:data-[slot=input-group]:bg-input/30 *:data-[slot=input-group]:border-input/30 data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2 group/combobox-content relative max-h-(--available-height) w-(--anchor-width) max-w-(--available-width) min-w-[calc(var(--anchor-width)+--spacing(7))] origin-(--transform-origin) overflow-hidden rounded-md shadow-md ring-1 motion-reduce:animate-none data-open:duration-(--transition-duration-normal) data-open:ease-(--ease-out) data-closed:duration-(--transition-duration-fast) data-closed:ease-(--ease-in) data-[chips=true]:min-w-(--anchor-width) *:data-[slot=input-group]:m-1 *:data-[slot=input-group]:mb-0 *:data-[slot=input-group]:h-8 *:data-[slot=input-group]:shadow-none", className )}
114
114
  {...props}
115
115
  />
116
116
  </ComboboxPrimitive.Positioner>
@@ -212,7 +212,6 @@ function ComboboxSeparator({
212
212
  )
213
213
  }
214
214
 
215
- // [vendure] shadow removed for flat look — restore if overwritten by shadcn upgrade
216
215
  function ComboboxChips({
217
216
  className,
218
217
  ...props
@@ -10,11 +10,11 @@ import {
10
10
  DialogDescription,
11
11
  DialogHeader,
12
12
  DialogTitle,
13
- } from "@vendure-io/ui/components/ui/dialog"
13
+ } from "@vendure-io/ui/components/atoms/dialog"
14
14
  import {
15
15
  InputGroup,
16
16
  InputGroupAddon,
17
- } from "@vendure-io/ui/components/ui/input-group"
17
+ } from "@vendure-io/ui/components/atoms/input-group"
18
18
  import { SearchIcon, CheckIcon } from "lucide-react"
19
19
 
20
20
  function Command({
@@ -52,7 +52,7 @@ function ContextMenuContent({
52
52
  >
53
53
  <ContextMenuPrimitive.Popup
54
54
  data-slot="context-menu-content"
55
- className={cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 bg-popover text-popover-foreground data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2 z-50 max-h-(--available-height) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-md p-1 shadow-md ring-1 duration-100 outline-none", className )}
55
+ className={cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 bg-popover text-popover-foreground data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2 z-50 max-h-(--available-height) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-md p-1 shadow-md ring-1 outline-none motion-reduce:animate-none data-open:duration-(--transition-duration-normal) data-open:ease-(--ease-out) data-closed:duration-(--transition-duration-fast) data-closed:ease-(--ease-in)", className )}
56
56
  {...props}
57
57
  />
58
58
  </ContextMenuPrimitive.Positioner>
@@ -4,7 +4,7 @@ import * as React from "react"
4
4
  import { Dialog as DialogPrimitive } from "@base-ui/react/dialog"
5
5
 
6
6
  import { cn } from "@vendure-io/ui/lib/utils"
7
- import { Button } from "@vendure-io/ui/components/ui/button"
7
+ import { Button } from "@vendure-io/ui/components/atoms/button"
8
8
  import { XIcon } from "lucide-react"
9
9
 
10
10
  function Dialog({ ...props }: DialogPrimitive.Root.Props) {
@@ -31,7 +31,7 @@ function DialogOverlay({
31
31
  <DialogPrimitive.Backdrop
32
32
  data-slot="dialog-overlay"
33
33
  className={cn(
34
- "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs",
34
+ "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 fixed inset-0 isolate z-50 bg-black/10 motion-reduce:animate-none data-open:duration-(--transition-duration-normal) data-open:ease-(--ease-out) data-closed:duration-(--transition-duration-fast) data-closed:ease-(--ease-in) supports-backdrop-filter:backdrop-blur-xs",
35
35
  className
36
36
  )}
37
37
  {...props}
@@ -53,7 +53,7 @@ function DialogContent({
53
53
  <DialogPrimitive.Popup
54
54
  data-slot="dialog-content"
55
55
  className={cn(
56
- "bg-background data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 ring-foreground/10 fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-6 rounded-xl p-6 text-sm ring-1 duration-100 outline-none sm:max-w-md",
56
+ "bg-overlay data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 ring-foreground/10 fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-6 rounded-xl p-6 text-sm ring-1 motion-reduce:animate-none data-open:duration-(--transition-duration-normal) data-open:ease-(--ease-out) data-closed:duration-(--transition-duration-fast) data-closed:ease-(--ease-in) outline-none sm:max-w-md",
57
57
  className
58
58
  )}
59
59
  {...props}
@@ -121,7 +121,7 @@ function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) {
121
121
  return (
122
122
  <DialogPrimitive.Title
123
123
  data-slot="dialog-title"
124
- className={cn("leading-none font-medium", className)}
124
+ className={cn("text-style-section-title", className)}
125
125
  {...props}
126
126
  />
127
127
  )
@@ -37,7 +37,7 @@ function DrawerOverlay({
37
37
  <DrawerPrimitive.Overlay
38
38
  data-slot="drawer-overlay"
39
39
  className={cn(
40
- "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 fixed inset-0 z-50 bg-black/10 supports-backdrop-filter:backdrop-blur-xs",
40
+ "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 fixed inset-0 z-50 bg-black/10 motion-reduce:animate-none data-open:duration-(--transition-duration-normal) data-open:ease-(--ease-out) data-closed:duration-(--transition-duration-fast) data-closed:ease-(--ease-in) supports-backdrop-filter:backdrop-blur-xs",
41
41
  className
42
42
  )}
43
43
  {...props}
@@ -56,7 +56,7 @@ function DrawerContent({
56
56
  <DrawerPrimitive.Content
57
57
  data-slot="drawer-content"
58
58
  className={cn(
59
- "bg-background group/drawer-content fixed z-50 flex h-auto flex-col text-sm data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=bottom]:rounded-t-xl data-[vaul-drawer-direction=bottom]:border-t data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=left]:rounded-r-xl data-[vaul-drawer-direction=left]:border-r data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=right]:rounded-l-xl data-[vaul-drawer-direction=right]:border-l data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=top]:rounded-b-xl data-[vaul-drawer-direction=top]:border-b data-[vaul-drawer-direction=left]:sm:max-w-sm data-[vaul-drawer-direction=right]:sm:max-w-sm",
59
+ "bg-overlay group/drawer-content fixed z-50 flex h-auto flex-col text-sm data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=bottom]:rounded-t-xl data-[vaul-drawer-direction=bottom]:border-t data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=left]:rounded-r-xl data-[vaul-drawer-direction=left]:border-r data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=right]:rounded-l-xl data-[vaul-drawer-direction=right]:border-l data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=top]:rounded-b-xl data-[vaul-drawer-direction=top]:border-b data-[vaul-drawer-direction=left]:sm:max-w-sm data-[vaul-drawer-direction=right]:sm:max-w-sm",
60
60
  className
61
61
  )}
62
62
  {...props}
@@ -98,7 +98,7 @@ function DrawerTitle({
98
98
  return (
99
99
  <DrawerPrimitive.Title
100
100
  data-slot="drawer-title"
101
- className={cn("text-foreground font-medium", className)}
101
+ className={cn("text-foreground text-style-section-title", className)}
102
102
  {...props}
103
103
  />
104
104
  )
@@ -39,9 +39,10 @@ function DropdownMenuContent({
39
39
  side={side}
40
40
  sideOffset={sideOffset}
41
41
  >
42
+ {/* No w-(--anchor-width) here: pinning the popup to the trigger width makes wide items wrap — the popup sizes to its content, min-w-32 keeps the floor */}
42
43
  <MenuPrimitive.Popup
43
44
  data-slot="dropdown-menu-content"
44
- className={cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 bg-popover text-popover-foreground data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2 z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-md p-1 shadow-md ring-1 duration-100 outline-none data-closed:overflow-hidden", className )}
45
+ className={cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 bg-popover text-popover-foreground data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2 z-50 max-h-(--available-height) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-md p-1 shadow-md ring-1 outline-none motion-reduce:animate-none data-open:duration-(--transition-duration-normal) data-open:ease-(--ease-out) data-closed:duration-(--transition-duration-fast) data-closed:ease-(--ease-in) data-closed:overflow-hidden", className )}
45
46
  {...props}
46
47
  />
47
48
  </MenuPrimitive.Positioner>
@@ -136,7 +137,7 @@ function DropdownMenuSubContent({
136
137
  <DropdownMenuContent
137
138
  data-slot="dropdown-menu-sub-content"
138
139
  className={cn(
139
- "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 bg-popover text-popover-foreground w-auto min-w-[96px] rounded-md p-1 shadow-lg ring-1 duration-100",
140
+ "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 bg-popover text-popover-foreground w-auto min-w-[96px] rounded-md p-1 shadow-lg ring-1 motion-reduce:animate-none data-open:duration-(--transition-duration-normal) data-open:ease-(--ease-out) data-closed:duration-(--transition-duration-fast) data-closed:ease-(--ease-in)",
140
141
  className
141
142
  )}
142
143
  align={align}
@@ -59,7 +59,7 @@ function EmptyTitle({ className, ...props }: React.ComponentProps<"div">) {
59
59
  return (
60
60
  <div
61
61
  data-slot="empty-title"
62
- className={cn("text-lg font-medium tracking-tight", className)}
62
+ className={cn("text-style-section-title", className)}
63
63
  {...props}
64
64
  />
65
65
  )
@@ -4,8 +4,8 @@ import { useMemo } from "react"
4
4
  import { cva, type VariantProps } from "class-variance-authority"
5
5
 
6
6
  import { cn } from "@vendure-io/ui/lib/utils"
7
- import { Label } from "@vendure-io/ui/components/ui/label"
8
- import { Separator } from "@vendure-io/ui/components/ui/separator"
7
+ import { Label } from "@vendure-io/ui/components/atoms/label"
8
+ import { Separator } from "@vendure-io/ui/components/atoms/separator"
9
9
 
10
10
  function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) {
11
11
  return (
@@ -38,7 +38,7 @@ function HoverCardContent({
38
38
  <PreviewCardPrimitive.Popup
39
39
  data-slot="hover-card-content"
40
40
  className={cn(
41
- "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 bg-popover text-popover-foreground data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2 z-50 w-64 origin-(--transform-origin) rounded-lg p-4 text-sm shadow-md ring-1 outline-hidden duration-100",
41
+ "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 bg-popover text-popover-foreground data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2 z-50 w-64 origin-(--transform-origin) rounded-lg p-4 text-sm shadow-md ring-1 outline-hidden motion-reduce:animate-none data-open:duration-(--transition-duration-normal) data-open:ease-(--ease-out) data-closed:duration-(--transition-duration-fast) data-closed:ease-(--ease-in)",
42
42
  className
43
43
  )}
44
44
  {...props}
@@ -4,11 +4,10 @@ import * as React from "react"
4
4
  import { cva, type VariantProps } from "class-variance-authority"
5
5
 
6
6
  import { cn } from "@vendure-io/ui/lib/utils"
7
- import { Button } from "@vendure-io/ui/components/ui/button"
8
- import { Input } from "@vendure-io/ui/components/ui/input"
9
- import { Textarea } from "@vendure-io/ui/components/ui/textarea"
7
+ import { Button } from "@vendure-io/ui/components/atoms/button"
8
+ import { Input } from "@vendure-io/ui/components/atoms/input"
9
+ import { Textarea } from "@vendure-io/ui/components/atoms/textarea"
10
10
 
11
- // [vendure] shadow removed for flat look — restore if overwritten by shadcn upgrade
12
11
  function InputGroup({ className, ...props }: React.ComponentProps<"div">) {
13
12
  return (
14
13
  <div
@@ -40,7 +40,6 @@ function InputOTPGroup({ className, ...props }: React.ComponentProps<"div">) {
40
40
  )
41
41
  }
42
42
 
43
- // [vendure] shadow removed for flat look — restore if overwritten by shadcn upgrade
44
43
  function InputOTPSlot({
45
44
  index,
46
45
  className,
@@ -3,7 +3,6 @@ import { Input as InputPrimitive } from "@base-ui/react/input"
3
3
 
4
4
  import { cn } from "@vendure-io/ui/lib/utils"
5
5
 
6
- // [vendure] shadow removed for flat look — restore if overwritten by shadcn upgrade
7
6
  function Input({ className, type, ...props }: React.ComponentProps<"input">) {
8
7
  return (
9
8
  <InputPrimitive
@@ -4,7 +4,7 @@ import { useRender } from "@base-ui/react/use-render"
4
4
  import { cva, type VariantProps } from "class-variance-authority"
5
5
 
6
6
  import { cn } from "@vendure-io/ui/lib/utils"
7
- import { Separator } from "@vendure-io/ui/components/ui/separator"
7
+ import { Separator } from "@vendure-io/ui/components/atoms/separator"
8
8
 
9
9
  function ItemGroup({ className, ...props }: React.ComponentProps<"div">) {
10
10
  return (
@@ -130,7 +130,7 @@ function ItemTitle({ className, ...props }: React.ComponentProps<"div">) {
130
130
  <div
131
131
  data-slot="item-title"
132
132
  className={cn(
133
- "line-clamp-1 flex w-fit items-center gap-2 text-sm leading-snug font-medium underline-offset-4",
133
+ "text-style-body line-clamp-1 flex w-fit items-center gap-2 font-medium underline-offset-4",
134
134
  className
135
135
  )}
136
136
  {...props}
@@ -19,10 +19,9 @@ import {
19
19
  DropdownMenuSubContent,
20
20
  DropdownMenuSubTrigger,
21
21
  DropdownMenuTrigger,
22
- } from "@vendure-io/ui/components/ui/dropdown-menu"
22
+ } from "@vendure-io/ui/components/atoms/dropdown-menu"
23
23
  import { CheckIcon } from "lucide-react"
24
24
 
25
- // [vendure] shadow removed for flat look — restore if overwritten by shadcn upgrade
26
25
  function Menubar({ className, ...props }: MenubarPrimitive.Props) {
27
26
  return (
28
27
  <MenubarPrimitive
@@ -81,7 +80,7 @@ function MenubarContent({
81
80
  align={align}
82
81
  alignOffset={alignOffset}
83
82
  sideOffset={sideOffset}
84
- className={cn("bg-popover text-popover-foreground data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2 min-w-36 rounded-md p-1 shadow-md ring-1 duration-100", className )}
83
+ className={cn("bg-popover text-popover-foreground data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2 min-w-36 rounded-md p-1 shadow-md ring-1 motion-reduce:animate-none data-open:duration-(--transition-duration-normal) data-open:ease-(--ease-out) data-closed:duration-(--transition-duration-fast) data-closed:ease-(--ease-in)", className )}
85
84
  {...props}
86
85
  />
87
86
  )
@@ -256,7 +255,7 @@ function MenubarSubContent({
256
255
  <DropdownMenuSubContent
257
256
  data-slot="menubar-sub-content"
258
257
  className={cn(
259
- "bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 min-w-32 rounded-md p-1 shadow-lg ring-1 duration-100",
258
+ "bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 min-w-32 rounded-md p-1 shadow-lg ring-1 motion-reduce:animate-none data-open:duration-(--transition-duration-normal) data-open:ease-(--ease-out) data-closed:duration-(--transition-duration-fast) data-closed:ease-(--ease-in)",
260
259
  className
261
260
  )}
262
261
  {...props}
@@ -7,7 +7,6 @@ type NativeSelectProps = Omit<React.ComponentProps<"select">, "size"> & {
7
7
  size?: "sm" | "default"
8
8
  }
9
9
 
10
- // [vendure] shadow removed for flat look — restore if overwritten by shadcn upgrade
11
10
  function NativeSelect({
12
11
  className,
13
12
  size = "default",
@@ -84,7 +84,7 @@ function NavigationMenuContent({
84
84
  <NavigationMenuPrimitive.Content
85
85
  data-slot="navigation-menu-content"
86
86
  className={cn(
87
- "data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:data-open:animate-in group-data-[viewport=false]/navigation-menu:data-closed:animate-out group-data-[viewport=false]/navigation-menu:data-closed:zoom-out-95 group-data-[viewport=false]/navigation-menu:data-open:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-open:fade-in-0 group-data-[viewport=false]/navigation-menu:data-closed:fade-out-0 group-data-[viewport=false]/navigation-menu:ring-foreground/10 data-ending-style:data-activation-direction=left:translate-x-[50%] data-ending-style:data-activation-direction=right:translate-x-[-50%] data-starting-style:data-activation-direction=left:translate-x-[-50%] data-starting-style:data-activation-direction=right:translate-x-[50%] h-full w-auto p-2 pr-2.5 transition-[opacity,transform,translate] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] group-data-[viewport=false]/navigation-menu:rounded-md group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:ring-1 group-data-[viewport=false]/navigation-menu:duration-300 data-ending-style:opacity-0 data-starting-style:opacity-0 **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none",
87
+ "data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:data-open:animate-in group-data-[viewport=false]/navigation-menu:data-closed:animate-out group-data-[viewport=false]/navigation-menu:data-closed:zoom-out-95 group-data-[viewport=false]/navigation-menu:data-open:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-open:fade-in-0 group-data-[viewport=false]/navigation-menu:data-closed:fade-out-0 group-data-[viewport=false]/navigation-menu:ring-foreground/10 data-ending-style:data-activation-direction=left:translate-x-[50%] data-ending-style:data-activation-direction=right:translate-x-[-50%] data-starting-style:data-activation-direction=left:translate-x-[-50%] data-starting-style:data-activation-direction=right:translate-x-[50%] h-full w-auto p-2 pr-2.5 transition-[opacity,transform,translate] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] motion-reduce:animate-none motion-reduce:transition-none group-data-[viewport=false]/navigation-menu:rounded-md group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:ring-1 group-data-[viewport=false]/navigation-menu:data-open:duration-(--transition-duration-normal) group-data-[viewport=false]/navigation-menu:data-open:ease-(--ease-out) group-data-[viewport=false]/navigation-menu:data-closed:duration-(--transition-duration-fast) group-data-[viewport=false]/navigation-menu:data-closed:ease-(--ease-in) data-ending-style:opacity-0 data-starting-style:opacity-0 **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none",
88
88
  className
89
89
  )}
90
90
  {...props}
@@ -108,12 +108,12 @@ function NavigationMenuPositioner({
108
108
  align={align}
109
109
  alignOffset={alignOffset}
110
110
  className={cn(
111
- "isolate z-50 h-(--positioner-height) w-(--positioner-width) max-w-(--available-width) transition-[top,left,right,bottom] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] data-instant:transition-none data-[side=bottom]:before:top-[-10px] data-[side=bottom]:before:right-0 data-[side=bottom]:before:left-0",
111
+ "isolate z-50 h-(--positioner-height) w-(--positioner-width) max-w-(--available-width) transition-[top,left,right,bottom] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] data-instant:transition-none motion-reduce:transition-none data-[side=bottom]:before:top-[-10px] data-[side=bottom]:before:right-0 data-[side=bottom]:before:left-0",
112
112
  className
113
113
  )}
114
114
  {...props}
115
115
  >
116
- <NavigationMenuPrimitive.Popup className="bg-popover text-popover-foreground ring-foreground/10 data-[ending-style]:easing-[ease] xs:w-(--popup-width) relative h-(--popup-height) w-(--popup-width) origin-(--transform-origin) rounded-lg shadow ring-1 transition-[opacity,transform,width,height,scale,translate] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] outline-none data-ending-style:scale-90 data-ending-style:opacity-0 data-ending-style:duration-150 data-starting-style:scale-90 data-starting-style:opacity-0">
116
+ <NavigationMenuPrimitive.Popup className="bg-popover text-popover-foreground ring-foreground/10 data-[ending-style]:easing-[ease] xs:w-(--popup-width) relative h-(--popup-height) w-(--popup-width) origin-(--transform-origin) rounded-lg shadow ring-1 transition-[opacity,transform,width,height,scale,translate] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] outline-none motion-reduce:transition-none data-ending-style:scale-90 data-ending-style:opacity-0 data-ending-style:duration-(--transition-duration-fast) data-ending-style:ease-(--ease-in) data-starting-style:scale-90 data-starting-style:opacity-0">
117
117
  <NavigationMenuPrimitive.Viewport className="relative size-full overflow-hidden" />
118
118
  </NavigationMenuPrimitive.Popup>
119
119
  </NavigationMenuPrimitive.Positioner>
@@ -141,11 +141,14 @@ function NavigationMenuIndicator({
141
141
  className,
142
142
  ...props
143
143
  }: React.ComponentPropsWithRef<typeof NavigationMenuPrimitive.Icon>) {
144
+ // Base UI's Icon emits data-popup-open while its item's popup is open (never Radix-style
145
+ // data-[state=...]) and stays mounted when closed with no closed/ending attribute, so the
146
+ // closed state is hidden via opacity instead of an exit animation
144
147
  return (
145
148
  <NavigationMenuPrimitive.Icon
146
149
  data-slot="navigation-menu-indicator"
147
150
  className={cn(
148
- "data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in top-full z-1 flex h-1.5 items-end justify-center overflow-hidden",
151
+ "data-popup-open:animate-in data-popup-open:fade-in not-data-popup-open:opacity-0 motion-reduce:animate-none top-full z-1 flex h-1.5 items-end justify-center overflow-hidden",
149
152
  className
150
153
  )}
151
154
  {...props}
@@ -1,7 +1,7 @@
1
1
  import * as React from "react"
2
2
 
3
3
  import { cn } from "@vendure-io/ui/lib/utils"
4
- import { Button } from "@vendure-io/ui/components/ui/button"
4
+ import { Button } from "@vendure-io/ui/components/atoms/button"
5
5
  import { ChevronLeftIcon, ChevronRightIcon, MoreHorizontalIcon } from "lucide-react"
6
6
 
7
7
  function Pagination({ className, ...props }: React.ComponentProps<"nav">) {