@devalok/shilp-sutra 0.37.1 → 0.39.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 (260) hide show
  1. package/MIGRATION.md +185 -0
  2. package/dist/_chunks/badge-group.js +4 -4
  3. package/dist/_chunks/badge-group.js.map +1 -1
  4. package/dist/_chunks/chat.js +14 -14
  5. package/dist/_chunks/chat.js.map +1 -1
  6. package/dist/_chunks/date-picker.js +9 -9
  7. package/dist/_chunks/date-picker.js.map +1 -1
  8. package/dist/_chunks/document-preview.js +2 -2
  9. package/dist/_chunks/document-preview.js.map +1 -1
  10. package/dist/_chunks/file-preview.js +11 -11
  11. package/dist/_chunks/file-preview.js.map +1 -1
  12. package/dist/_chunks/image-preview.js +2 -2
  13. package/dist/_chunks/image-preview.js.map +1 -1
  14. package/dist/_chunks/mention-suggestion.js +5 -5
  15. package/dist/_chunks/mention-suggestion.js.map +1 -1
  16. package/dist/_chunks/popover.js +3 -3
  17. package/dist/_chunks/popover.js.map +1 -1
  18. package/dist/_chunks/rich-chat-input.js +33 -33
  19. package/dist/_chunks/rich-chat-input.js.map +1 -1
  20. package/dist/_chunks/shared.js +5 -5
  21. package/dist/_chunks/shared.js.map +1 -1
  22. package/dist/_chunks/text.js +2 -2
  23. package/dist/_chunks/text.js.map +1 -1
  24. package/dist/_chunks/tiptap.js +977 -968
  25. package/dist/_chunks/tiptap.js.map +1 -1
  26. package/dist/_chunks/tree-view.js +1 -1
  27. package/dist/_chunks/tree-view.js.map +1 -1
  28. package/dist/_chunks/use-calendar.js +5 -5
  29. package/dist/_chunks/use-calendar.js.map +1 -1
  30. package/dist/ai/command-bar.js +10 -10
  31. package/dist/ai/command-bar.js.map +1 -1
  32. package/dist/ai/conversation.js +4 -4
  33. package/dist/ai/conversation.js.map +1 -1
  34. package/dist/composed/activity-feed.js +5 -5
  35. package/dist/composed/activity-feed.js.map +1 -1
  36. package/dist/composed/avatar-group.js +4 -4
  37. package/dist/composed/avatar-group.js.map +1 -1
  38. package/dist/composed/bulk-action-bar.js +1 -1
  39. package/dist/composed/bulk-action-bar.js.map +1 -1
  40. package/dist/composed/command-palette.js +5 -5
  41. package/dist/composed/command-palette.js.map +1 -1
  42. package/dist/composed/content-card.js +1 -1
  43. package/dist/composed/content-card.js.map +1 -1
  44. package/dist/composed/emoji-picker.js +4 -4
  45. package/dist/composed/emoji-picker.js.map +1 -1
  46. package/dist/composed/empty-state.js +1 -1
  47. package/dist/composed/empty-state.js.map +1 -1
  48. package/dist/composed/error-boundary.js +3 -3
  49. package/dist/composed/error-boundary.js.map +1 -1
  50. package/dist/composed/filter-bar.js +1 -1
  51. package/dist/composed/filter-bar.js.map +1 -1
  52. package/dist/composed/index.d.ts +0 -2
  53. package/dist/composed/index.d.ts.map +1 -1
  54. package/dist/composed/index.js +5 -6
  55. package/dist/composed/inline-edit.js +1 -1
  56. package/dist/composed/inline-edit.js.map +1 -1
  57. package/dist/composed/loading-skeleton.js +9 -9
  58. package/dist/composed/loading-skeleton.js.map +1 -1
  59. package/dist/composed/markdown-viewer.js +3 -3
  60. package/dist/composed/markdown-viewer.js.map +1 -1
  61. package/dist/composed/multi-select-popover.js +1 -1
  62. package/dist/composed/multi-select-popover.js.map +1 -1
  63. package/dist/composed/page-header.js +1 -1
  64. package/dist/composed/page-header.js.map +1 -1
  65. package/dist/composed/page-skeletons.js +15 -15
  66. package/dist/composed/page-skeletons.js.map +1 -1
  67. package/dist/composed/priority-indicator.js +3 -3
  68. package/dist/composed/priority-indicator.js.map +1 -1
  69. package/dist/composed/rich-text-editor.js +11 -11
  70. package/dist/composed/rich-text-editor.js.map +1 -1
  71. package/dist/composed/schedule-view.js +3 -3
  72. package/dist/composed/schedule-view.js.map +1 -1
  73. package/dist/composed/status-badge.js +3 -3
  74. package/dist/composed/status-badge.js.map +1 -1
  75. package/dist/hooks/index.d.ts +2 -2
  76. package/dist/hooks/index.d.ts.map +1 -1
  77. package/dist/hooks/index.js +0 -1
  78. package/dist/shell/bottom-navbar.js +6 -6
  79. package/dist/shell/bottom-navbar.js.map +1 -1
  80. package/dist/shell/notification-center.js +8 -8
  81. package/dist/shell/notification-center.js.map +1 -1
  82. package/dist/shell/notification-preferences.js +1 -1
  83. package/dist/shell/notification-preferences.js.map +1 -1
  84. package/dist/shell/sidebar.js +6 -6
  85. package/dist/shell/sidebar.js.map +1 -1
  86. package/dist/shell/top-bar.js +4 -4
  87. package/dist/shell/top-bar.js.map +1 -1
  88. package/dist/tokens/semantic.css +82 -9
  89. package/dist/ui/accordion.js +1 -1
  90. package/dist/ui/accordion.js.map +1 -1
  91. package/dist/ui/alert-dialog.js +3 -3
  92. package/dist/ui/alert-dialog.js.map +1 -1
  93. package/dist/ui/alert.d.ts +1 -2
  94. package/dist/ui/alert.d.ts.map +1 -1
  95. package/dist/ui/alert.js +3 -29
  96. package/dist/ui/alert.js.map +1 -1
  97. package/dist/ui/autocomplete.js +2 -2
  98. package/dist/ui/autocomplete.js.map +1 -1
  99. package/dist/ui/avatar.js +11 -11
  100. package/dist/ui/avatar.js.map +1 -1
  101. package/dist/ui/badge-indicator.js +1 -1
  102. package/dist/ui/badge-indicator.js.map +1 -1
  103. package/dist/ui/banner.d.ts +3 -5
  104. package/dist/ui/banner.d.ts.map +1 -1
  105. package/dist/ui/banner.js +14 -14
  106. package/dist/ui/banner.js.map +1 -1
  107. package/dist/ui/breadcrumb.js +1 -1
  108. package/dist/ui/breadcrumb.js.map +1 -1
  109. package/dist/ui/button.d.ts +2 -2
  110. package/dist/ui/button.js +14 -14
  111. package/dist/ui/button.js.map +1 -1
  112. package/dist/ui/card.js +5 -5
  113. package/dist/ui/card.js.map +1 -1
  114. package/dist/ui/charts/index.js +5 -5
  115. package/dist/ui/charts/index.js.map +1 -1
  116. package/dist/ui/checkbox.js +1 -1
  117. package/dist/ui/checkbox.js.map +1 -1
  118. package/dist/ui/code.js +2 -2
  119. package/dist/ui/code.js.map +1 -1
  120. package/dist/ui/color-input.js +10 -10
  121. package/dist/ui/color-input.js.map +1 -1
  122. package/dist/ui/color-swatch.js +3 -3
  123. package/dist/ui/color-swatch.js.map +1 -1
  124. package/dist/ui/combobox.js +5 -5
  125. package/dist/ui/combobox.js.map +1 -1
  126. package/dist/ui/context-menu.js +6 -6
  127. package/dist/ui/context-menu.js.map +1 -1
  128. package/dist/ui/data-table-body.js +1 -1
  129. package/dist/ui/data-table-body.js.map +1 -1
  130. package/dist/ui/data-table-bulk-actions.js +2 -2
  131. package/dist/ui/data-table-bulk-actions.js.map +1 -1
  132. package/dist/ui/data-table-card.js +2 -2
  133. package/dist/ui/data-table-card.js.map +1 -1
  134. package/dist/ui/data-table-header.js +2 -2
  135. package/dist/ui/data-table-header.js.map +1 -1
  136. package/dist/ui/data-table-pagination.js +3 -3
  137. package/dist/ui/data-table-pagination.js.map +1 -1
  138. package/dist/ui/data-table-toolbar.js +1 -1
  139. package/dist/ui/data-table-toolbar.js.map +1 -1
  140. package/dist/ui/data-table.js +1 -1
  141. package/dist/ui/data-table.js.map +1 -1
  142. package/dist/ui/devalok-grain.d.ts +1 -1
  143. package/dist/ui/devalok-grain.js.map +1 -1
  144. package/dist/ui/dialog.js +2 -2
  145. package/dist/ui/dialog.js.map +1 -1
  146. package/dist/ui/dropdown-menu.js +6 -6
  147. package/dist/ui/dropdown-menu.js.map +1 -1
  148. package/dist/ui/file-upload.js +4 -4
  149. package/dist/ui/file-upload.js.map +1 -1
  150. package/dist/ui/hover-card.js +1 -1
  151. package/dist/ui/hover-card.js.map +1 -1
  152. package/dist/ui/icon-button.js +1 -1
  153. package/dist/ui/icon-button.js.map +1 -1
  154. package/dist/ui/index.d.ts +1 -1
  155. package/dist/ui/index.d.ts.map +1 -1
  156. package/dist/ui/index.js +2 -2
  157. package/dist/ui/index.js.map +1 -1
  158. package/dist/ui/input-otp.js +1 -1
  159. package/dist/ui/input-otp.js.map +1 -1
  160. package/dist/ui/input.d.ts +1 -9
  161. package/dist/ui/input.d.ts.map +1 -1
  162. package/dist/ui/input.js +28 -29
  163. package/dist/ui/input.js.map +1 -1
  164. package/dist/ui/link.js +1 -1
  165. package/dist/ui/link.js.map +1 -1
  166. package/dist/ui/menubar.js +8 -8
  167. package/dist/ui/menubar.js.map +1 -1
  168. package/dist/ui/navigation-menu.js +3 -3
  169. package/dist/ui/navigation-menu.js.map +1 -1
  170. package/dist/ui/number-input.js +3 -3
  171. package/dist/ui/number-input.js.map +1 -1
  172. package/dist/ui/pagination.js +1 -1
  173. package/dist/ui/pagination.js.map +1 -1
  174. package/dist/ui/progress.js +1 -1
  175. package/dist/ui/progress.js.map +1 -1
  176. package/dist/ui/radio.js +1 -1
  177. package/dist/ui/radio.js.map +1 -1
  178. package/dist/ui/segmented-control.d.ts +1 -1
  179. package/dist/ui/segmented-control.d.ts.map +1 -1
  180. package/dist/ui/segmented-control.js +5 -7
  181. package/dist/ui/segmented-control.js.map +1 -1
  182. package/dist/ui/select.js +3 -3
  183. package/dist/ui/select.js.map +1 -1
  184. package/dist/ui/sheet.js +2 -2
  185. package/dist/ui/sheet.js.map +1 -1
  186. package/dist/ui/sidebar.js +11 -11
  187. package/dist/ui/sidebar.js.map +1 -1
  188. package/dist/ui/skeleton.js +9 -9
  189. package/dist/ui/skeleton.js.map +1 -1
  190. package/dist/ui/slider.js +2 -2
  191. package/dist/ui/slider.js.map +1 -1
  192. package/dist/ui/split-button.js +7 -7
  193. package/dist/ui/split-button.js.map +1 -1
  194. package/dist/ui/stat-card.js +7 -7
  195. package/dist/ui/stat-card.js.map +1 -1
  196. package/dist/ui/status-dot.js +2 -2
  197. package/dist/ui/status-dot.js.map +1 -1
  198. package/dist/ui/stepper.js +2 -2
  199. package/dist/ui/stepper.js.map +1 -1
  200. package/dist/ui/switch.js +2 -2
  201. package/dist/ui/switch.js.map +1 -1
  202. package/dist/ui/tabs.js +3 -3
  203. package/dist/ui/tabs.js.map +1 -1
  204. package/dist/ui/textarea.js +1 -1
  205. package/dist/ui/textarea.js.map +1 -1
  206. package/dist/ui/toast.js +8 -8
  207. package/dist/ui/toast.js.map +1 -1
  208. package/dist/ui/toggle.js +1 -1
  209. package/dist/ui/toggle.js.map +1 -1
  210. package/dist/ui/tooltip.js +1 -1
  211. package/dist/ui/tooltip.js.map +1 -1
  212. package/docs/components/_header.md +91 -2
  213. package/docs/components/ui/alert.md +4 -1
  214. package/docs/components/ui/banner.md +3 -1
  215. package/docs/components/ui/input.md +4 -2
  216. package/docs/components/ui/segmented-control.md +13 -6
  217. package/docs/recipes/customize-brand.md +297 -0
  218. package/docs/recipes/index.md +51 -0
  219. package/docs/recipes/install-astro.md +178 -0
  220. package/docs/recipes/install-next-app-router.md +230 -0
  221. package/docs/recipes/install-next-pages.md +123 -0
  222. package/docs/recipes/install-remix.md +171 -0
  223. package/docs/recipes/install-tanstack-start.md +143 -0
  224. package/docs/recipes/install-vite.md +170 -0
  225. package/docs/recipes/server-components.md +209 -0
  226. package/docs/recipes/troubleshoot.md +217 -0
  227. package/llms-full.txt +116 -54
  228. package/llms.txt +42 -17
  229. package/package.json +46 -35
  230. package/skill/README.md +99 -0
  231. package/skill/SKILL.md +144 -0
  232. package/skill/install.sh +59 -0
  233. package/skill/references/components-full.md +6997 -0
  234. package/skill/references/components.md +673 -0
  235. package/skill/references/customize-brand.md +299 -0
  236. package/skill/references/server-components.md +211 -0
  237. package/skill/references/setup-astro.md +180 -0
  238. package/skill/references/setup-next-app-router.md +232 -0
  239. package/skill/references/setup-next-pages.md +125 -0
  240. package/skill/references/setup-remix.md +173 -0
  241. package/skill/references/setup-tanstack-start.md +145 -0
  242. package/skill/references/setup-vite.md +172 -0
  243. package/skill/references/troubleshoot.md +219 -0
  244. package/dist/composed/responsive-overlay.d.ts +0 -23
  245. package/dist/composed/responsive-overlay.d.ts.map +0 -1
  246. package/dist/composed/responsive-overlay.js +0 -40
  247. package/dist/composed/responsive-overlay.js.map +0 -1
  248. package/dist/hooks/use-toast.d.ts +0 -17
  249. package/dist/hooks/use-toast.d.ts.map +0 -1
  250. package/dist/hooks/use-toast.js +0 -3
  251. package/dist/tailwind/index.cjs +0 -41
  252. package/dist/tailwind/index.d.ts +0 -2
  253. package/dist/tailwind/index.d.ts.map +0 -1
  254. package/dist/tailwind/index.js +0 -2
  255. package/dist/tailwind/preset.d.ts +0 -25
  256. package/dist/tailwind/preset.d.ts.map +0 -1
  257. package/dist/tailwind/preset.js +0 -17
  258. package/dist/tailwind/preset.js.map +0 -1
  259. package/docs/components/composed/responsive-overlay.md +0 -41
  260. /package/{LICENSE → skill/LICENSE} +0 -0
@@ -7,7 +7,7 @@ import * as i from "react";
7
7
  import { jsx as a, jsxs as o } from "react/jsx-runtime";
8
8
  import { IconMinus as s, IconPlus as c } from "@tabler/icons-react";
9
9
  //#region src/ui/number-input.tsx
10
- var l = e("flex items-center justify-between rounded-ds-md border border-surface-border-strong", {
10
+ var l = e("flex items-center justify-between rounded-control border border-surface-border-strong", {
11
11
  variants: { size: {
12
12
  xs: "h-ds-xs-plus",
13
13
  sm: "h-ds-sm",
@@ -62,7 +62,7 @@ var l = e("flex items-center justify-between rounded-ds-md border border-surface
62
62
  disabled: _ || e <= m,
63
63
  "aria-label": "Decrease value",
64
64
  title: "Decrease",
65
- className: t("flex items-center justify-center border-0 rounded-ds-sm text-surface-fg-subtle hover:bg-surface-raised-hover hover:text-surface-fg-muted active:scale-90 transition-[color,background-color,transform] duration-fast-01 ease-productive-standard disabled:opacity-action-disabled disabled:pointer-events-none", j),
65
+ className: t("flex items-center justify-center border-0 rounded-control-inner text-surface-fg-subtle hover:bg-surface-raised-hover hover:text-surface-fg-muted active:scale-90 transition-[color,background-color,transform] duration-fast-01 ease-productive-standard disabled:opacity-action-disabled disabled:pointer-events-none", j),
66
66
  children: /* @__PURE__ */ a(n, {
67
67
  icon: s,
68
68
  size: M
@@ -89,7 +89,7 @@ var l = e("flex items-center justify-between rounded-ds-md border border-surface
89
89
  disabled: _ || e >= h,
90
90
  "aria-label": "Increase value",
91
91
  title: "Increase",
92
- className: t("flex items-center justify-center border-0 rounded-ds-sm text-surface-fg-subtle hover:bg-surface-raised-hover hover:text-surface-fg-muted active:scale-90 transition-[color,background-color,transform] duration-fast-01 ease-productive-standard disabled:opacity-action-disabled disabled:pointer-events-none", j),
92
+ className: t("flex items-center justify-center border-0 rounded-control-inner text-surface-fg-subtle hover:bg-surface-raised-hover hover:text-surface-fg-muted active:scale-90 transition-[color,background-color,transform] duration-fast-01 ease-productive-standard disabled:opacity-action-disabled disabled:pointer-events-none", j),
93
93
  children: /* @__PURE__ */ a(n, {
94
94
  icon: c,
95
95
  size: M
@@ -1 +1 @@
1
- {"version":3,"file":"number-input.js","names":[],"sources":["../../src/ui/number-input.tsx"],"sourcesContent":["'use client'\n\nimport { IconMinus, IconPlus } from '@tabler/icons-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport * as React from 'react'\n\nimport { useFormField } from './form'\nimport { Icon } from './icon'\nimport type { IconSize } from './icon-context'\nimport { cn } from './lib/utils'\n\nexport type NumberInputState = 'default' | 'error' | 'warning' | 'success'\n\nconst numberInputWrapperVariants = cva(\n 'flex items-center justify-between rounded-ds-md border border-surface-border-strong',\n {\n variants: {\n size: {\n xs: 'h-ds-xs-plus',\n sm: 'h-ds-sm',\n md: 'h-ds-md',\n lg: 'h-ds-lg',\n },\n },\n defaultVariants: { size: 'md' },\n },\n)\n\nexport type NumberInputSize = NonNullable<VariantProps<typeof numberInputWrapperVariants>['size']>\n\n/** Maps size to stepper button dimensions */\nconst buttonSizeMap: Record<NonNullable<NumberInputSize>, string> = {\n xs: 'h-[22px] w-[22px]',\n sm: 'h-ds-sm w-ds-sm',\n md: 'h-ds-sm w-ds-sm',\n lg: 'h-ds-md w-ds-md',\n}\n\n/** Maps size to Icon component size */\nconst iconSizeMap: Record<NonNullable<NumberInputSize>, IconSize> = {\n xs: 'xs',\n sm: 'sm',\n md: 'sm',\n lg: 'md',\n}\n\n/** Maps size to input text and width classes */\nconst inputSizeMap: Record<NonNullable<NumberInputSize>, string> = {\n xs: 'text-ds-sm w-[28px]',\n sm: 'text-ds-sm w-ds-sm-plus',\n md: 'text-ds-md w-ds-sm-plus',\n lg: 'text-ds-md w-ds-md',\n}\n\n/** Maps state to border color classes */\nconst stateColorMap: Record<NonNullable<NumberInputState>, string> = {\n default: '',\n error: 'border-error-7',\n warning: 'border-warning-7',\n success: 'border-success-7',\n}\n\n/**\n * Props for NumberInput — a stepper control with \"−\" and \"+\" buttons flanking a numeric input,\n * clamped between `min` and `max`. The decrement/increment buttons are disabled when bounds are reached.\n *\n * **Controlled only:** Pass `value` + `onValueChange` for controlled usage. Uncontrolled usage is\n * possible but the buttons won't update the displayed value without `onValueChange`.\n *\n * **Step:** The `step` prop controls how much each button press increments/decrements (default 1).\n * Direct text input is also clamped to `[min, max]` on change.\n *\n * **Sizes:** `xs` (28px) | `sm` (32px) | `md` (40px, default) | `lg` (48px)\n *\n * **Validation states:** `state=\"error\"` colors the border red.\n * Use with `<FormField>` to show helper text below the input.\n *\n * @example\n * // Quantity selector with 1–99 range:\n * <NumberInput value={qty} onValueChange={setQty} min={1} max={99} />\n *\n * @example\n * // Rating input (1–10, step 1):\n * <NumberInput value={rating} onValueChange={setRating} min={1} max={10} />\n *\n * @example\n * // Fine-grained opacity control (0–100, step 5):\n * <NumberInput value={opacity} onValueChange={setOpacity} min={0} max={100} step={5} />\n *\n * @example\n * // Disabled number display (read-only-like):\n * <NumberInput value={autoCalcValue} onValueChange={() => {}} disabled />\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface NumberInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange' | 'type' | 'size'> {\n value?: number\n onValueChange?: (value: number) => void\n min?: number\n max?: number\n step?: number\n /** Size of the number input. Controls height, button sizes, text size. */\n size?: NumberInputSize\n /** Validation state controlling border color. */\n state?: NumberInputState\n}\n\nconst NumberInput = React.forwardRef<HTMLInputElement, NumberInputProps>(\n (\n {\n value = 0,\n onValueChange,\n min = Number.MIN_SAFE_INTEGER,\n max = Number.MAX_SAFE_INTEGER,\n step = 1,\n disabled = false,\n className,\n size: sizeProp = 'md',\n state: stateProp,\n 'aria-label': ariaLabelProp,\n ...rest\n },\n ref,\n ) => {\n const size = sizeProp ?? 'md'\n const fieldCtx = useFormField()\n // If no explicit aria-label and not inside a FormField (no id to associate with Label),\n // provide a sensible default\n const ariaLabel = ariaLabelProp ?? (rest.id || fieldCtx.helperTextId ? undefined : 'Numeric value')\n\n // Merge FormField context — explicit props always win\n const state =\n stateProp ??\n (fieldCtx.state === 'helper'\n ? 'default'\n : (fieldCtx.state as NumberInputState | undefined)) ??\n 'default'\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const raw = e.target.value.trim()\n if (raw === '' || raw === '-') {\n onValueChange?.(min >= 0 ? min : 0)\n return\n }\n const parsed = Number(raw)\n if (Number.isNaN(parsed)) return\n const clamped = Math.min(Math.max(parsed, min), max)\n onValueChange?.(clamped)\n }\n\n const handleIncrement = (e: React.MouseEvent<HTMLButtonElement>) => {\n e.preventDefault() // Prevent form submission\n const newValue = value + step\n if (newValue <= max) {\n onValueChange?.(newValue)\n }\n }\n\n const handleDecrement = (e: React.MouseEvent<HTMLButtonElement>) => {\n e.preventDefault() // Prevent form submission\n const newValue = value - step\n if (newValue >= min) {\n onValueChange?.(newValue)\n }\n }\n\n const resolvedButtonSize = buttonSizeMap[size]\n const resolvedIconSize = iconSizeMap[size]\n const resolvedInputSize = inputSizeMap[size]\n\n return (\n <div\n className={cn(\n numberInputWrapperVariants({ size }),\n stateColorMap[state],\n className,\n )}\n >\n <button\n type=\"button\"\n onClick={handleDecrement}\n disabled={disabled || value <= min}\n aria-label=\"Decrease value\"\n title=\"Decrease\"\n className={cn(\n 'flex items-center justify-center border-0 rounded-ds-sm text-surface-fg-subtle hover:bg-surface-raised-hover hover:text-surface-fg-muted active:scale-90 transition-[color,background-color,transform] duration-fast-01 ease-productive-standard disabled:opacity-action-disabled disabled:pointer-events-none',\n resolvedButtonSize,\n )}\n >\n <Icon icon={IconMinus} size={resolvedIconSize} />\n </button>\n\n <input\n ref={ref}\n type=\"number\"\n value={value}\n onChange={handleInputChange}\n min={min}\n max={max}\n step={step}\n disabled={disabled}\n aria-label={ariaLabel}\n aria-invalid={state === 'error' || undefined}\n aria-describedby={rest['aria-describedby'] ?? fieldCtx.helperTextId}\n className={cn(\n 'bg-transparent font-semibold border-0 text-center text-surface-fg-muted focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none',\n resolvedInputSize,\n )}\n {...rest}\n />\n\n <button\n type=\"button\"\n onClick={handleIncrement}\n disabled={disabled || value >= max}\n aria-label=\"Increase value\"\n title=\"Increase\"\n className={cn(\n 'flex items-center justify-center border-0 rounded-ds-sm text-surface-fg-subtle hover:bg-surface-raised-hover hover:text-surface-fg-muted active:scale-90 transition-[color,background-color,transform] duration-fast-01 ease-productive-standard disabled:opacity-action-disabled disabled:pointer-events-none',\n resolvedButtonSize,\n )}\n >\n <Icon icon={IconPlus} size={resolvedIconSize} />\n </button>\n </div>\n )\n },\n)\nNumberInput.displayName = 'NumberInput'\n\nexport { NumberInput, numberInputWrapperVariants }\n"],"mappings":";;;;;;;;;AAaA,IAAM,IAA6B,EACjC,uFACA;CACE,UAAU,EACR,MAAM;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACL,EACF;CACD,iBAAiB,EAAE,MAAM,MAAM;CAChC,CACF,EAKK,IAA8D;CAClE,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACL,EAGK,IAA8D;CAClE,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACL,EAGK,IAA6D;CACjE,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACL,EAGK,IAA+D;CACnE,SAAS;CACT,OAAO;CACP,SAAS;CACT,SAAS;CACV,EA8CK,IAAc,EAAM,YAEtB,EACE,WAAQ,GACR,kBACA,SAAM,gBACN,sBACA,UAAO,GACP,cAAW,IACX,cACA,MAAM,IAAW,MACjB,OAAO,GACP,cAAc,GACd,GAAG,KAEL,MACG;CACH,IAAM,IAAO,KAAY,MACnB,IAAW,GAAc,EAGzB,IAAY,MAAkB,EAAK,MAAM,EAAS,eAAe,KAAA,IAAY,kBAG7E,IACJ,MACC,EAAS,UAAU,WAChB,YACC,EAAS,UACd,WAEI,KAAqB,MAA2C;EACpE,IAAM,IAAM,EAAE,OAAO,MAAM,MAAM;AACjC,MAAI,MAAQ,MAAM,MAAQ,KAAK;AAC7B,OAAgB,KAAO,IAAI,IAAM,EAAE;AACnC;;EAEF,IAAM,IAAS,OAAO,EAAI;AACtB,SAAO,MAAM,EAAO,IAExB,IADgB,KAAK,IAAI,KAAK,IAAI,GAAQ,EAAI,EAAE,EAAI,CAC5B;IAGpB,KAAmB,MAA2C;AAClE,IAAE,gBAAgB;EAClB,IAAM,IAAW,IAAQ;AACzB,EAAI,KAAY,KACd,IAAgB,EAAS;IAIvB,KAAmB,MAA2C;AAClE,IAAE,gBAAgB;EAClB,IAAM,IAAW,IAAQ;AACzB,EAAI,KAAY,KACd,IAAgB,EAAS;IAIvB,IAAqB,EAAc,IACnC,IAAmB,EAAY,IAC/B,IAAoB,EAAa;AAEvC,QACE,kBAAC,OAAD;EACE,WAAW,EACT,EAA2B,EAAE,SAAM,CAAC,EACpC,EAAc,IACd,EACD;YALH;GAOE,kBAAC,UAAD;IACE,MAAK;IACL,SAAS;IACT,UAAU,KAAY,KAAS;IAC/B,cAAW;IACX,OAAM;IACN,WAAW,EACT,kTACA,EACD;cAED,kBAAC,GAAD;KAAM,MAAM;KAAW,MAAM;KAAoB,CAAA;IAC1C,CAAA;GAET,kBAAC,SAAD;IACO;IACL,MAAK;IACE;IACP,UAAU;IACL;IACA;IACC;IACI;IACV,cAAY;IACZ,gBAAc,MAAU,WAAW,KAAA;IACnC,oBAAkB,EAAK,uBAAuB,EAAS;IACvD,WAAW,EACT,8QACA,EACD;IACD,GAAI;IACJ,CAAA;GAEF,kBAAC,UAAD;IACE,MAAK;IACL,SAAS;IACT,UAAU,KAAY,KAAS;IAC/B,cAAW;IACX,OAAM;IACN,WAAW,EACT,kTACA,EACD;cAED,kBAAC,GAAD;KAAM,MAAM;KAAU,MAAM;KAAoB,CAAA;IACzC,CAAA;GACL;;EAGX;AACD,EAAY,cAAc"}
1
+ {"version":3,"file":"number-input.js","names":[],"sources":["../../src/ui/number-input.tsx"],"sourcesContent":["'use client'\n\nimport { IconMinus, IconPlus } from '@tabler/icons-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport * as React from 'react'\n\nimport { useFormField } from './form'\nimport { Icon } from './icon'\nimport type { IconSize } from './icon-context'\nimport { cn } from './lib/utils'\n\nexport type NumberInputState = 'default' | 'error' | 'warning' | 'success'\n\nconst numberInputWrapperVariants = cva(\n 'flex items-center justify-between rounded-control border border-surface-border-strong',\n {\n variants: {\n size: {\n xs: 'h-ds-xs-plus',\n sm: 'h-ds-sm',\n md: 'h-ds-md',\n lg: 'h-ds-lg',\n },\n },\n defaultVariants: { size: 'md' },\n },\n)\n\nexport type NumberInputSize = NonNullable<VariantProps<typeof numberInputWrapperVariants>['size']>\n\n/** Maps size to stepper button dimensions */\nconst buttonSizeMap: Record<NonNullable<NumberInputSize>, string> = {\n xs: 'h-[22px] w-[22px]',\n sm: 'h-ds-sm w-ds-sm',\n md: 'h-ds-sm w-ds-sm',\n lg: 'h-ds-md w-ds-md',\n}\n\n/** Maps size to Icon component size */\nconst iconSizeMap: Record<NonNullable<NumberInputSize>, IconSize> = {\n xs: 'xs',\n sm: 'sm',\n md: 'sm',\n lg: 'md',\n}\n\n/** Maps size to input text and width classes */\nconst inputSizeMap: Record<NonNullable<NumberInputSize>, string> = {\n xs: 'text-ds-sm w-[28px]',\n sm: 'text-ds-sm w-ds-sm-plus',\n md: 'text-ds-md w-ds-sm-plus',\n lg: 'text-ds-md w-ds-md',\n}\n\n/** Maps state to border color classes */\nconst stateColorMap: Record<NonNullable<NumberInputState>, string> = {\n default: '',\n error: 'border-error-7',\n warning: 'border-warning-7',\n success: 'border-success-7',\n}\n\n/**\n * Props for NumberInput — a stepper control with \"−\" and \"+\" buttons flanking a numeric input,\n * clamped between `min` and `max`. The decrement/increment buttons are disabled when bounds are reached.\n *\n * **Controlled only:** Pass `value` + `onValueChange` for controlled usage. Uncontrolled usage is\n * possible but the buttons won't update the displayed value without `onValueChange`.\n *\n * **Step:** The `step` prop controls how much each button press increments/decrements (default 1).\n * Direct text input is also clamped to `[min, max]` on change.\n *\n * **Sizes:** `xs` (28px) | `sm` (32px) | `md` (40px, default) | `lg` (48px)\n *\n * **Validation states:** `state=\"error\"` colors the border red.\n * Use with `<FormField>` to show helper text below the input.\n *\n * @example\n * // Quantity selector with 1–99 range:\n * <NumberInput value={qty} onValueChange={setQty} min={1} max={99} />\n *\n * @example\n * // Rating input (1–10, step 1):\n * <NumberInput value={rating} onValueChange={setRating} min={1} max={10} />\n *\n * @example\n * // Fine-grained opacity control (0–100, step 5):\n * <NumberInput value={opacity} onValueChange={setOpacity} min={0} max={100} step={5} />\n *\n * @example\n * // Disabled number display (read-only-like):\n * <NumberInput value={autoCalcValue} onValueChange={() => {}} disabled />\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface NumberInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange' | 'type' | 'size'> {\n value?: number\n onValueChange?: (value: number) => void\n min?: number\n max?: number\n step?: number\n /** Size of the number input. Controls height, button sizes, text size. */\n size?: NumberInputSize\n /** Validation state controlling border color. */\n state?: NumberInputState\n}\n\nconst NumberInput = React.forwardRef<HTMLInputElement, NumberInputProps>(\n (\n {\n value = 0,\n onValueChange,\n min = Number.MIN_SAFE_INTEGER,\n max = Number.MAX_SAFE_INTEGER,\n step = 1,\n disabled = false,\n className,\n size: sizeProp = 'md',\n state: stateProp,\n 'aria-label': ariaLabelProp,\n ...rest\n },\n ref,\n ) => {\n const size = sizeProp ?? 'md'\n const fieldCtx = useFormField()\n // If no explicit aria-label and not inside a FormField (no id to associate with Label),\n // provide a sensible default\n const ariaLabel = ariaLabelProp ?? (rest.id || fieldCtx.helperTextId ? undefined : 'Numeric value')\n\n // Merge FormField context — explicit props always win\n const state =\n stateProp ??\n (fieldCtx.state === 'helper'\n ? 'default'\n : (fieldCtx.state as NumberInputState | undefined)) ??\n 'default'\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const raw = e.target.value.trim()\n if (raw === '' || raw === '-') {\n onValueChange?.(min >= 0 ? min : 0)\n return\n }\n const parsed = Number(raw)\n if (Number.isNaN(parsed)) return\n const clamped = Math.min(Math.max(parsed, min), max)\n onValueChange?.(clamped)\n }\n\n const handleIncrement = (e: React.MouseEvent<HTMLButtonElement>) => {\n e.preventDefault() // Prevent form submission\n const newValue = value + step\n if (newValue <= max) {\n onValueChange?.(newValue)\n }\n }\n\n const handleDecrement = (e: React.MouseEvent<HTMLButtonElement>) => {\n e.preventDefault() // Prevent form submission\n const newValue = value - step\n if (newValue >= min) {\n onValueChange?.(newValue)\n }\n }\n\n const resolvedButtonSize = buttonSizeMap[size]\n const resolvedIconSize = iconSizeMap[size]\n const resolvedInputSize = inputSizeMap[size]\n\n return (\n <div\n className={cn(\n numberInputWrapperVariants({ size }),\n stateColorMap[state],\n className,\n )}\n >\n <button\n type=\"button\"\n onClick={handleDecrement}\n disabled={disabled || value <= min}\n aria-label=\"Decrease value\"\n title=\"Decrease\"\n className={cn(\n 'flex items-center justify-center border-0 rounded-control-inner text-surface-fg-subtle hover:bg-surface-raised-hover hover:text-surface-fg-muted active:scale-90 transition-[color,background-color,transform] duration-fast-01 ease-productive-standard disabled:opacity-action-disabled disabled:pointer-events-none',\n resolvedButtonSize,\n )}\n >\n <Icon icon={IconMinus} size={resolvedIconSize} />\n </button>\n\n <input\n ref={ref}\n type=\"number\"\n value={value}\n onChange={handleInputChange}\n min={min}\n max={max}\n step={step}\n disabled={disabled}\n aria-label={ariaLabel}\n aria-invalid={state === 'error' || undefined}\n aria-describedby={rest['aria-describedby'] ?? fieldCtx.helperTextId}\n className={cn(\n 'bg-transparent font-semibold border-0 text-center text-surface-fg-muted focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none',\n resolvedInputSize,\n )}\n {...rest}\n />\n\n <button\n type=\"button\"\n onClick={handleIncrement}\n disabled={disabled || value >= max}\n aria-label=\"Increase value\"\n title=\"Increase\"\n className={cn(\n 'flex items-center justify-center border-0 rounded-control-inner text-surface-fg-subtle hover:bg-surface-raised-hover hover:text-surface-fg-muted active:scale-90 transition-[color,background-color,transform] duration-fast-01 ease-productive-standard disabled:opacity-action-disabled disabled:pointer-events-none',\n resolvedButtonSize,\n )}\n >\n <Icon icon={IconPlus} size={resolvedIconSize} />\n </button>\n </div>\n )\n },\n)\nNumberInput.displayName = 'NumberInput'\n\nexport { NumberInput, numberInputWrapperVariants }\n"],"mappings":";;;;;;;;;AAaA,IAAM,IAA6B,EACjC,yFACA;CACE,UAAU,EACR,MAAM;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACL,EACF;CACD,iBAAiB,EAAE,MAAM,MAAM;CAChC,CACF,EAKK,IAA8D;CAClE,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACL,EAGK,IAA8D;CAClE,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACL,EAGK,IAA6D;CACjE,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACL,EAGK,IAA+D;CACnE,SAAS;CACT,OAAO;CACP,SAAS;CACT,SAAS;CACV,EA8CK,IAAc,EAAM,YAEtB,EACE,WAAQ,GACR,kBACA,SAAM,gBACN,sBACA,UAAO,GACP,cAAW,IACX,cACA,MAAM,IAAW,MACjB,OAAO,GACP,cAAc,GACd,GAAG,KAEL,MACG;CACH,IAAM,IAAO,KAAY,MACnB,IAAW,GAAc,EAGzB,IAAY,MAAkB,EAAK,MAAM,EAAS,eAAe,KAAA,IAAY,kBAG7E,IACJ,MACC,EAAS,UAAU,WAChB,YACC,EAAS,UACd,WAEI,KAAqB,MAA2C;EACpE,IAAM,IAAM,EAAE,OAAO,MAAM,MAAM;AACjC,MAAI,MAAQ,MAAM,MAAQ,KAAK;AAC7B,OAAgB,KAAO,IAAI,IAAM,EAAE;AACnC;;EAEF,IAAM,IAAS,OAAO,EAAI;AACtB,SAAO,MAAM,EAAO,IAExB,IADgB,KAAK,IAAI,KAAK,IAAI,GAAQ,EAAI,EAAE,EAAI,CAC5B;IAGpB,KAAmB,MAA2C;AAClE,IAAE,gBAAgB;EAClB,IAAM,IAAW,IAAQ;AACzB,EAAI,KAAY,KACd,IAAgB,EAAS;IAIvB,KAAmB,MAA2C;AAClE,IAAE,gBAAgB;EAClB,IAAM,IAAW,IAAQ;AACzB,EAAI,KAAY,KACd,IAAgB,EAAS;IAIvB,IAAqB,EAAc,IACnC,IAAmB,EAAY,IAC/B,IAAoB,EAAa;AAEvC,QACE,kBAAC,OAAD;EACE,WAAW,EACT,EAA2B,EAAE,SAAM,CAAC,EACpC,EAAc,IACd,EACD;YALH;GAOE,kBAAC,UAAD;IACE,MAAK;IACL,SAAS;IACT,UAAU,KAAY,KAAS;IAC/B,cAAW;IACX,OAAM;IACN,WAAW,EACT,0TACA,EACD;cAED,kBAAC,GAAD;KAAM,MAAM;KAAW,MAAM;KAAoB,CAAA;IAC1C,CAAA;GAET,kBAAC,SAAD;IACO;IACL,MAAK;IACE;IACP,UAAU;IACL;IACA;IACC;IACI;IACV,cAAY;IACZ,gBAAc,MAAU,WAAW,KAAA;IACnC,oBAAkB,EAAK,uBAAuB,EAAS;IACvD,WAAW,EACT,8QACA,EACD;IACD,GAAI;IACJ,CAAA;GAEF,kBAAC,UAAD;IACE,MAAK;IACL,SAAS;IACT,UAAU,KAAY,KAAS;IAC/B,cAAW;IACX,OAAM;IACN,WAAW,EACT,0TACA,EACD;cAED,kBAAC,GAAD;KAAM,MAAM;KAAU,MAAM;KAAoB,CAAA;IACzC,CAAA;GACL;;EAGX;AACD,EAAY,cAAc"}
@@ -29,7 +29,7 @@ d.displayName = "PaginationItem";
29
29
  var f = r.forwardRef(({ className: n, isActive: r = !1, asChild: a = !1, ...o }, s) => /* @__PURE__ */ i(a ? e : "button", {
30
30
  ref: s,
31
31
  "aria-current": r ? "page" : void 0,
32
- className: t("inline-flex items-center justify-center h-ds-sm-plus w-ds-sm-plus rounded-ds-md text-ds-md font-medium tabular-nums transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-action-disabled active:scale-95", r ? "bg-accent-9 text-accent-fg" : "hover:bg-surface-raised-hover text-surface-fg", n),
32
+ className: t("inline-flex items-center justify-center h-ds-sm-plus w-ds-sm-plus rounded-control text-ds-md font-medium tabular-nums transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-action-disabled active:scale-95", r ? "bg-accent-9 text-accent-fg" : "hover:bg-surface-raised-hover text-surface-fg", n),
33
33
  ...o
34
34
  }));
35
35
  f.displayName = "PaginationLink";
@@ -1 +1 @@
1
- {"version":3,"file":"pagination.js","names":[],"sources":["../../src/ui/pagination.tsx"],"sourcesContent":["'use client'\n\nimport { Slot } from '@primitives/react-slot'\nimport { IconChevronLeft, IconChevronRight, IconDots } from '@tabler/icons-react'\nimport * as React from 'react'\n\nimport { Icon } from './icon'\nimport { cn } from './lib/utils'\n\nconst PaginationRoot = React.forwardRef<\n HTMLElement,\n React.ComponentPropsWithoutRef<'nav'>\n>(({ className, ...props }, ref) => (\n <nav\n ref={ref}\n role=\"navigation\"\n aria-label=\"pagination\"\n className={cn('mx-auto flex w-full justify-center', className)}\n {...props}\n />\n))\nPaginationRoot.displayName = 'PaginationRoot'\n\nconst PaginationContent = React.forwardRef<\n HTMLUListElement,\n React.ComponentPropsWithoutRef<'ul'>\n>(({ className, ...props }, ref) => (\n <ul\n ref={ref}\n className={cn('flex flex-row items-center gap-ds-02', className)}\n {...props}\n />\n))\nPaginationContent.displayName = 'PaginationContent'\n\nconst PaginationItem = React.forwardRef<\n HTMLLIElement,\n React.ComponentPropsWithoutRef<'li'>\n>(({ className, ...props }, ref) => (\n <li ref={ref} className={cn('', className)} {...props} />\n))\nPaginationItem.displayName = 'PaginationItem'\n\n/**\n * Props for PaginationLink — a single page number button in a pagination row.\n * When `isActive` is true, the button gets the brand interactive fill and `aria-current=\"page\"`.\n *\n * @example\n * // Active page button:\n * <PaginationLink isActive onClick={() => goToPage(3)}>3</PaginationLink>\n *\n * @example\n * // Render as a Next.js Link via asChild:\n * <PaginationLink asChild isActive={currentPage === 5}>\n * <Link href=\"/posts?page=5\">5</Link>\n * </PaginationLink>\n */\nexport interface PaginationLinkProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n isActive?: boolean\n asChild?: boolean\n}\n\nconst PaginationLink = React.forwardRef<HTMLButtonElement, PaginationLinkProps>(\n ({ className, isActive = false, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : 'button'\n return (\n <Comp\n ref={ref}\n aria-current={isActive ? 'page' : undefined}\n className={cn(\n 'inline-flex items-center justify-center h-ds-sm-plus w-ds-sm-plus rounded-ds-md text-ds-md font-medium tabular-nums transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-action-disabled active:scale-95',\n isActive\n ? 'bg-accent-9 text-accent-fg'\n : 'hover:bg-surface-raised-hover text-surface-fg',\n className,\n )}\n {...props}\n />\n )\n },\n)\nPaginationLink.displayName = 'PaginationLink'\n\nconst PaginationPrevious = React.forwardRef<\n HTMLButtonElement,\n PaginationLinkProps\n>(({ className, ...props }, ref) => (\n <PaginationLink\n ref={ref}\n aria-label=\"Go to previous page\"\n className={cn('w-auto gap-ds-02 pl-ds-03 pr-ds-04', className)}\n {...props}\n >\n <Icon icon={IconChevronLeft} size=\"sm\" />\n <span>Previous</span>\n </PaginationLink>\n))\nPaginationPrevious.displayName = 'PaginationPrevious'\n\nconst PaginationNext = React.forwardRef<\n HTMLButtonElement,\n PaginationLinkProps\n>(({ className, ...props }, ref) => (\n <PaginationLink\n ref={ref}\n aria-label=\"Go to next page\"\n className={cn('w-auto gap-ds-02 pl-ds-04 pr-ds-03', className)}\n {...props}\n >\n <span>Next</span>\n <Icon icon={IconChevronRight} size=\"sm\" />\n </PaginationLink>\n))\nPaginationNext.displayName = 'PaginationNext'\n\nconst PaginationEllipsis = React.forwardRef<\n HTMLSpanElement,\n React.ComponentPropsWithoutRef<'span'>\n>(({ className, ...props }, ref) => (\n <span\n ref={ref}\n aria-hidden=\"true\"\n className={cn(\n 'flex h-ds-sm-plus w-ds-sm-plus items-center justify-center text-surface-fg-muted',\n className,\n )}\n {...props}\n >\n <Icon icon={IconDots} size=\"sm\" />\n <span className=\"sr-only\">More pages</span>\n </span>\n))\nPaginationEllipsis.displayName = 'PaginationEllipsis'\n\n/* ------------------------------------------------------------------ */\n/* generatePagination helper */\n/* ------------------------------------------------------------------ */\n\ntype PageItem = number | 'ellipsis'\n\n/**\n * Pure function that builds an array of page numbers and ellipsis markers.\n * Always shows first and last page, plus `siblingCount` pages around `current`.\n *\n * @example generatePagination(5, 10, 1) → [1, 'ellipsis', 4, 5, 6, 'ellipsis', 10]\n */\nfunction generatePagination(\n current: number,\n total: number,\n siblingCount: number,\n): PageItem[] {\n // When total pages fit without any ellipsis\n const totalSlots = siblingCount * 2 + 5 // first + last + current + 2*siblings + 2 ellipsis slots\n if (total <= totalSlots) {\n return Array.from({ length: total }, (_, i) => i + 1)\n }\n\n const leftSibling = Math.max(current - siblingCount, 1)\n const rightSibling = Math.min(current + siblingCount, total)\n\n const showLeftEllipsis = leftSibling > 2\n const showRightEllipsis = rightSibling < total - 1\n\n if (!showLeftEllipsis && showRightEllipsis) {\n // e.g. [1, 2, 3, 4, 5, '...', 10]\n const leftCount = siblingCount * 2 + 3\n const leftPages = Array.from({ length: leftCount }, (_, i) => i + 1)\n return [...leftPages, 'ellipsis', total]\n }\n\n if (showLeftEllipsis && !showRightEllipsis) {\n // e.g. [1, '...', 6, 7, 8, 9, 10]\n const rightCount = siblingCount * 2 + 3\n const rightPages = Array.from(\n { length: rightCount },\n (_, i) => total - rightCount + 1 + i,\n )\n return [1, 'ellipsis', ...rightPages]\n }\n\n // Both ellipses: [1, '...', 4, 5, 6, '...', 10]\n const middlePages = Array.from(\n { length: rightSibling - leftSibling + 1 },\n (_, i) => leftSibling + i,\n )\n return [1, 'ellipsis', ...middlePages, 'ellipsis', total]\n}\n\n/* ------------------------------------------------------------------ */\n/* PaginationNav — controlled convenience wrapper */\n/* ------------------------------------------------------------------ */\n\n/**\n * Props for PaginationNav — a fully self-contained controlled pagination component that renders\n * Previous / page numbers (with ellipsis) / Next — using `generatePagination` internally.\n *\n * **1-indexed:** `currentPage` starts at 1 (not 0). `onPageChange` also receives 1-indexed values.\n *\n * **`siblingCount`:** Number of page buttons shown on each side of the current page (default 1).\n * A wider `siblingCount` shows more page buttons before switching to ellipsis.\n *\n * @example\n * // Basic controlled pagination:\n * <PaginationNav\n * totalPages={24}\n * currentPage={currentPage}\n * onPageChange={setCurrentPage}\n * />\n *\n * @example\n * // Wider sibling range for a results grid (shows more page context):\n * <PaginationNav\n * totalPages={100}\n * currentPage={currentPage}\n * onPageChange={setCurrentPage}\n * siblingCount={2}\n * />\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface PaginationNavProps\n extends React.HTMLAttributes<HTMLElement> {\n /** Total number of pages */\n totalPages: number\n /** Current active page (1-indexed) */\n currentPage: number\n /** Called when the user requests a different page */\n onPageChange: (page: number) => void\n /** Number of sibling page buttons shown on each side of the current page (default: 1) */\n siblingCount?: number\n}\n\nconst PaginationNav = React.forwardRef<HTMLElement, PaginationNavProps>(\n (\n {\n totalPages,\n currentPage,\n onPageChange,\n siblingCount = 1,\n className,\n ...props\n },\n ref,\n ) => {\n const pages = generatePagination(currentPage, totalPages, siblingCount)\n\n return (\n <PaginationRoot ref={ref} className={className} {...props}>\n <PaginationContent>\n <PaginationItem>\n <PaginationPrevious\n onClick={() => onPageChange(Math.max(1, currentPage - 1))}\n disabled={currentPage <= 1}\n />\n </PaginationItem>\n\n {pages.map((page, i) =>\n page === 'ellipsis' ? (\n <PaginationItem key={`e${i}`}>\n <PaginationEllipsis />\n </PaginationItem>\n ) : (\n <PaginationItem key={page}>\n <PaginationLink\n isActive={page === currentPage}\n onClick={() => onPageChange(page)}\n >\n {page}\n </PaginationLink>\n </PaginationItem>\n ),\n )}\n\n <PaginationItem>\n <PaginationNext\n onClick={() =>\n onPageChange(Math.min(totalPages, currentPage + 1))\n }\n disabled={currentPage >= totalPages}\n />\n </PaginationItem>\n </PaginationContent>\n </PaginationRoot>\n )\n },\n)\nPaginationNav.displayName = 'PaginationNav'\n\nexport {\n generatePagination,\n PaginationContent,\n PaginationEllipsis,\n PaginationItem,\n PaginationLink,\n PaginationNav,\n PaginationNext,\n PaginationPrevious,\n PaginationRoot,\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"pagination.js","names":[],"sources":["../../src/ui/pagination.tsx"],"sourcesContent":["'use client'\n\nimport { Slot } from '@primitives/react-slot'\nimport { IconChevronLeft, IconChevronRight, IconDots } from '@tabler/icons-react'\nimport * as React from 'react'\n\nimport { Icon } from './icon'\nimport { cn } from './lib/utils'\n\nconst PaginationRoot = React.forwardRef<\n HTMLElement,\n React.ComponentPropsWithoutRef<'nav'>\n>(({ className, ...props }, ref) => (\n <nav\n ref={ref}\n role=\"navigation\"\n aria-label=\"pagination\"\n className={cn('mx-auto flex w-full justify-center', className)}\n {...props}\n />\n))\nPaginationRoot.displayName = 'PaginationRoot'\n\nconst PaginationContent = React.forwardRef<\n HTMLUListElement,\n React.ComponentPropsWithoutRef<'ul'>\n>(({ className, ...props }, ref) => (\n <ul\n ref={ref}\n className={cn('flex flex-row items-center gap-ds-02', className)}\n {...props}\n />\n))\nPaginationContent.displayName = 'PaginationContent'\n\nconst PaginationItem = React.forwardRef<\n HTMLLIElement,\n React.ComponentPropsWithoutRef<'li'>\n>(({ className, ...props }, ref) => (\n <li ref={ref} className={cn('', className)} {...props} />\n))\nPaginationItem.displayName = 'PaginationItem'\n\n/**\n * Props for PaginationLink — a single page number button in a pagination row.\n * When `isActive` is true, the button gets the brand interactive fill and `aria-current=\"page\"`.\n *\n * @example\n * // Active page button:\n * <PaginationLink isActive onClick={() => goToPage(3)}>3</PaginationLink>\n *\n * @example\n * // Render as a Next.js Link via asChild:\n * <PaginationLink asChild isActive={currentPage === 5}>\n * <Link href=\"/posts?page=5\">5</Link>\n * </PaginationLink>\n */\nexport interface PaginationLinkProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n isActive?: boolean\n asChild?: boolean\n}\n\nconst PaginationLink = React.forwardRef<HTMLButtonElement, PaginationLinkProps>(\n ({ className, isActive = false, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : 'button'\n return (\n <Comp\n ref={ref}\n aria-current={isActive ? 'page' : undefined}\n className={cn(\n 'inline-flex items-center justify-center h-ds-sm-plus w-ds-sm-plus rounded-control text-ds-md font-medium tabular-nums transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-action-disabled active:scale-95',\n isActive\n ? 'bg-accent-9 text-accent-fg'\n : 'hover:bg-surface-raised-hover text-surface-fg',\n className,\n )}\n {...props}\n />\n )\n },\n)\nPaginationLink.displayName = 'PaginationLink'\n\nconst PaginationPrevious = React.forwardRef<\n HTMLButtonElement,\n PaginationLinkProps\n>(({ className, ...props }, ref) => (\n <PaginationLink\n ref={ref}\n aria-label=\"Go to previous page\"\n className={cn('w-auto gap-ds-02 pl-ds-03 pr-ds-04', className)}\n {...props}\n >\n <Icon icon={IconChevronLeft} size=\"sm\" />\n <span>Previous</span>\n </PaginationLink>\n))\nPaginationPrevious.displayName = 'PaginationPrevious'\n\nconst PaginationNext = React.forwardRef<\n HTMLButtonElement,\n PaginationLinkProps\n>(({ className, ...props }, ref) => (\n <PaginationLink\n ref={ref}\n aria-label=\"Go to next page\"\n className={cn('w-auto gap-ds-02 pl-ds-04 pr-ds-03', className)}\n {...props}\n >\n <span>Next</span>\n <Icon icon={IconChevronRight} size=\"sm\" />\n </PaginationLink>\n))\nPaginationNext.displayName = 'PaginationNext'\n\nconst PaginationEllipsis = React.forwardRef<\n HTMLSpanElement,\n React.ComponentPropsWithoutRef<'span'>\n>(({ className, ...props }, ref) => (\n <span\n ref={ref}\n aria-hidden=\"true\"\n className={cn(\n 'flex h-ds-sm-plus w-ds-sm-plus items-center justify-center text-surface-fg-muted',\n className,\n )}\n {...props}\n >\n <Icon icon={IconDots} size=\"sm\" />\n <span className=\"sr-only\">More pages</span>\n </span>\n))\nPaginationEllipsis.displayName = 'PaginationEllipsis'\n\n/* ------------------------------------------------------------------ */\n/* generatePagination helper */\n/* ------------------------------------------------------------------ */\n\ntype PageItem = number | 'ellipsis'\n\n/**\n * Pure function that builds an array of page numbers and ellipsis markers.\n * Always shows first and last page, plus `siblingCount` pages around `current`.\n *\n * @example generatePagination(5, 10, 1) → [1, 'ellipsis', 4, 5, 6, 'ellipsis', 10]\n */\nfunction generatePagination(\n current: number,\n total: number,\n siblingCount: number,\n): PageItem[] {\n // When total pages fit without any ellipsis\n const totalSlots = siblingCount * 2 + 5 // first + last + current + 2*siblings + 2 ellipsis slots\n if (total <= totalSlots) {\n return Array.from({ length: total }, (_, i) => i + 1)\n }\n\n const leftSibling = Math.max(current - siblingCount, 1)\n const rightSibling = Math.min(current + siblingCount, total)\n\n const showLeftEllipsis = leftSibling > 2\n const showRightEllipsis = rightSibling < total - 1\n\n if (!showLeftEllipsis && showRightEllipsis) {\n // e.g. [1, 2, 3, 4, 5, '...', 10]\n const leftCount = siblingCount * 2 + 3\n const leftPages = Array.from({ length: leftCount }, (_, i) => i + 1)\n return [...leftPages, 'ellipsis', total]\n }\n\n if (showLeftEllipsis && !showRightEllipsis) {\n // e.g. [1, '...', 6, 7, 8, 9, 10]\n const rightCount = siblingCount * 2 + 3\n const rightPages = Array.from(\n { length: rightCount },\n (_, i) => total - rightCount + 1 + i,\n )\n return [1, 'ellipsis', ...rightPages]\n }\n\n // Both ellipses: [1, '...', 4, 5, 6, '...', 10]\n const middlePages = Array.from(\n { length: rightSibling - leftSibling + 1 },\n (_, i) => leftSibling + i,\n )\n return [1, 'ellipsis', ...middlePages, 'ellipsis', total]\n}\n\n/* ------------------------------------------------------------------ */\n/* PaginationNav — controlled convenience wrapper */\n/* ------------------------------------------------------------------ */\n\n/**\n * Props for PaginationNav — a fully self-contained controlled pagination component that renders\n * Previous / page numbers (with ellipsis) / Next — using `generatePagination` internally.\n *\n * **1-indexed:** `currentPage` starts at 1 (not 0). `onPageChange` also receives 1-indexed values.\n *\n * **`siblingCount`:** Number of page buttons shown on each side of the current page (default 1).\n * A wider `siblingCount` shows more page buttons before switching to ellipsis.\n *\n * @example\n * // Basic controlled pagination:\n * <PaginationNav\n * totalPages={24}\n * currentPage={currentPage}\n * onPageChange={setCurrentPage}\n * />\n *\n * @example\n * // Wider sibling range for a results grid (shows more page context):\n * <PaginationNav\n * totalPages={100}\n * currentPage={currentPage}\n * onPageChange={setCurrentPage}\n * siblingCount={2}\n * />\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface PaginationNavProps\n extends React.HTMLAttributes<HTMLElement> {\n /** Total number of pages */\n totalPages: number\n /** Current active page (1-indexed) */\n currentPage: number\n /** Called when the user requests a different page */\n onPageChange: (page: number) => void\n /** Number of sibling page buttons shown on each side of the current page (default: 1) */\n siblingCount?: number\n}\n\nconst PaginationNav = React.forwardRef<HTMLElement, PaginationNavProps>(\n (\n {\n totalPages,\n currentPage,\n onPageChange,\n siblingCount = 1,\n className,\n ...props\n },\n ref,\n ) => {\n const pages = generatePagination(currentPage, totalPages, siblingCount)\n\n return (\n <PaginationRoot ref={ref} className={className} {...props}>\n <PaginationContent>\n <PaginationItem>\n <PaginationPrevious\n onClick={() => onPageChange(Math.max(1, currentPage - 1))}\n disabled={currentPage <= 1}\n />\n </PaginationItem>\n\n {pages.map((page, i) =>\n page === 'ellipsis' ? (\n <PaginationItem key={`e${i}`}>\n <PaginationEllipsis />\n </PaginationItem>\n ) : (\n <PaginationItem key={page}>\n <PaginationLink\n isActive={page === currentPage}\n onClick={() => onPageChange(page)}\n >\n {page}\n </PaginationLink>\n </PaginationItem>\n ),\n )}\n\n <PaginationItem>\n <PaginationNext\n onClick={() =>\n onPageChange(Math.min(totalPages, currentPage + 1))\n }\n disabled={currentPage >= totalPages}\n />\n </PaginationItem>\n </PaginationContent>\n </PaginationRoot>\n )\n },\n)\nPaginationNav.displayName = 'PaginationNav'\n\nexport {\n generatePagination,\n PaginationContent,\n PaginationEllipsis,\n PaginationItem,\n PaginationLink,\n PaginationNav,\n PaginationNext,\n PaginationPrevious,\n PaginationRoot,\n}\n"],"mappings":";;;;;;;;AASA,IAAM,IAAiB,EAAM,YAG1B,EAAE,cAAW,GAAG,KAAS,MAC1B,kBAAC,OAAD;CACO;CACL,MAAK;CACL,cAAW;CACX,WAAW,EAAG,sCAAsC,EAAU;CAC9D,GAAI;CACJ,CAAA,CACF;AACF,EAAe,cAAc;AAE7B,IAAM,IAAoB,EAAM,YAG7B,EAAE,cAAW,GAAG,KAAS,MAC1B,kBAAC,MAAD;CACO;CACL,WAAW,EAAG,wCAAwC,EAAU;CAChE,GAAI;CACJ,CAAA,CACF;AACF,EAAkB,cAAc;AAEhC,IAAM,IAAiB,EAAM,YAG1B,EAAE,cAAW,GAAG,KAAS,MAC1B,kBAAC,MAAD;CAAS;CAAK,WAAW,EAAG,IAAI,EAAU;CAAE,GAAI;CAAS,CAAA,CACzD;AACF,EAAe,cAAc;AAsB7B,IAAM,IAAiB,EAAM,YAC1B,EAAE,cAAW,cAAW,IAAO,aAAU,IAAO,GAAG,KAAS,MAGzD,kBAFW,IAAU,IAAO,UAE5B;CACO;CACL,gBAAc,IAAW,SAAS,KAAA;CAClC,WAAW,EACT,mUACA,IACI,+BACA,iDACJ,EACD;CACD,GAAI;CACJ,CAAA,CAGP;AACD,EAAe,cAAc;AAE7B,IAAM,IAAqB,EAAM,YAG9B,EAAE,cAAW,GAAG,KAAS,MAC1B,kBAAC,GAAD;CACO;CACL,cAAW;CACX,WAAW,EAAG,sCAAsC,EAAU;CAC9D,GAAI;WAJN,CAME,kBAAC,GAAD;EAAM,MAAM;EAAiB,MAAK;EAAO,CAAA,EACzC,kBAAC,QAAD,EAAA,UAAM,YAAe,CAAA,CACN;GACjB;AACF,EAAmB,cAAc;AAEjC,IAAM,IAAiB,EAAM,YAG1B,EAAE,cAAW,GAAG,KAAS,MAC1B,kBAAC,GAAD;CACO;CACL,cAAW;CACX,WAAW,EAAG,sCAAsC,EAAU;CAC9D,GAAI;WAJN,CAME,kBAAC,QAAD,EAAA,UAAM,QAAW,CAAA,EACjB,kBAAC,GAAD;EAAM,MAAM;EAAkB,MAAK;EAAO,CAAA,CAC3B;GACjB;AACF,EAAe,cAAc;AAE7B,IAAM,IAAqB,EAAM,YAG9B,EAAE,cAAW,GAAG,KAAS,MAC1B,kBAAC,QAAD;CACO;CACL,eAAY;CACZ,WAAW,EACT,oFACA,EACD;CACD,GAAI;WAPN,CASE,kBAAC,GAAD;EAAM,MAAM;EAAU,MAAK;EAAO,CAAA,EAClC,kBAAC,QAAD;EAAM,WAAU;YAAU;EAAiB,CAAA,CACtC;GACP;AACF,EAAmB,cAAc;AAcjC,SAAS,EACP,GACA,GACA,GACY;AAGZ,KAAI,KADe,IAAe,IAAI,EAEpC,QAAO,MAAM,KAAK,EAAE,QAAQ,GAAO,GAAG,GAAG,MAAM,IAAI,EAAE;CAGvD,IAAM,IAAc,KAAK,IAAI,IAAU,GAAc,EAAE,EACjD,IAAe,KAAK,IAAI,IAAU,GAAc,EAAM,EAEtD,IAAmB,IAAc,GACjC,IAAoB,IAAe,IAAQ;AAEjD,KAAI,CAAC,KAAoB,GAAmB;EAE1C,IAAM,IAAY,IAAe,IAAI;AAErC,SAAO;GAAC,GADU,MAAM,KAAK,EAAE,QAAQ,GAAW,GAAG,GAAG,MAAM,IAAI,EAAE;GAC9C;GAAY;GAAM;;AAG1C,KAAI,KAAoB,CAAC,GAAmB;EAE1C,IAAM,IAAa,IAAe,IAAI;AAKtC,SAAO;GAAC;GAAG;GAAY,GAJJ,MAAM,KACvB,EAAE,QAAQ,GAAY,GACrB,GAAG,MAAM,IAAQ,IAAa,IAAI,EACpC;GACoC;;AAQvC,QAAO;EAAC;EAAG;EAAY,GAJH,MAAM,KACxB,EAAE,QAAQ,IAAe,IAAc,GAAG,GACzC,GAAG,MAAM,IAAc,EACzB;EACsC;EAAY;EAAM;;AA8C3D,IAAM,IAAgB,EAAM,YAExB,EACE,eACA,gBACA,iBACA,kBAAe,GACf,cACA,GAAG,KAEL,MACG;CACH,IAAM,IAAQ,EAAmB,GAAa,GAAY,EAAa;AAEvE,QACE,kBAAC,GAAD;EAAqB;EAAgB;EAAW,GAAI;YAClD,kBAAC,GAAD,EAAA,UAAA;GACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;IACE,eAAe,EAAa,KAAK,IAAI,GAAG,IAAc,EAAE,CAAC;IACzD,UAAU,KAAe;IACzB,CAAA,EACa,CAAA;GAEhB,EAAM,KAAK,GAAM,MAChB,MAAS,aACP,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAsB,CAAA,EACP,EAFI,IAAI,IAER,GAEjB,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;IACE,UAAU,MAAS;IACnB,eAAe,EAAa,EAAK;cAEhC;IACc,CAAA,EACF,EAPI,EAOJ,CAEpB;GAED,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;IACE,eACE,EAAa,KAAK,IAAI,GAAY,IAAc,EAAE,CAAC;IAErD,UAAU,KAAe;IACzB,CAAA,EACa,CAAA;GACC,EAAA,CAAA;EACL,CAAA;EAGtB;AACD,EAAc,cAAc"}
@@ -7,7 +7,7 @@ import * as a from "react";
7
7
  import { jsx as o, jsxs as s } from "react/jsx-runtime";
8
8
  import { motion as c } from "framer-motion";
9
9
  //#region src/ui/progress.tsx
10
- var l = r("relative w-full overflow-hidden rounded-ds-full bg-surface-raised", {
10
+ var l = r("relative w-full overflow-hidden rounded-pill bg-surface-raised", {
11
11
  variants: { size: {
12
12
  sm: "h-1",
13
13
  md: "h-2",
@@ -1 +1 @@
1
- {"version":3,"file":"progress.js","names":[],"sources":["../../src/ui/progress.tsx"],"sourcesContent":["'use client'\n\nimport * as ProgressPrimitive from '@primitives/react-progress'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { springs } from './lib/motion'\nimport { cn } from './lib/utils'\n\n/* ---------------------------------------------------------------------------\n * CVA Variants\n * ------------------------------------------------------------------------ */\n\nconst progressTrackVariants = cva(\n 'relative w-full overflow-hidden rounded-ds-full bg-surface-raised',\n {\n variants: {\n size: {\n sm: 'h-1',\n md: 'h-2',\n lg: 'h-3',\n },\n },\n defaultVariants: { size: 'md' },\n },\n)\n\nconst progressIndicatorVariants = cva(\n 'h-full w-full flex-1 transition-[width] duration-moderate-02 ease-expressive-standard',\n {\n variants: {\n color: {\n default: 'bg-accent-9',\n success: 'bg-success-9',\n warning: 'bg-warning-9',\n error: 'bg-error-9',\n },\n },\n defaultVariants: { color: 'default' },\n },\n)\n\n/* ---------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------ */\n\n/**\n * Props for Progress — a horizontal progress bar with size and color variants, an optional\n * percentage label, and an indeterminate animation when `value` is undefined/null.\n *\n * **Track size:** `sm` (4px) | `md` (8px, default) | `lg` (12px)\n *\n * **Indicator color:** `default` (brand interactive) | `success` | `warning` | `error`\n *\n * **Indeterminate:** Omit `value` (or pass `undefined`) to show an animated indeterminate bar.\n * When `value` is provided, it should be a number between 0–100.\n *\n * **`showLabel`:** Renders the percentage value next to the bar (only when `value` is set).\n *\n * @example\n * // Determinate upload progress:\n * <Progress value={uploadPercent} color=\"default\" showLabel />\n *\n * @example\n * // Indeterminate loading bar (while waiting for an async operation):\n * <Progress size=\"sm\" />\n *\n * @example\n * // Success-colored completion bar (e.g. after all tasks done):\n * <Progress value={100} color=\"success\" size=\"md\" />\n *\n * @example\n * // Warning threshold indicator (disk usage at 80%):\n * <Progress value={80} color=\"warning\" showLabel size=\"lg\" />\n * // These are just a few ways — feel free to combine props creatively!\n */\ninterface ProgressProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>,\n 'color'\n >,\n VariantProps<typeof progressTrackVariants>,\n VariantProps<typeof progressIndicatorVariants> {\n /** Additional class names for the indicator element */\n indicatorClassName?: string\n /** Display the percentage label next to the progress bar */\n showLabel?: boolean\n /** When true, color auto-shifts by value: 0-59 = default (accent), 60-84 = warning, 85-100 = success, >100 = error. @default false */\n autoColor?: boolean\n}\n\n/* ---------------------------------------------------------------------------\n * Component\n * ------------------------------------------------------------------------ */\n\nconst Progress = React.forwardRef<\n React.ElementRef<typeof ProgressPrimitive.Root>,\n ProgressProps\n>(\n (\n {\n className,\n value,\n size,\n color,\n indicatorClassName,\n showLabel,\n autoColor,\n ...props\n },\n ref,\n ) => {\n const isIndeterminate = value === undefined || value === null\n\n const effectiveColor =\n autoColor && value != null\n ? value > 100\n ? 'error'\n : value >= 85\n ? 'success'\n : value >= 60\n ? 'warning'\n : 'default'\n : color\n\n return (\n <div className={cn('flex items-center gap-ds-03', showLabel && 'w-full')}>\n <ProgressPrimitive.Root\n ref={ref}\n value={isIndeterminate ? null : value}\n className={cn(progressTrackVariants({ size }), className)}\n {...props}\n >\n {isIndeterminate ? (\n <ProgressPrimitive.Indicator\n className={cn(\n progressIndicatorVariants({ color: effectiveColor }),\n 'w-2/5 animate-progress-indeterminate motion-reduce:animate-none',\n indicatorClassName,\n )}\n />\n ) : (\n <ProgressPrimitive.Indicator\n className={cn('h-full', indicatorClassName)}\n asChild\n >\n <motion.div\n className={cn(\n progressIndicatorVariants({ color: effectiveColor }),\n 'transition-colors duration-moderate-01 ease-productive-standard',\n )}\n initial={false}\n animate={{ width: `${value || 0}%` }}\n transition={springs.smooth}\n />\n </ProgressPrimitive.Indicator>\n )}\n </ProgressPrimitive.Root>\n\n {showLabel && !isIndeterminate && (\n <span className=\"shrink-0 text-ds-xs text-surface-fg-muted tabular-nums\">\n {value}%\n </span>\n )}\n </div>\n )\n },\n)\nProgress.displayName = ProgressPrimitive.Root.displayName\n\nexport { Progress, progressIndicatorVariants,progressTrackVariants }\nexport type { ProgressProps }\n"],"mappings":";;;;;;;;;AAcA,IAAM,IAAwB,EAC5B,qEACA;CACE,UAAU,EACR,MAAM;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACL,EACF;CACD,iBAAiB,EAAE,MAAM,MAAM;CAChC,CACF,EAEK,IAA4B,EAChC,yFACA;CACE,UAAU,EACR,OAAO;EACL,SAAS;EACT,SAAS;EACT,SAAS;EACT,OAAO;EACR,EACF;CACD,iBAAiB,EAAE,OAAO,WAAW;CACtC,CACF,EAuDK,IAAW,EAAM,YAKnB,EACE,cACA,UACA,SACA,UACA,uBACA,cACA,cACA,GAAG,KAEL,MACG;CACH,IAAM,IAAkB,KAAiC,MAEnD,IACJ,KAAa,KAAS,OAClB,IAAQ,MACN,UACA,KAAS,KACP,YACA,KAAS,KACP,YACA,YACN;AAEN,QACE,kBAAC,OAAD;EAAK,WAAW,EAAG,+BAA+B,KAAa,SAAS;YAAxE,CACE,kBAAC,GAAD;GACO;GACL,OAAO,IAAkB,OAAO;GAChC,WAAW,EAAG,EAAsB,EAAE,SAAM,CAAC,EAAE,EAAU;GACzD,GAAI;aAEH,IACC,kBAAC,GAAD,EACE,WAAW,EACT,EAA0B,EAAE,OAAO,GAAgB,CAAC,EACpD,mEACA,EACD,EACD,CAAA,GAEF,kBAAC,GAAD;IACE,WAAW,EAAG,UAAU,EAAmB;IAC3C,SAAA;cAEA,kBAAC,EAAO,KAAR;KACE,WAAW,EACT,EAA0B,EAAE,OAAO,GAAgB,CAAC,EACpD,kEACD;KACD,SAAS;KACT,SAAS,EAAE,OAAO,GAAG,KAAS,EAAE,IAAI;KACpC,YAAY,EAAQ;KACpB,CAAA;IAC0B,CAAA;GAET,CAAA,EAExB,KAAa,CAAC,KACb,kBAAC,QAAD;GAAM,WAAU;aAAhB,CACG,GAAM,IACF;KAEL;;EAGX;AACD,EAAS,cAAA,EAAqC"}
1
+ {"version":3,"file":"progress.js","names":[],"sources":["../../src/ui/progress.tsx"],"sourcesContent":["'use client'\n\nimport * as ProgressPrimitive from '@primitives/react-progress'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { springs } from './lib/motion'\nimport { cn } from './lib/utils'\n\n/* ---------------------------------------------------------------------------\n * CVA Variants\n * ------------------------------------------------------------------------ */\n\nconst progressTrackVariants = cva(\n 'relative w-full overflow-hidden rounded-pill bg-surface-raised',\n {\n variants: {\n size: {\n sm: 'h-1',\n md: 'h-2',\n lg: 'h-3',\n },\n },\n defaultVariants: { size: 'md' },\n },\n)\n\nconst progressIndicatorVariants = cva(\n 'h-full w-full flex-1 transition-[width] duration-moderate-02 ease-expressive-standard',\n {\n variants: {\n color: {\n default: 'bg-accent-9',\n success: 'bg-success-9',\n warning: 'bg-warning-9',\n error: 'bg-error-9',\n },\n },\n defaultVariants: { color: 'default' },\n },\n)\n\n/* ---------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------ */\n\n/**\n * Props for Progress — a horizontal progress bar with size and color variants, an optional\n * percentage label, and an indeterminate animation when `value` is undefined/null.\n *\n * **Track size:** `sm` (4px) | `md` (8px, default) | `lg` (12px)\n *\n * **Indicator color:** `default` (brand interactive) | `success` | `warning` | `error`\n *\n * **Indeterminate:** Omit `value` (or pass `undefined`) to show an animated indeterminate bar.\n * When `value` is provided, it should be a number between 0–100.\n *\n * **`showLabel`:** Renders the percentage value next to the bar (only when `value` is set).\n *\n * @example\n * // Determinate upload progress:\n * <Progress value={uploadPercent} color=\"default\" showLabel />\n *\n * @example\n * // Indeterminate loading bar (while waiting for an async operation):\n * <Progress size=\"sm\" />\n *\n * @example\n * // Success-colored completion bar (e.g. after all tasks done):\n * <Progress value={100} color=\"success\" size=\"md\" />\n *\n * @example\n * // Warning threshold indicator (disk usage at 80%):\n * <Progress value={80} color=\"warning\" showLabel size=\"lg\" />\n * // These are just a few ways — feel free to combine props creatively!\n */\ninterface ProgressProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>,\n 'color'\n >,\n VariantProps<typeof progressTrackVariants>,\n VariantProps<typeof progressIndicatorVariants> {\n /** Additional class names for the indicator element */\n indicatorClassName?: string\n /** Display the percentage label next to the progress bar */\n showLabel?: boolean\n /** When true, color auto-shifts by value: 0-59 = default (accent), 60-84 = warning, 85-100 = success, >100 = error. @default false */\n autoColor?: boolean\n}\n\n/* ---------------------------------------------------------------------------\n * Component\n * ------------------------------------------------------------------------ */\n\nconst Progress = React.forwardRef<\n React.ElementRef<typeof ProgressPrimitive.Root>,\n ProgressProps\n>(\n (\n {\n className,\n value,\n size,\n color,\n indicatorClassName,\n showLabel,\n autoColor,\n ...props\n },\n ref,\n ) => {\n const isIndeterminate = value === undefined || value === null\n\n const effectiveColor =\n autoColor && value != null\n ? value > 100\n ? 'error'\n : value >= 85\n ? 'success'\n : value >= 60\n ? 'warning'\n : 'default'\n : color\n\n return (\n <div className={cn('flex items-center gap-ds-03', showLabel && 'w-full')}>\n <ProgressPrimitive.Root\n ref={ref}\n value={isIndeterminate ? null : value}\n className={cn(progressTrackVariants({ size }), className)}\n {...props}\n >\n {isIndeterminate ? (\n <ProgressPrimitive.Indicator\n className={cn(\n progressIndicatorVariants({ color: effectiveColor }),\n 'w-2/5 animate-progress-indeterminate motion-reduce:animate-none',\n indicatorClassName,\n )}\n />\n ) : (\n <ProgressPrimitive.Indicator\n className={cn('h-full', indicatorClassName)}\n asChild\n >\n <motion.div\n className={cn(\n progressIndicatorVariants({ color: effectiveColor }),\n 'transition-colors duration-moderate-01 ease-productive-standard',\n )}\n initial={false}\n animate={{ width: `${value || 0}%` }}\n transition={springs.smooth}\n />\n </ProgressPrimitive.Indicator>\n )}\n </ProgressPrimitive.Root>\n\n {showLabel && !isIndeterminate && (\n <span className=\"shrink-0 text-ds-xs text-surface-fg-muted tabular-nums\">\n {value}%\n </span>\n )}\n </div>\n )\n },\n)\nProgress.displayName = ProgressPrimitive.Root.displayName\n\nexport { Progress, progressIndicatorVariants,progressTrackVariants }\nexport type { ProgressProps }\n"],"mappings":";;;;;;;;;AAcA,IAAM,IAAwB,EAC5B,kEACA;CACE,UAAU,EACR,MAAM;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACL,EACF;CACD,iBAAiB,EAAE,MAAM,MAAM;CAChC,CACF,EAEK,IAA4B,EAChC,yFACA;CACE,UAAU,EACR,OAAO;EACL,SAAS;EACT,SAAS;EACT,SAAS;EACT,OAAO;EACR,EACF;CACD,iBAAiB,EAAE,OAAO,WAAW;CACtC,CACF,EAuDK,IAAW,EAAM,YAKnB,EACE,cACA,UACA,SACA,UACA,uBACA,cACA,cACA,GAAG,KAEL,MACG;CACH,IAAM,IAAkB,KAAiC,MAEnD,IACJ,KAAa,KAAS,OAClB,IAAQ,MACN,UACA,KAAS,KACP,YACA,KAAS,KACP,YACA,YACN;AAEN,QACE,kBAAC,OAAD;EAAK,WAAW,EAAG,+BAA+B,KAAa,SAAS;YAAxE,CACE,kBAAC,GAAD;GACO;GACL,OAAO,IAAkB,OAAO;GAChC,WAAW,EAAG,EAAsB,EAAE,SAAM,CAAC,EAAE,EAAU;GACzD,GAAI;aAEH,IACC,kBAAC,GAAD,EACE,WAAW,EACT,EAA0B,EAAE,OAAO,GAAgB,CAAC,EACpD,mEACA,EACD,EACD,CAAA,GAEF,kBAAC,GAAD;IACE,WAAW,EAAG,UAAU,EAAmB;IAC3C,SAAA;cAEA,kBAAC,EAAO,KAAR;KACE,WAAW,EACT,EAA0B,EAAE,OAAO,GAAgB,CAAC,EACpD,kEACD;KACD,SAAS;KACT,SAAS,EAAE,OAAO,GAAG,KAAS,EAAE,IAAI;KACpC,YAAY,EAAQ;KACpB,CAAA;IAC0B,CAAA;GAET,CAAA,EAExB,KAAa,CAAC,KACb,kBAAC,QAAD;GAAM,WAAU;aAAhB,CACG,GAAM,IACF;KAEL;;EAGX;AACD,EAAS,cAAA,EAAqC"}
package/dist/ui/radio.js CHANGED
@@ -30,7 +30,7 @@ var d = {
30
30
  lg: "h-2.5 w-2.5"
31
31
  }, p = o.forwardRef(({ className: e, size: a = "md", ...o }, u) => /* @__PURE__ */ s(n, {
32
32
  ref: u,
33
- className: i("touch-target aspect-square rounded-ds-full", d[a], "border border-surface-border-strong bg-surface-raised-hover", "transition-colors duration-fast-01", "focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2", "disabled:cursor-not-allowed disabled:opacity-action-disabled", "hover:border-accent-7 hover:bg-surface-raised-active", "data-[state=checked]:border-accent-7", e),
33
+ className: i("touch-target aspect-square rounded-pill", d[a], "border border-surface-border-strong bg-surface-raised-hover", "transition-colors duration-fast-01", "focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2", "disabled:cursor-not-allowed disabled:opacity-action-disabled", "hover:border-accent-7 hover:bg-surface-raised-active", "data-[state=checked]:border-accent-7", e),
34
34
  ...o,
35
35
  children: /* @__PURE__ */ s(t, {
36
36
  asChild: !0,
@@ -1 +1 @@
1
- {"version":3,"file":"radio.js","names":[],"sources":["../../src/ui/radio.tsx"],"sourcesContent":["'use client'\n\nimport * as RadioGroupPrimitive from '@primitives/react-radio-group'\nimport { IconCircle } from '@tabler/icons-react'\nimport { AnimatePresence, motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useFormField } from './form'\nimport { springs } from './lib/motion'\nimport { cn } from './lib/utils'\n\nconst RadioGroup = React.forwardRef<\n React.ElementRef<typeof RadioGroupPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>\n>(({ className, ...props }, ref) => {\n const fieldCtx = useFormField()\n const isError = fieldCtx.state === 'error'\n const ariaDescribedBy = props['aria-describedby'] ?? fieldCtx.helperTextId\n const ariaRequired = props['aria-required'] ?? fieldCtx.required\n\n return (\n <RadioGroupPrimitive.Root\n className={cn('grid gap-ds-03', className)}\n aria-invalid={isError || undefined}\n aria-describedby={ariaDescribedBy}\n aria-required={ariaRequired || undefined}\n {...props}\n ref={ref}\n />\n )\n})\nRadioGroup.displayName = RadioGroupPrimitive.Root.displayName\n\nexport interface RadioGroupItemProps extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item> {\n /** Control size — `sm` (20px), `md` (24px, default, WCAG compliant), `lg` (28px). */\n size?: 'sm' | 'md' | 'lg'\n}\n\nconst radioSizeClasses = {\n sm: 'h-5 w-5',\n md: 'h-6 w-6',\n lg: 'h-7 w-7',\n} as const\n\nconst radioIndicatorClasses = {\n sm: 'h-1.5 w-1.5',\n md: 'h-ds-03 w-ds-03',\n lg: 'h-2.5 w-2.5',\n} as const\n\nconst RadioGroupItem = React.forwardRef<\n React.ElementRef<typeof RadioGroupPrimitive.Item>,\n RadioGroupItemProps\n>(({ className, size = 'md', ...props }, ref) => {\n return (\n <RadioGroupPrimitive.Item\n ref={ref}\n className={cn(\n 'touch-target aspect-square rounded-ds-full',\n radioSizeClasses[size],\n 'border border-surface-border-strong bg-surface-raised-hover',\n 'transition-colors duration-fast-01',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2',\n 'disabled:cursor-not-allowed disabled:opacity-action-disabled',\n 'hover:border-accent-7 hover:bg-surface-raised-active',\n 'data-[state=checked]:border-accent-7',\n className,\n )}\n {...props}\n >\n <RadioGroupPrimitive.Indicator asChild className=\"flex items-center justify-center\">\n <motion.span\n className=\"flex items-center justify-center\"\n initial={{ scale: 0 }}\n animate={{ scale: 1 }}\n transition={springs.bouncy}\n >\n <IconCircle className={cn(radioIndicatorClasses[size], 'fill-accent-9 text-accent-11')} />\n </motion.span>\n </RadioGroupPrimitive.Indicator>\n </RadioGroupPrimitive.Item>\n )\n})\nRadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName\n\nexport type RadioGroupProps = React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>\n\nexport { RadioGroup, RadioGroupItem }\n"],"mappings":";;;;;;;;;;AAWA,IAAM,IAAa,EAAM,YAGtB,EAAE,cAAW,GAAG,KAAS,MAAQ;CAClC,IAAM,IAAW,GAAc,EACzB,IAAU,EAAS,UAAU,SAC7B,IAAkB,EAAM,uBAAuB,EAAS,cACxD,IAAe,EAAM,oBAAoB,EAAS;AAExD,QACE,kBAAC,GAAD;EACE,WAAW,EAAG,kBAAkB,EAAU;EAC1C,gBAAc,KAAW,KAAA;EACzB,oBAAkB;EAClB,iBAAe,KAAgB,KAAA;EAC/B,GAAI;EACC;EACL,CAAA;EAEJ;AACF,EAAW,cAAA,EAAuC;AAOlD,IAAM,IAAmB;CACvB,IAAI;CACJ,IAAI;CACJ,IAAI;CACL,EAEK,IAAwB;CAC5B,IAAI;CACJ,IAAI;CACJ,IAAI;CACL,EAEK,IAAiB,EAAM,YAG1B,EAAE,cAAW,UAAO,MAAM,GAAG,KAAS,MAErC,kBAAC,GAAD;CACO;CACL,WAAW,EACT,8CACA,EAAiB,IACjB,+DACA,sCACA,6GACA,gEACA,wDACA,wCACA,EACD;CACD,GAAI;WAEJ,kBAAC,GAAD;EAA+B,SAAA;EAAQ,WAAU;YAC/C,kBAAC,EAAO,MAAR;GACE,WAAU;GACV,SAAS,EAAE,OAAO,GAAG;GACrB,SAAS,EAAE,OAAO,GAAG;GACrB,YAAY,EAAQ;aAEpB,kBAAC,GAAD,EAAY,WAAW,EAAG,EAAsB,IAAO,+BAA+B,EAAI,CAAA;GAC9E,CAAA;EACgB,CAAA;CACP,CAAA,CAE7B;AACF,EAAe,cAAA,EAAuC"}
1
+ {"version":3,"file":"radio.js","names":[],"sources":["../../src/ui/radio.tsx"],"sourcesContent":["'use client'\n\nimport * as RadioGroupPrimitive from '@primitives/react-radio-group'\nimport { IconCircle } from '@tabler/icons-react'\nimport { AnimatePresence, motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useFormField } from './form'\nimport { springs } from './lib/motion'\nimport { cn } from './lib/utils'\n\nconst RadioGroup = React.forwardRef<\n React.ElementRef<typeof RadioGroupPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>\n>(({ className, ...props }, ref) => {\n const fieldCtx = useFormField()\n const isError = fieldCtx.state === 'error'\n const ariaDescribedBy = props['aria-describedby'] ?? fieldCtx.helperTextId\n const ariaRequired = props['aria-required'] ?? fieldCtx.required\n\n return (\n <RadioGroupPrimitive.Root\n className={cn('grid gap-ds-03', className)}\n aria-invalid={isError || undefined}\n aria-describedby={ariaDescribedBy}\n aria-required={ariaRequired || undefined}\n {...props}\n ref={ref}\n />\n )\n})\nRadioGroup.displayName = RadioGroupPrimitive.Root.displayName\n\nexport interface RadioGroupItemProps extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item> {\n /** Control size — `sm` (20px), `md` (24px, default, WCAG compliant), `lg` (28px). */\n size?: 'sm' | 'md' | 'lg'\n}\n\nconst radioSizeClasses = {\n sm: 'h-5 w-5',\n md: 'h-6 w-6',\n lg: 'h-7 w-7',\n} as const\n\nconst radioIndicatorClasses = {\n sm: 'h-1.5 w-1.5',\n md: 'h-ds-03 w-ds-03',\n lg: 'h-2.5 w-2.5',\n} as const\n\nconst RadioGroupItem = React.forwardRef<\n React.ElementRef<typeof RadioGroupPrimitive.Item>,\n RadioGroupItemProps\n>(({ className, size = 'md', ...props }, ref) => {\n return (\n <RadioGroupPrimitive.Item\n ref={ref}\n className={cn(\n 'touch-target aspect-square rounded-pill',\n radioSizeClasses[size],\n 'border border-surface-border-strong bg-surface-raised-hover',\n 'transition-colors duration-fast-01',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2',\n 'disabled:cursor-not-allowed disabled:opacity-action-disabled',\n 'hover:border-accent-7 hover:bg-surface-raised-active',\n 'data-[state=checked]:border-accent-7',\n className,\n )}\n {...props}\n >\n <RadioGroupPrimitive.Indicator asChild className=\"flex items-center justify-center\">\n <motion.span\n className=\"flex items-center justify-center\"\n initial={{ scale: 0 }}\n animate={{ scale: 1 }}\n transition={springs.bouncy}\n >\n <IconCircle className={cn(radioIndicatorClasses[size], 'fill-accent-9 text-accent-11')} />\n </motion.span>\n </RadioGroupPrimitive.Indicator>\n </RadioGroupPrimitive.Item>\n )\n})\nRadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName\n\nexport type RadioGroupProps = React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>\n\nexport { RadioGroup, RadioGroupItem }\n"],"mappings":";;;;;;;;;;AAWA,IAAM,IAAa,EAAM,YAGtB,EAAE,cAAW,GAAG,KAAS,MAAQ;CAClC,IAAM,IAAW,GAAc,EACzB,IAAU,EAAS,UAAU,SAC7B,IAAkB,EAAM,uBAAuB,EAAS,cACxD,IAAe,EAAM,oBAAoB,EAAS;AAExD,QACE,kBAAC,GAAD;EACE,WAAW,EAAG,kBAAkB,EAAU;EAC1C,gBAAc,KAAW,KAAA;EACzB,oBAAkB;EAClB,iBAAe,KAAgB,KAAA;EAC/B,GAAI;EACC;EACL,CAAA;EAEJ;AACF,EAAW,cAAA,EAAuC;AAOlD,IAAM,IAAmB;CACvB,IAAI;CACJ,IAAI;CACJ,IAAI;CACL,EAEK,IAAwB;CAC5B,IAAI;CACJ,IAAI;CACJ,IAAI;CACL,EAEK,IAAiB,EAAM,YAG1B,EAAE,cAAW,UAAO,MAAM,GAAG,KAAS,MAErC,kBAAC,GAAD;CACO;CACL,WAAW,EACT,2CACA,EAAiB,IACjB,+DACA,sCACA,6GACA,gEACA,wDACA,wCACA,EACD;CACD,GAAI;WAEJ,kBAAC,GAAD;EAA+B,SAAA;EAAQ,WAAU;YAC/C,kBAAC,EAAO,MAAR;GACE,WAAU;GACV,SAAS,EAAE,OAAO,GAAG;GACrB,SAAS,EAAE,OAAO,GAAG;GACrB,YAAY,EAAQ;aAEpB,kBAAC,GAAD,EAAY,WAAW,EAAG,EAAsB,IAAO,+BAA+B,EAAI,CAAA;GAC9E,CAAA;EACgB,CAAA;CACP,CAAA,CAE7B;AACF,EAAe,cAAA,EAAuC"}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import * as React from 'react';
3
3
  export type SegmentedControlSize = 'sm' | 'md' | 'lg';
4
- export type SegmentedControlVariant = 'default' | 'solid' | /** @deprecated Use `'solid'` instead. */ 'accent';
4
+ export type SegmentedControlVariant = 'default' | 'solid';
5
5
  export interface SegmentedControlOption {
6
6
  id: string;
7
7
  text: string;
@@ -1 +1 @@
1
- {"version":3,"file":"segmented-control.d.ts","sourceRoot":"","sources":["../../src/ui/segmented-control.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAM9B,MAAM,MAAM,oBAAoB,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AACrD,MAAM,MAAM,uBAAuB,GAAG,SAAS,GAAG,OAAO,GAAG,yCAAyC,CAAC,QAAQ,CAAA;AAE9G,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,8DAA8D;IAC9D,IAAI,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACnD;AAED,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC;IACnG,IAAI,CAAC,EAAE,oBAAoB,CAAA;IAC3B,OAAO,CAAC,EAAE,uBAAuB,CAAA;IACjC,OAAO,EAAE,sBAAsB,EAAE,CAAA;IACjC,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAiCD,QAAA,MAAM,gBAAgB,8FA+HrB,CAAA;AAKD,OAAO,EAAE,gBAAgB,EAAE,CAAA"}
1
+ {"version":3,"file":"segmented-control.d.ts","sourceRoot":"","sources":["../../src/ui/segmented-control.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAM9B,MAAM,MAAM,oBAAoB,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AACrD,MAAM,MAAM,uBAAuB,GAAG,SAAS,GAAG,OAAO,CAAA;AAEzD,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,8DAA8D;IAC9D,IAAI,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACnD;AAED,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC;IACnG,IAAI,CAAC,EAAE,oBAAoB,CAAA;IAC3B,OAAO,CAAC,EAAE,uBAAuB,CAAA;IACjC,OAAO,EAAE,sBAAsB,EAAE,CAAA;IACjC,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AA6BD,QAAA,MAAM,gBAAgB,8FA+HrB,CAAA;AAKD,OAAO,EAAE,gBAAgB,EAAE,CAAA"}
@@ -19,12 +19,10 @@ var o = {
19
19
  }
20
20
  }, s = {
21
21
  default: "bg-surface-overlay shadow-raised",
22
- solid: "bg-accent-9",
23
- accent: "bg-accent-9"
22
+ solid: "bg-accent-9"
24
23
  }, c = {
25
24
  default: "text-surface-fg",
26
- solid: "text-accent-fg",
27
- accent: "text-accent-fg"
25
+ solid: "text-accent-fg"
28
26
  }, l = {
29
27
  type: "spring",
30
28
  stiffness: 400,
@@ -60,7 +58,7 @@ var o = {
60
58
  tabIndex: -1,
61
59
  "aria-label": _["aria-label"] ?? "Segmented control",
62
60
  onKeyDown: S,
63
- className: e("inline-flex p-[3px] rounded-ds-lg", "bg-surface-raised-hover border border-surface-border-subtle shadow-inset", h && "opacity-action-disabled pointer-events-none", g),
61
+ className: e("inline-flex p-[3px] rounded-pill", "bg-surface-raised-hover border border-surface-border-subtle shadow-inset", h && "opacity-action-disabled pointer-events-none", g),
64
62
  ..._,
65
63
  children: /* @__PURE__ */ n(i, {
66
64
  id: y,
@@ -73,11 +71,11 @@ var o = {
73
71
  tabIndex: i ? 0 : -1,
74
72
  disabled: h,
75
73
  onClick: () => m(t.id),
76
- className: e("relative inline-flex items-center justify-center gap-ds-02 rounded-ds-md", "font-medium transition-colors duration-fast-02 ease-productive-standard", "outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2", C, i ? c[d] : "text-surface-fg-muted hover:text-surface-fg"),
74
+ className: e("relative inline-flex items-center justify-center gap-ds-02 rounded-pill", "font-medium transition-colors duration-fast-02 ease-productive-standard", "outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2", C, i ? c[d] : "text-surface-fg-muted hover:text-surface-fg"),
77
75
  children: [
78
76
  i && /* @__PURE__ */ n(a.span, {
79
77
  layoutId: "segment-pill",
80
- className: e("absolute inset-0 rounded-ds-md pointer-events-none", s[d]),
78
+ className: e("absolute inset-0 rounded-pill pointer-events-none", s[d]),
81
79
  transition: l
82
80
  }),
83
81
  o && /* @__PURE__ */ n(o, { className: e("relative z-[1] shrink-0", w) }),
@@ -1 +1 @@
1
- {"version":3,"file":"segmented-control.js","names":[],"sources":["../../src/ui/segmented-control.tsx"],"sourcesContent":["'use client'\n\nimport { LayoutGroup,motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { cn } from './lib/utils'\n\n/* ── Types ─────────────────────────────────────────────────── */\n\nexport type SegmentedControlSize = 'sm' | 'md' | 'lg'\nexport type SegmentedControlVariant = 'default' | 'solid' | /** @deprecated Use `'solid'` instead. */ 'accent'\n\nexport interface SegmentedControlOption {\n id: string\n text: string\n /** Optional icon component rendered before the text label. */\n icon?: React.ComponentType<{ className?: string }>\n}\n\nexport interface SegmentedControlProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect'> {\n size?: SegmentedControlSize\n variant?: SegmentedControlVariant\n options: SegmentedControlOption[]\n selectedId: string\n onSelect: (id: string) => void\n disabled?: boolean\n}\n\n/* ── Size config ───────────────────────────────────────────── */\n\nconst sizeConfig = {\n sm: { button: 'h-7 px-ds-04 text-ds-sm', icon: 'h-3.5 w-3.5' },\n md: { button: 'h-8 px-ds-05 text-ds-md', icon: 'h-4 w-4' },\n lg: { button: 'h-10 px-ds-06 text-ds-md', icon: 'h-4 w-4' },\n} as const\n\n/* ── Pill styles per variant ───────────────────────────────── */\n\nconst pillStyles = {\n default: 'bg-surface-overlay shadow-raised',\n solid: 'bg-accent-9',\n /** @deprecated Use `solid` instead. */\n accent: 'bg-accent-9',\n} as const\n\nconst selectedTextStyles = {\n default: 'text-surface-fg',\n solid: 'text-accent-fg',\n /** @deprecated Use `solid` instead. */\n accent: 'text-accent-fg',\n} as const\n\n/* ── Spring config (snappy, minimal overshoot) ─────────────── */\n/* Intentionally softer than springs.snappy (500/30/0.5) for pill slide feel */\n\nconst pillSpring = { type: 'spring' as const, stiffness: 400, damping: 30 }\n\n/* ── SegmentedControl ──────────────────────────────────────── */\n\nconst SegmentedControl = React.forwardRef<HTMLDivElement, SegmentedControlProps>(\n function SegmentedControl(\n {\n size = 'md',\n variant = 'default',\n options,\n selectedId,\n onSelect,\n disabled = false,\n className,\n ...props\n },\n ref,\n ) {\n const instanceId = React.useId()\n const tablistRef = React.useRef<HTMLDivElement | null>(null)\n\n // Compose refs\n const mergedRef = React.useCallback(\n (node: HTMLDivElement | null) => {\n tablistRef.current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node\n },\n [ref],\n )\n\n // Keyboard navigation\n const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (disabled) return\n\n const currentIndex = options.findIndex((o) => o.id === selectedId)\n let nextIndex = currentIndex\n\n switch (e.key) {\n case 'ArrowLeft':\n e.preventDefault()\n nextIndex = currentIndex > 0 ? currentIndex - 1 : options.length - 1\n break\n case 'ArrowRight':\n e.preventDefault()\n nextIndex = currentIndex < options.length - 1 ? currentIndex + 1 : 0\n break\n case 'Home':\n e.preventDefault()\n nextIndex = 0\n break\n case 'End':\n e.preventDefault()\n nextIndex = options.length - 1\n break\n default:\n return\n }\n\n onSelect(options[nextIndex].id)\n requestAnimationFrame(() => {\n const buttons = tablistRef.current?.querySelectorAll<HTMLButtonElement>('[role=\"tab\"]')\n buttons?.[nextIndex]?.focus()\n })\n }\n\n const { button: buttonSize, icon: iconSize } = sizeConfig[size]\n\n return (\n <div\n ref={mergedRef}\n role=\"tablist\"\n tabIndex={-1}\n aria-label={props['aria-label'] ?? 'Segmented control'}\n onKeyDown={handleKeyDown}\n className={cn(\n 'inline-flex p-[3px] rounded-ds-lg',\n 'bg-surface-raised-hover border border-surface-border-subtle shadow-inset',\n disabled && 'opacity-action-disabled pointer-events-none',\n className,\n )}\n {...props}\n >\n <LayoutGroup id={instanceId}>\n {options.map((option) => {\n const isSelected = option.id === selectedId\n const OptionIcon = option.icon\n\n return (\n <button\n key={option.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={isSelected}\n tabIndex={isSelected ? 0 : -1}\n disabled={disabled}\n onClick={() => onSelect(option.id)}\n className={cn(\n 'relative inline-flex items-center justify-center gap-ds-02 rounded-ds-md',\n 'font-medium transition-colors duration-fast-02 ease-productive-standard',\n 'outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2',\n buttonSize,\n isSelected\n ? selectedTextStyles[variant]\n : 'text-surface-fg-muted hover:text-surface-fg',\n )}\n >\n {/* Sliding pill indicator */}\n {isSelected && (\n <motion.span\n layoutId=\"segment-pill\"\n className={cn(\n 'absolute inset-0 rounded-ds-md pointer-events-none',\n pillStyles[variant],\n )}\n transition={pillSpring}\n />\n )}\n\n {/* Content (above pill via z-index) */}\n {OptionIcon && (\n <OptionIcon className={cn('relative z-[1] shrink-0', iconSize)} />\n )}\n <span className=\"relative z-[1]\">{option.text}</span>\n </button>\n )\n })}\n </LayoutGroup>\n </div>\n )\n },\n)\nSegmentedControl.displayName = 'SegmentedControl'\n\n/* ── Exports ───────────────────────────────────────────────── */\n\nexport { SegmentedControl }\n"],"mappings":";;;;;;AA8BA,IAAM,IAAa;CACjB,IAAI;EAAE,QAAQ;EAA2B,MAAM;EAAe;CAC9D,IAAI;EAAE,QAAQ;EAA2B,MAAM;EAAW;CAC1D,IAAI;EAAE,QAAQ;EAA4B,MAAM;EAAW;CAC5D,EAIK,IAAa;CACjB,SAAS;CACT,OAAO;CAEP,QAAQ;CACT,EAEK,IAAqB;CACzB,SAAS;CACT,OAAO;CAEP,QAAQ;CACT,EAKK,IAAa;CAAE,MAAM;CAAmB,WAAW;CAAK,SAAS;CAAI,EAIrE,IAAmB,EAAM,WAC7B,SACE,EACE,UAAO,MACP,aAAU,WACV,YACA,eACA,aACA,cAAW,IACX,cACA,GAAG,KAEL,GACA;CACA,IAAM,IAAa,EAAM,OAAO,EAC1B,IAAa,EAAM,OAA8B,KAAK,EAGtD,IAAY,EAAM,aACrB,MAAgC;AAE/B,EADA,EAAW,UAAU,GACjB,OAAO,KAAQ,aAAY,EAAI,EAAK,GAC/B,MAAM,EAAsD,UAAU;IAEjF,CAAC,EAAI,CACN,EAGK,KAAiB,MAA2C;AAChE,MAAI,EAAU;EAEd,IAAM,IAAe,EAAQ,WAAW,MAAM,EAAE,OAAO,EAAW,EAC9D,IAAY;AAEhB,UAAQ,EAAE,KAAV;GACE,KAAK;AAEH,IADA,EAAE,gBAAgB,EAClB,IAAY,IAAe,IAAI,IAAe,IAAI,EAAQ,SAAS;AACnE;GACF,KAAK;AAEH,IADA,EAAE,gBAAgB,EAClB,IAAY,IAAe,EAAQ,SAAS,IAAI,IAAe,IAAI;AACnE;GACF,KAAK;AAEH,IADA,EAAE,gBAAgB,EAClB,IAAY;AACZ;GACF,KAAK;AAEH,IADA,EAAE,gBAAgB,EAClB,IAAY,EAAQ,SAAS;AAC7B;GACF,QACE;;AAIJ,EADA,EAAS,EAAQ,GAAW,GAAG,EAC/B,4BAA4B;AAE1B,IADgB,EAAW,SAAS,iBAAoC,iBAAe,IAC7E,IAAY,OAAO;IAC7B;IAGE,EAAE,QAAQ,GAAY,MAAM,MAAa,EAAW;AAE1D,QACE,kBAAC,OAAD;EACE,KAAK;EACL,MAAK;EACL,UAAU;EACV,cAAY,EAAM,iBAAiB;EACnC,WAAW;EACX,WAAW,EACT,qCACA,4EACA,KAAY,+CACZ,EACD;EACD,GAAI;YAEJ,kBAAC,GAAD;GAAa,IAAI;aACd,EAAQ,KAAK,MAAW;IACvB,IAAM,IAAa,EAAO,OAAO,GAC3B,IAAa,EAAO;AAE1B,WACE,kBAAC,UAAD;KAEE,MAAK;KACL,MAAK;KACL,iBAAe;KACf,UAAU,IAAa,IAAI;KACjB;KACV,eAAe,EAAS,EAAO,GAAG;KAClC,WAAW,EACT,4EACA,2EACA,+FACA,GACA,IACI,EAAmB,KACnB,8CACL;eAhBH;MAmBG,KACC,kBAAC,EAAO,MAAR;OACE,UAAS;OACT,WAAW,EACT,sDACA,EAAW,GACZ;OACD,YAAY;OACZ,CAAA;MAIH,KACC,kBAAC,GAAD,EAAY,WAAW,EAAG,2BAA2B,EAAS,EAAI,CAAA;MAEpE,kBAAC,QAAD;OAAM,WAAU;iBAAkB,EAAO;OAAY,CAAA;MAC9C;OAlCF,EAAO,GAkCL;KAEX;GACU,CAAA;EACV,CAAA;EAGX;AACD,EAAiB,cAAc"}
1
+ {"version":3,"file":"segmented-control.js","names":[],"sources":["../../src/ui/segmented-control.tsx"],"sourcesContent":["'use client'\n\nimport { LayoutGroup,motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { cn } from './lib/utils'\n\n/* ── Types ─────────────────────────────────────────────────── */\n\nexport type SegmentedControlSize = 'sm' | 'md' | 'lg'\nexport type SegmentedControlVariant = 'default' | 'solid'\n\nexport interface SegmentedControlOption {\n id: string\n text: string\n /** Optional icon component rendered before the text label. */\n icon?: React.ComponentType<{ className?: string }>\n}\n\nexport interface SegmentedControlProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect'> {\n size?: SegmentedControlSize\n variant?: SegmentedControlVariant\n options: SegmentedControlOption[]\n selectedId: string\n onSelect: (id: string) => void\n disabled?: boolean\n}\n\n/* ── Size config ───────────────────────────────────────────── */\n\nconst sizeConfig = {\n sm: { button: 'h-7 px-ds-04 text-ds-sm', icon: 'h-3.5 w-3.5' },\n md: { button: 'h-8 px-ds-05 text-ds-md', icon: 'h-4 w-4' },\n lg: { button: 'h-10 px-ds-06 text-ds-md', icon: 'h-4 w-4' },\n} as const\n\n/* ── Pill styles per variant ───────────────────────────────── */\n\nconst pillStyles = {\n default: 'bg-surface-overlay shadow-raised',\n solid: 'bg-accent-9',\n} as const\n\nconst selectedTextStyles = {\n default: 'text-surface-fg',\n solid: 'text-accent-fg',\n} as const\n\n/* ── Spring config (snappy, minimal overshoot) ─────────────── */\n/* Intentionally softer than springs.snappy (500/30/0.5) for pill slide feel */\n\nconst pillSpring = { type: 'spring' as const, stiffness: 400, damping: 30 }\n\n/* ── SegmentedControl ──────────────────────────────────────── */\n\nconst SegmentedControl = React.forwardRef<HTMLDivElement, SegmentedControlProps>(\n function SegmentedControl(\n {\n size = 'md',\n variant = 'default',\n options,\n selectedId,\n onSelect,\n disabled = false,\n className,\n ...props\n },\n ref,\n ) {\n const instanceId = React.useId()\n const tablistRef = React.useRef<HTMLDivElement | null>(null)\n\n // Compose refs\n const mergedRef = React.useCallback(\n (node: HTMLDivElement | null) => {\n tablistRef.current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node\n },\n [ref],\n )\n\n // Keyboard navigation\n const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (disabled) return\n\n const currentIndex = options.findIndex((o) => o.id === selectedId)\n let nextIndex = currentIndex\n\n switch (e.key) {\n case 'ArrowLeft':\n e.preventDefault()\n nextIndex = currentIndex > 0 ? currentIndex - 1 : options.length - 1\n break\n case 'ArrowRight':\n e.preventDefault()\n nextIndex = currentIndex < options.length - 1 ? currentIndex + 1 : 0\n break\n case 'Home':\n e.preventDefault()\n nextIndex = 0\n break\n case 'End':\n e.preventDefault()\n nextIndex = options.length - 1\n break\n default:\n return\n }\n\n onSelect(options[nextIndex].id)\n requestAnimationFrame(() => {\n const buttons = tablistRef.current?.querySelectorAll<HTMLButtonElement>('[role=\"tab\"]')\n buttons?.[nextIndex]?.focus()\n })\n }\n\n const { button: buttonSize, icon: iconSize } = sizeConfig[size]\n\n return (\n <div\n ref={mergedRef}\n role=\"tablist\"\n tabIndex={-1}\n aria-label={props['aria-label'] ?? 'Segmented control'}\n onKeyDown={handleKeyDown}\n className={cn(\n 'inline-flex p-[3px] rounded-pill',\n 'bg-surface-raised-hover border border-surface-border-subtle shadow-inset',\n disabled && 'opacity-action-disabled pointer-events-none',\n className,\n )}\n {...props}\n >\n <LayoutGroup id={instanceId}>\n {options.map((option) => {\n const isSelected = option.id === selectedId\n const OptionIcon = option.icon\n\n return (\n <button\n key={option.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={isSelected}\n tabIndex={isSelected ? 0 : -1}\n disabled={disabled}\n onClick={() => onSelect(option.id)}\n className={cn(\n 'relative inline-flex items-center justify-center gap-ds-02 rounded-pill',\n 'font-medium transition-colors duration-fast-02 ease-productive-standard',\n 'outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2',\n buttonSize,\n isSelected\n ? selectedTextStyles[variant]\n : 'text-surface-fg-muted hover:text-surface-fg',\n )}\n >\n {/* Sliding pill indicator */}\n {isSelected && (\n <motion.span\n layoutId=\"segment-pill\"\n className={cn(\n 'absolute inset-0 rounded-pill pointer-events-none',\n pillStyles[variant],\n )}\n transition={pillSpring}\n />\n )}\n\n {/* Content (above pill via z-index) */}\n {OptionIcon && (\n <OptionIcon className={cn('relative z-[1] shrink-0', iconSize)} />\n )}\n <span className=\"relative z-[1]\">{option.text}</span>\n </button>\n )\n })}\n </LayoutGroup>\n </div>\n )\n },\n)\nSegmentedControl.displayName = 'SegmentedControl'\n\n/* ── Exports ───────────────────────────────────────────────── */\n\nexport { SegmentedControl }\n"],"mappings":";;;;;;AA8BA,IAAM,IAAa;CACjB,IAAI;EAAE,QAAQ;EAA2B,MAAM;EAAe;CAC9D,IAAI;EAAE,QAAQ;EAA2B,MAAM;EAAW;CAC1D,IAAI;EAAE,QAAQ;EAA4B,MAAM;EAAW;CAC5D,EAIK,IAAa;CACjB,SAAS;CACT,OAAO;CACR,EAEK,IAAqB;CACzB,SAAS;CACT,OAAO;CACR,EAKK,IAAa;CAAE,MAAM;CAAmB,WAAW;CAAK,SAAS;CAAI,EAIrE,IAAmB,EAAM,WAC7B,SACE,EACE,UAAO,MACP,aAAU,WACV,YACA,eACA,aACA,cAAW,IACX,cACA,GAAG,KAEL,GACA;CACA,IAAM,IAAa,EAAM,OAAO,EAC1B,IAAa,EAAM,OAA8B,KAAK,EAGtD,IAAY,EAAM,aACrB,MAAgC;AAE/B,EADA,EAAW,UAAU,GACjB,OAAO,KAAQ,aAAY,EAAI,EAAK,GAC/B,MAAM,EAAsD,UAAU;IAEjF,CAAC,EAAI,CACN,EAGK,KAAiB,MAA2C;AAChE,MAAI,EAAU;EAEd,IAAM,IAAe,EAAQ,WAAW,MAAM,EAAE,OAAO,EAAW,EAC9D,IAAY;AAEhB,UAAQ,EAAE,KAAV;GACE,KAAK;AAEH,IADA,EAAE,gBAAgB,EAClB,IAAY,IAAe,IAAI,IAAe,IAAI,EAAQ,SAAS;AACnE;GACF,KAAK;AAEH,IADA,EAAE,gBAAgB,EAClB,IAAY,IAAe,EAAQ,SAAS,IAAI,IAAe,IAAI;AACnE;GACF,KAAK;AAEH,IADA,EAAE,gBAAgB,EAClB,IAAY;AACZ;GACF,KAAK;AAEH,IADA,EAAE,gBAAgB,EAClB,IAAY,EAAQ,SAAS;AAC7B;GACF,QACE;;AAIJ,EADA,EAAS,EAAQ,GAAW,GAAG,EAC/B,4BAA4B;AAE1B,IADgB,EAAW,SAAS,iBAAoC,iBAAe,IAC7E,IAAY,OAAO;IAC7B;IAGE,EAAE,QAAQ,GAAY,MAAM,MAAa,EAAW;AAE1D,QACE,kBAAC,OAAD;EACE,KAAK;EACL,MAAK;EACL,UAAU;EACV,cAAY,EAAM,iBAAiB;EACnC,WAAW;EACX,WAAW,EACT,oCACA,4EACA,KAAY,+CACZ,EACD;EACD,GAAI;YAEJ,kBAAC,GAAD;GAAa,IAAI;aACd,EAAQ,KAAK,MAAW;IACvB,IAAM,IAAa,EAAO,OAAO,GAC3B,IAAa,EAAO;AAE1B,WACE,kBAAC,UAAD;KAEE,MAAK;KACL,MAAK;KACL,iBAAe;KACf,UAAU,IAAa,IAAI;KACjB;KACV,eAAe,EAAS,EAAO,GAAG;KAClC,WAAW,EACT,2EACA,2EACA,+FACA,GACA,IACI,EAAmB,KACnB,8CACL;eAhBH;MAmBG,KACC,kBAAC,EAAO,MAAR;OACE,UAAS;OACT,WAAW,EACT,qDACA,EAAW,GACZ;OACD,YAAY;OACZ,CAAA;MAIH,KACC,kBAAC,GAAD,EAAY,WAAW,EAAG,2BAA2B,EAAS,EAAI,CAAA;MAEpE,kBAAC,QAAD;OAAM,WAAU;iBAAkB,EAAO;OAAY,CAAA;MAC9C;OAlCF,EAAO,GAkCL;KAEX;GACU,CAAA;EACV,CAAA;EAGX;AACD,EAAiB,cAAc"}
package/dist/ui/select.js CHANGED
@@ -10,7 +10,7 @@ import { jsx as S, jsxs as C } from "react/jsx-runtime";
10
10
  import { IconCheck as w, IconChevronDown as T, IconChevronUp as E } from "@tabler/icons-react";
11
11
  import { motion as D } from "framer-motion";
12
12
  //#region src/ui/select.tsx
13
- var O = e, k = r, A = u, j = _("flex w-full items-center justify-between whitespace-nowrap rounded-ds-md placeholder:text-surface-fg-subtle focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-action-disabled [&>span]:line-clamp-1", {
13
+ var O = e, k = r, A = u, j = _("flex w-full items-center justify-between whitespace-nowrap rounded-control placeholder:text-surface-fg-subtle focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-action-disabled [&>span]:line-clamp-1", {
14
14
  variants: {
15
15
  variant: {
16
16
  default: "border border-surface-border-strong bg-surface-raised-hover focus-visible:border-accent-7",
@@ -97,7 +97,7 @@ var F = x.forwardRef(({ className: e, children: n, position: r = "popper", ...a
97
97
  ...h.snappy,
98
98
  opacity: g.fade
99
99
  },
100
- className: v("relative z-popover max-h-96 min-w-[8rem] overflow-hidden rounded-ds-lg border border-surface-border-strong bg-surface-overlay text-surface-fg shadow-floating", r === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1", e),
100
+ className: v("relative z-popover max-h-96 min-w-[8rem] overflow-hidden rounded-overlay border border-surface-border-strong bg-surface-overlay text-surface-fg shadow-floating", r === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1", e),
101
101
  children: [
102
102
  /* @__PURE__ */ S(N, {}),
103
103
  /* @__PURE__ */ S(c, {
@@ -117,7 +117,7 @@ var I = x.forwardRef(({ className: e, ...t }, n) => /* @__PURE__ */ S(s, {
117
117
  I.displayName = s.displayName;
118
118
  var L = x.forwardRef(({ className: e, children: t, ...r }, i) => /* @__PURE__ */ C(n, {
119
119
  ref: i,
120
- className: v("relative flex w-full cursor-default select-none items-center rounded-ds-md py-ds-02b pl-ds-03 pr-ds-07 text-ds-md outline-hidden transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-raised focus:bg-surface-raised focus:text-surface-fg data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled", e),
120
+ className: v("relative flex w-full cursor-default select-none items-center rounded-control py-ds-02b pl-ds-03 pr-ds-07 text-ds-md outline-hidden transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-raised focus:bg-surface-raised focus:text-surface-fg data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled", e),
121
121
  ...r,
122
122
  children: [/* @__PURE__ */ S("span", {
123
123
  className: "absolute right-ds-03 flex h-ico-sm w-ico-sm items-center justify-center",
@@ -1 +1 @@
1
- {"version":3,"file":"select.js","names":[],"sources":["../../src/ui/select.tsx"],"sourcesContent":["'use client'\n\nimport * as SelectPrimitive from '@primitives/react-select'\nimport { IconCheck, IconChevronDown, IconChevronUp } from '@tabler/icons-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useFormField } from './form'\nimport { Icon } from './icon'\nimport { springs, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\n\n/**\n * Select root — manages open/close state and selected value.\n *\n * **Important:** `size` is NOT a prop on `Select`. Set it on `SelectTrigger` instead.\n * Passing `size` directly to `Select` produces no TypeScript error but has no effect.\n *\n * @example\n * // CORRECT — size goes on SelectTrigger:\n * <Select onValueChange={setValue}>\n * <SelectTrigger size=\"lg\">\n * <SelectValue placeholder=\"Choose...\" />\n * </SelectTrigger>\n * <SelectContent>\n * <SelectItem value=\"a\">Option A</SelectItem>\n * <SelectItem value=\"b\">Option B</SelectItem>\n * </SelectContent>\n * </Select>\n *\n * // WRONG — size on Select root is silently ignored (no TypeScript error):\n * // <Select size=\"lg\">...</Select>\n */\nconst Select = SelectPrimitive.Root\n\nconst SelectGroup = SelectPrimitive.Group\n\nconst SelectValue = SelectPrimitive.Value\n\nexport const selectTriggerVariants = cva(\n 'flex w-full items-center justify-between whitespace-nowrap rounded-ds-md placeholder:text-surface-fg-subtle focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-action-disabled [&>span]:line-clamp-1',\n {\n variants: {\n variant: {\n default:\n 'border border-surface-border-strong bg-surface-raised-hover focus-visible:border-accent-7',\n outline:\n 'border border-surface-border-strong bg-transparent focus-visible:border-accent-7',\n ghost:\n 'border border-transparent bg-transparent hover:bg-surface-raised-hover focus-visible:border-accent-7',\n },\n color: {\n default: '',\n error: 'border-error-7 text-error-11 focus-visible:ring-error-9',\n success: 'border-success-7',\n warning: 'border-warning-7',\n },\n size: {\n xs: 'h-ds-xs-plus text-ds-sm px-ds-02',\n sm: 'h-ds-sm text-ds-sm px-ds-03',\n md: 'h-ds-md text-ds-md px-ds-04',\n lg: 'h-ds-lg text-ds-md px-ds-05',\n },\n },\n defaultVariants: { variant: 'default', color: 'default', size: 'md' },\n },\n)\n\n/**\n * Props for SelectTrigger. Use `size` here (not on the `Select` root).\n *\n * @example\n * <SelectTrigger size=\"lg\" className=\"w-[200px]\">\n * <SelectValue placeholder=\"Select an option\" />\n * </SelectTrigger>\n */\nexport interface SelectTriggerProps\n extends Omit<React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>, 'color'>,\n VariantProps<typeof selectTriggerVariants> {}\n\nconst SelectTrigger = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Trigger>,\n SelectTriggerProps\n>(({ className, children, variant, color, size, ...props }, ref) => {\n const fieldCtx = useFormField()\n const isError =\n color === 'error' ||\n (fieldCtx.state === 'error' && color == null)\n const ariaDescribedBy = props['aria-describedby'] ?? fieldCtx.helperTextId\n const ariaRequired = props['aria-required'] ?? fieldCtx.required\n\n return (\n <SelectPrimitive.Trigger\n ref={ref}\n className={cn(selectTriggerVariants({ variant, color: isError && !color ? 'error' : color, size }), className)}\n aria-invalid={isError || undefined}\n aria-describedby={ariaDescribedBy}\n aria-required={ariaRequired || undefined}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n <Icon icon={IconChevronDown} size=\"sm\" className=\"opacity-50\" />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n )\n})\nSelectTrigger.displayName = SelectPrimitive.Trigger.displayName\n\nconst SelectScrollUpButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollUpButton\n ref={ref}\n className={cn(\n 'flex cursor-default items-center justify-center py-ds-02',\n className,\n )}\n {...props}\n >\n <Icon icon={IconChevronUp} size=\"sm\" />\n </SelectPrimitive.ScrollUpButton>\n))\nSelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName\n\nconst SelectScrollDownButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollDownButton\n ref={ref}\n className={cn(\n 'flex cursor-default items-center justify-center py-ds-02',\n className,\n )}\n {...props}\n >\n <Icon icon={IconChevronDown} size=\"sm\" />\n </SelectPrimitive.ScrollDownButton>\n))\nSelectScrollDownButton.displayName =\n SelectPrimitive.ScrollDownButton.displayName\n\nconst SelectContent = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>\n>(({ className, children, position = 'popper', ...props }, ref) => (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n ref={ref}\n position={position}\n asChild\n {...props}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={{ ...springs.snappy, opacity: tweens.fade }}\n className={cn(\n 'relative z-popover max-h-96 min-w-[8rem] overflow-hidden rounded-ds-lg border border-surface-border-strong bg-surface-overlay text-surface-fg shadow-floating',\n position === 'popper' &&\n 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',\n className,\n )}\n >\n <SelectScrollUpButton />\n <SelectPrimitive.Viewport\n className={cn(\n 'p-ds-02',\n position === 'popper' &&\n 'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]',\n )}\n >\n {children}\n </SelectPrimitive.Viewport>\n <SelectScrollDownButton />\n </motion.div>\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n))\nSelectContent.displayName = SelectPrimitive.Content.displayName\n\nconst SelectLabel = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.Label\n ref={ref}\n className={cn('px-ds-03 py-ds-02b text-ds-md font-semibold', className)}\n {...props}\n />\n))\nSelectLabel.displayName = SelectPrimitive.Label.displayName\n\nconst SelectItem = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>\n>(({ className, children, ...props }, ref) => (\n <SelectPrimitive.Item\n ref={ref}\n className={cn(\n 'relative flex w-full cursor-default select-none items-center rounded-ds-md py-ds-02b pl-ds-03 pr-ds-07 text-ds-md outline-hidden transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-raised focus:bg-surface-raised focus:text-surface-fg data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled',\n className,\n )}\n {...props}\n >\n <span className=\"absolute right-ds-03 flex h-ico-sm w-ico-sm items-center justify-center\">\n <SelectPrimitive.ItemIndicator>\n <Icon icon={IconCheck} size=\"sm\" />\n </SelectPrimitive.ItemIndicator>\n </span>\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n))\nSelectItem.displayName = SelectPrimitive.Item.displayName\n\nconst SelectSeparator = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.Separator\n ref={ref}\n className={cn('-mx-ds-01 my-ds-02 h-px bg-surface-border', className)}\n {...props}\n />\n))\nSelectSeparator.displayName = SelectPrimitive.Separator.displayName\n\nexport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectScrollDownButton,\n SelectScrollUpButton,\n SelectSeparator,\n SelectTrigger,\n SelectValue,\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"select.js","names":[],"sources":["../../src/ui/select.tsx"],"sourcesContent":["'use client'\n\nimport * as SelectPrimitive from '@primitives/react-select'\nimport { IconCheck, IconChevronDown, IconChevronUp } from '@tabler/icons-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useFormField } from './form'\nimport { Icon } from './icon'\nimport { springs, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\n\n/**\n * Select root — manages open/close state and selected value.\n *\n * **Important:** `size` is NOT a prop on `Select`. Set it on `SelectTrigger` instead.\n * Passing `size` directly to `Select` produces no TypeScript error but has no effect.\n *\n * @example\n * // CORRECT — size goes on SelectTrigger:\n * <Select onValueChange={setValue}>\n * <SelectTrigger size=\"lg\">\n * <SelectValue placeholder=\"Choose...\" />\n * </SelectTrigger>\n * <SelectContent>\n * <SelectItem value=\"a\">Option A</SelectItem>\n * <SelectItem value=\"b\">Option B</SelectItem>\n * </SelectContent>\n * </Select>\n *\n * // WRONG — size on Select root is silently ignored (no TypeScript error):\n * // <Select size=\"lg\">...</Select>\n */\nconst Select = SelectPrimitive.Root\n\nconst SelectGroup = SelectPrimitive.Group\n\nconst SelectValue = SelectPrimitive.Value\n\nexport const selectTriggerVariants = cva(\n 'flex w-full items-center justify-between whitespace-nowrap rounded-control placeholder:text-surface-fg-subtle focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-action-disabled [&>span]:line-clamp-1',\n {\n variants: {\n variant: {\n default:\n 'border border-surface-border-strong bg-surface-raised-hover focus-visible:border-accent-7',\n outline:\n 'border border-surface-border-strong bg-transparent focus-visible:border-accent-7',\n ghost:\n 'border border-transparent bg-transparent hover:bg-surface-raised-hover focus-visible:border-accent-7',\n },\n color: {\n default: '',\n error: 'border-error-7 text-error-11 focus-visible:ring-error-9',\n success: 'border-success-7',\n warning: 'border-warning-7',\n },\n size: {\n xs: 'h-ds-xs-plus text-ds-sm px-ds-02',\n sm: 'h-ds-sm text-ds-sm px-ds-03',\n md: 'h-ds-md text-ds-md px-ds-04',\n lg: 'h-ds-lg text-ds-md px-ds-05',\n },\n },\n defaultVariants: { variant: 'default', color: 'default', size: 'md' },\n },\n)\n\n/**\n * Props for SelectTrigger. Use `size` here (not on the `Select` root).\n *\n * @example\n * <SelectTrigger size=\"lg\" className=\"w-[200px]\">\n * <SelectValue placeholder=\"Select an option\" />\n * </SelectTrigger>\n */\nexport interface SelectTriggerProps\n extends Omit<React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>, 'color'>,\n VariantProps<typeof selectTriggerVariants> {}\n\nconst SelectTrigger = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Trigger>,\n SelectTriggerProps\n>(({ className, children, variant, color, size, ...props }, ref) => {\n const fieldCtx = useFormField()\n const isError =\n color === 'error' ||\n (fieldCtx.state === 'error' && color == null)\n const ariaDescribedBy = props['aria-describedby'] ?? fieldCtx.helperTextId\n const ariaRequired = props['aria-required'] ?? fieldCtx.required\n\n return (\n <SelectPrimitive.Trigger\n ref={ref}\n className={cn(selectTriggerVariants({ variant, color: isError && !color ? 'error' : color, size }), className)}\n aria-invalid={isError || undefined}\n aria-describedby={ariaDescribedBy}\n aria-required={ariaRequired || undefined}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n <Icon icon={IconChevronDown} size=\"sm\" className=\"opacity-50\" />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n )\n})\nSelectTrigger.displayName = SelectPrimitive.Trigger.displayName\n\nconst SelectScrollUpButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollUpButton\n ref={ref}\n className={cn(\n 'flex cursor-default items-center justify-center py-ds-02',\n className,\n )}\n {...props}\n >\n <Icon icon={IconChevronUp} size=\"sm\" />\n </SelectPrimitive.ScrollUpButton>\n))\nSelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName\n\nconst SelectScrollDownButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollDownButton\n ref={ref}\n className={cn(\n 'flex cursor-default items-center justify-center py-ds-02',\n className,\n )}\n {...props}\n >\n <Icon icon={IconChevronDown} size=\"sm\" />\n </SelectPrimitive.ScrollDownButton>\n))\nSelectScrollDownButton.displayName =\n SelectPrimitive.ScrollDownButton.displayName\n\nconst SelectContent = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>\n>(({ className, children, position = 'popper', ...props }, ref) => (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n ref={ref}\n position={position}\n asChild\n {...props}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={{ ...springs.snappy, opacity: tweens.fade }}\n className={cn(\n 'relative z-popover max-h-96 min-w-[8rem] overflow-hidden rounded-overlay border border-surface-border-strong bg-surface-overlay text-surface-fg shadow-floating',\n position === 'popper' &&\n 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',\n className,\n )}\n >\n <SelectScrollUpButton />\n <SelectPrimitive.Viewport\n className={cn(\n 'p-ds-02',\n position === 'popper' &&\n 'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]',\n )}\n >\n {children}\n </SelectPrimitive.Viewport>\n <SelectScrollDownButton />\n </motion.div>\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n))\nSelectContent.displayName = SelectPrimitive.Content.displayName\n\nconst SelectLabel = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.Label\n ref={ref}\n className={cn('px-ds-03 py-ds-02b text-ds-md font-semibold', className)}\n {...props}\n />\n))\nSelectLabel.displayName = SelectPrimitive.Label.displayName\n\nconst SelectItem = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>\n>(({ className, children, ...props }, ref) => (\n <SelectPrimitive.Item\n ref={ref}\n className={cn(\n 'relative flex w-full cursor-default select-none items-center rounded-control py-ds-02b pl-ds-03 pr-ds-07 text-ds-md outline-hidden transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-raised focus:bg-surface-raised focus:text-surface-fg data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled',\n className,\n )}\n {...props}\n >\n <span className=\"absolute right-ds-03 flex h-ico-sm w-ico-sm items-center justify-center\">\n <SelectPrimitive.ItemIndicator>\n <Icon icon={IconCheck} size=\"sm\" />\n </SelectPrimitive.ItemIndicator>\n </span>\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n))\nSelectItem.displayName = SelectPrimitive.Item.displayName\n\nconst SelectSeparator = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.Separator\n ref={ref}\n className={cn('-mx-ds-01 my-ds-02 h-px bg-surface-border', className)}\n {...props}\n />\n))\nSelectSeparator.displayName = SelectPrimitive.Separator.displayName\n\nexport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectScrollDownButton,\n SelectScrollUpButton,\n SelectSeparator,\n SelectTrigger,\n SelectValue,\n}\n"],"mappings":"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"}
package/dist/ui/sheet.js CHANGED
@@ -90,11 +90,11 @@ var O = {
90
90
  children: [
91
91
  d && /* @__PURE__ */ g("div", {
92
92
  className: "flex justify-center pt-ds-03 pb-ds-02",
93
- children: /* @__PURE__ */ g("div", { className: "h-1 w-8 rounded-ds-full bg-surface-border" })
93
+ children: /* @__PURE__ */ g("div", { className: "h-1 w-8 rounded-pill bg-surface-border" })
94
94
  }),
95
95
  /* @__PURE__ */ _(n, {
96
96
  title: "Close",
97
- className: "absolute right-ds-05 top-ds-05 min-h-ds-xs min-w-ds-xs flex items-center justify-center rounded-ds-sm text-surface-fg-subtle transition-colors ease-productive-standard hover:text-surface-fg-muted hover:bg-surface-raised-hover active:scale-90 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 disabled:pointer-events-none",
97
+ className: "absolute right-ds-05 top-ds-05 min-h-ds-xs min-w-ds-xs flex items-center justify-center rounded-control-inner text-surface-fg-subtle transition-colors ease-productive-standard hover:text-surface-fg-muted hover:bg-surface-raised-hover active:scale-90 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 disabled:pointer-events-none",
98
98
  children: [/* @__PURE__ */ g(p, {
99
99
  icon: v,
100
100
  size: "sm"
@@ -1 +1 @@
1
- {"version":3,"file":"sheet.js","names":[],"sources":["../../src/ui/sheet.tsx"],"sourcesContent":["'use client'\n\nimport * as SheetPrimitive from '@primitives/react-dialog'\nimport { IconX } from '@tabler/icons-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { AnimatePresence, motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useIsMobile } from '../hooks/use-mobile'\nimport { Icon } from './icon'\nimport { motionProps,springs, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\n\n// ── Internal open-state context ──────────────────────────────────────\n\nconst SheetOpenContext = React.createContext<{ open: boolean; onClose: () => void }>({ open: false, onClose: () => {} })\n\n/**\n * Sheet compound component — accessible sliding panel anchored to a screen edge, with focus trap\n * and Escape dismissal. Built on the Dialog primitive.\n *\n * **Parts (in composition order):**\n * - `Sheet` — manages open/closed state (this root)\n * - `SheetTrigger` — element that opens the sheet (use `asChild` to render your own button)\n * - `SheetContent` — the sliding panel (use `side=\"right\"|\"left\"|\"top\"|\"bottom\"`, default `\"right\"`)\n * - `SheetHeader` — optional layout wrapper for title + description\n * - `SheetTitle` — required for accessibility (sets the sheet's ARIA label)\n * - `SheetDescription` — optional subtitle text\n * - `SheetFooter` — optional layout wrapper for action buttons\n * - `SheetClose` — manual close trigger (a close button is already built into SheetContent)\n * - `SheetPortal` — low-level portal wrapper (exported for custom layout; used internally by SheetContent)\n * - `SheetOverlay` — the backdrop element (exported for custom overlay styling)\n *\n * @compound\n *\n * Note: The `side` prop goes on `SheetContent`, NOT on `Sheet`.\n * A close button is auto-rendered in the top corner of `SheetContent`.\n *\n * @example\n * // Right-side settings panel (default):\n * <Sheet>\n * <SheetTrigger asChild><Button>Open settings</Button></SheetTrigger>\n * <SheetContent>\n * <SheetHeader>\n * <SheetTitle>Account settings</SheetTitle>\n * <SheetDescription>Manage your profile and preferences.</SheetDescription>\n * </SheetHeader>\n * </SheetContent>\n * </Sheet>\n *\n * @example\n * // Bottom sheet for a mobile-friendly action drawer:\n * <Sheet>\n * <SheetTrigger asChild><Button variant=\"ghost\">More options</Button></SheetTrigger>\n * <SheetContent side=\"bottom\">\n * <SheetTitle>Actions</SheetTitle>\n * <div className=\"flex flex-col gap-ds-03 mt-ds-05\">\n * <Button variant=\"outline\" color=\"error\" fullWidth>Delete item</Button>\n * <Button variant=\"outline\" fullWidth>Duplicate</Button>\n * </div>\n * </SheetContent>\n * </Sheet>\n */\nconst Sheet: React.FC<React.ComponentPropsWithoutRef<typeof SheetPrimitive.Root>> = ({\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n children,\n ...props\n}) => {\n const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen)\n const isControlled = controlledOpen !== undefined\n const open = isControlled ? controlledOpen : uncontrolledOpen\n\n const handleOpenChange = React.useCallback(\n (value: boolean) => {\n if (!isControlled) setUncontrolledOpen(value)\n onOpenChange?.(value)\n },\n [isControlled, onOpenChange],\n )\n\n const contextValue = React.useMemo(\n () => ({ open, onClose: () => handleOpenChange(false) }),\n [open, handleOpenChange],\n )\n\n return (\n <SheetOpenContext.Provider value={contextValue}>\n <SheetPrimitive.Root open={open} onOpenChange={handleOpenChange} {...props}>\n {children}\n </SheetPrimitive.Root>\n </SheetOpenContext.Provider>\n )\n}\nSheet.displayName = 'Sheet'\n\nconst SheetTrigger = SheetPrimitive.Trigger\n\nconst SheetClose = SheetPrimitive.Close\n\nconst SheetPortal = SheetPrimitive.Portal\n\nconst SheetOverlay = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Overlay forceMount asChild>\n <motion.div\n ref={ref}\n className={cn('fixed inset-0 z-modal bg-overlay', className)}\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={tweens.fade}\n {...motionProps(props)}\n />\n </SheetPrimitive.Overlay>\n))\nSheetOverlay.displayName = SheetPrimitive.Overlay.displayName\n\n// ── Slide direction map ──────────────────────────────────────────────\n\nconst slideInitial = {\n top: { y: '-100%' },\n bottom: { y: '100%' },\n left: { x: '-100%' },\n right: { x: '100%' },\n} as const\n\nconst slideAnimate = {\n top: { y: 0 },\n bottom: { y: 0 },\n left: { x: 0 },\n right: { x: 0 },\n} as const\n\nconst sheetVariants = cva(\n 'fixed z-modal gap-ds-05 bg-surface-overlay p-ds-06 shadow-overlay',\n {\n variants: {\n side: {\n top: 'inset-x-0 top-0 border-b border-surface-border-strong',\n bottom: 'inset-x-0 bottom-0 border-t border-surface-border-strong',\n left: 'inset-y-0 left-0 h-full w-3/4 border-r border-surface-border-strong sm:max-w-sm',\n right: 'inset-y-0 right-0 h-full w-3/4 border-l border-surface-border-strong sm:max-w-sm',\n },\n },\n defaultVariants: {\n side: 'right',\n },\n },\n)\n\n/**\n * Props for SheetContent — the sliding panel content that appears from one of four screen edges.\n * Built on the Dialog primitive: accessible, focus-trapped, and dismissible with Escape.\n *\n * **`side` variants:** `right` (default, slide from right) | `left` | `top` | `bottom`\n *\n * **Usage pattern:** Wrap the whole sheet in `<Sheet>`, add a `<SheetTrigger>`, and put content\n * inside `<SheetContent>`. Use `<SheetHeader>`, `<SheetTitle>`, and `<SheetDescription>` for\n * accessible structure. A close button is auto-rendered in the top corner.\n *\n * @example\n * // Right-side settings panel (default):\n * <Sheet>\n * <SheetTrigger asChild><Button>Open settings</Button></SheetTrigger>\n * <SheetContent>\n * <SheetHeader>\n * <SheetTitle>Account settings</SheetTitle>\n * <SheetDescription>Manage your profile and preferences.</SheetDescription>\n * </SheetHeader>\n * </SheetContent>\n * </Sheet>\n *\n * @example\n * // Bottom sheet for a mobile-friendly action drawer:\n * <Sheet>\n * <SheetTrigger asChild><Button variant=\"ghost\">More options</Button></SheetTrigger>\n * <SheetContent side=\"bottom\">\n * <SheetTitle>Actions</SheetTitle>\n * <div className=\"flex flex-col gap-ds-03 mt-ds-05\">\n * <Button variant=\"outline\" color=\"error\" fullWidth>Delete item</Button>\n * <Button variant=\"outline\" fullWidth>Duplicate</Button>\n * </div>\n * </SheetContent>\n * </Sheet>\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface SheetContentProps\n extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,\n VariantProps<typeof sheetVariants> {\n /** When true (default), Sheet slides from bottom on mobile with swipe-to-dismiss. */\n responsive?: boolean\n}\n\nconst SheetContent = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Content>,\n SheetContentProps\n>(({ side = 'right', responsive, className, children, ...props }, ref) => {\n const isMobileRaw = useIsMobile()\n const isMobile = responsive !== false && isMobileRaw\n const isReduced = useReducedMotion()\n const { open, onClose } = React.useContext(SheetOpenContext)\n const effectiveSide = isMobile ? 'bottom' : (side ?? 'right')\n\n const internalRef = React.useRef<HTMLDivElement>(null)\n const composedRef = React.useCallback(\n (node: HTMLDivElement | null) => {\n internalRef.current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node\n },\n [ref],\n )\n\n return (\n <AnimatePresence>\n {open && (\n <SheetPortal forceMount>\n <SheetOverlay />\n <SheetPrimitive.Content forceMount asChild>\n <motion.div\n ref={composedRef}\n className={cn(sheetVariants({ side: effectiveSide }), className)}\n initial={slideInitial[effectiveSide]}\n animate={slideAnimate[effectiveSide]}\n exit={slideInitial[effectiveSide]}\n transition={springs.smooth}\n drag={isMobile && !isReduced ? 'y' : false}\n dragConstraints={{ top: 0 }}\n dragElastic={0.2}\n onDragEnd={\n isMobile\n ? (\n _: unknown,\n info: { offset: { y: number }; velocity: { y: number } },\n ) => {\n const h =\n internalRef.current?.getBoundingClientRect().height ?? 300\n if (info.offset.y > h * 0.3 || info.velocity.y > 500)\n onClose()\n }\n : undefined\n }\n {...motionProps(props)}\n >\n {isMobile && (\n <div className=\"flex justify-center pt-ds-03 pb-ds-02\">\n <div className=\"h-1 w-8 rounded-ds-full bg-surface-border\" />\n </div>\n )}\n <SheetPrimitive.Close title=\"Close\" className=\"absolute right-ds-05 top-ds-05 min-h-ds-xs min-w-ds-xs flex items-center justify-center rounded-ds-sm text-surface-fg-subtle transition-colors ease-productive-standard hover:text-surface-fg-muted hover:bg-surface-raised-hover active:scale-90 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 disabled:pointer-events-none\">\n <Icon icon={IconX} size=\"sm\" />\n <span className=\"sr-only\">Close</span>\n </SheetPrimitive.Close>\n {children}\n </motion.div>\n </SheetPrimitive.Content>\n </SheetPortal>\n )}\n </AnimatePresence>\n )\n})\nSheetContent.displayName = SheetPrimitive.Content.displayName\n\nconst SheetHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col space-y-ds-03 text-center sm:text-left',\n className,\n )}\n {...props}\n />\n ),\n)\nSheetHeader.displayName = 'SheetHeader'\n\nconst SheetFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-ds-03',\n className,\n )}\n {...props}\n />\n ),\n)\nSheetFooter.displayName = 'SheetFooter'\n\nconst SheetTitle = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Title\n ref={ref}\n className={cn('text-ds-lg font-semibold text-surface-fg', className)}\n {...props}\n />\n))\nSheetTitle.displayName = SheetPrimitive.Title.displayName\n\nconst SheetDescription = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Description\n ref={ref}\n className={cn('text-ds-md text-surface-fg-muted', className)}\n {...props}\n />\n))\nSheetDescription.displayName = SheetPrimitive.Description.displayName\n\nexport {\n Sheet,\n SheetClose,\n SheetContent,\n SheetDescription,\n SheetFooter,\n SheetHeader,\n SheetOverlay,\n SheetPortal,\n SheetTitle,\n SheetTrigger,\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sheet.js","names":[],"sources":["../../src/ui/sheet.tsx"],"sourcesContent":["'use client'\n\nimport * as SheetPrimitive from '@primitives/react-dialog'\nimport { IconX } from '@tabler/icons-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { AnimatePresence, motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useIsMobile } from '../hooks/use-mobile'\nimport { Icon } from './icon'\nimport { motionProps,springs, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\n\n// ── Internal open-state context ──────────────────────────────────────\n\nconst SheetOpenContext = React.createContext<{ open: boolean; onClose: () => void }>({ open: false, onClose: () => {} })\n\n/**\n * Sheet compound component — accessible sliding panel anchored to a screen edge, with focus trap\n * and Escape dismissal. Built on the Dialog primitive.\n *\n * **Parts (in composition order):**\n * - `Sheet` — manages open/closed state (this root)\n * - `SheetTrigger` — element that opens the sheet (use `asChild` to render your own button)\n * - `SheetContent` — the sliding panel (use `side=\"right\"|\"left\"|\"top\"|\"bottom\"`, default `\"right\"`)\n * - `SheetHeader` — optional layout wrapper for title + description\n * - `SheetTitle` — required for accessibility (sets the sheet's ARIA label)\n * - `SheetDescription` — optional subtitle text\n * - `SheetFooter` — optional layout wrapper for action buttons\n * - `SheetClose` — manual close trigger (a close button is already built into SheetContent)\n * - `SheetPortal` — low-level portal wrapper (exported for custom layout; used internally by SheetContent)\n * - `SheetOverlay` — the backdrop element (exported for custom overlay styling)\n *\n * @compound\n *\n * Note: The `side` prop goes on `SheetContent`, NOT on `Sheet`.\n * A close button is auto-rendered in the top corner of `SheetContent`.\n *\n * @example\n * // Right-side settings panel (default):\n * <Sheet>\n * <SheetTrigger asChild><Button>Open settings</Button></SheetTrigger>\n * <SheetContent>\n * <SheetHeader>\n * <SheetTitle>Account settings</SheetTitle>\n * <SheetDescription>Manage your profile and preferences.</SheetDescription>\n * </SheetHeader>\n * </SheetContent>\n * </Sheet>\n *\n * @example\n * // Bottom sheet for a mobile-friendly action drawer:\n * <Sheet>\n * <SheetTrigger asChild><Button variant=\"ghost\">More options</Button></SheetTrigger>\n * <SheetContent side=\"bottom\">\n * <SheetTitle>Actions</SheetTitle>\n * <div className=\"flex flex-col gap-ds-03 mt-ds-05\">\n * <Button variant=\"outline\" color=\"error\" fullWidth>Delete item</Button>\n * <Button variant=\"outline\" fullWidth>Duplicate</Button>\n * </div>\n * </SheetContent>\n * </Sheet>\n */\nconst Sheet: React.FC<React.ComponentPropsWithoutRef<typeof SheetPrimitive.Root>> = ({\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n children,\n ...props\n}) => {\n const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen)\n const isControlled = controlledOpen !== undefined\n const open = isControlled ? controlledOpen : uncontrolledOpen\n\n const handleOpenChange = React.useCallback(\n (value: boolean) => {\n if (!isControlled) setUncontrolledOpen(value)\n onOpenChange?.(value)\n },\n [isControlled, onOpenChange],\n )\n\n const contextValue = React.useMemo(\n () => ({ open, onClose: () => handleOpenChange(false) }),\n [open, handleOpenChange],\n )\n\n return (\n <SheetOpenContext.Provider value={contextValue}>\n <SheetPrimitive.Root open={open} onOpenChange={handleOpenChange} {...props}>\n {children}\n </SheetPrimitive.Root>\n </SheetOpenContext.Provider>\n )\n}\nSheet.displayName = 'Sheet'\n\nconst SheetTrigger = SheetPrimitive.Trigger\n\nconst SheetClose = SheetPrimitive.Close\n\nconst SheetPortal = SheetPrimitive.Portal\n\nconst SheetOverlay = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Overlay forceMount asChild>\n <motion.div\n ref={ref}\n className={cn('fixed inset-0 z-modal bg-overlay', className)}\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={tweens.fade}\n {...motionProps(props)}\n />\n </SheetPrimitive.Overlay>\n))\nSheetOverlay.displayName = SheetPrimitive.Overlay.displayName\n\n// ── Slide direction map ──────────────────────────────────────────────\n\nconst slideInitial = {\n top: { y: '-100%' },\n bottom: { y: '100%' },\n left: { x: '-100%' },\n right: { x: '100%' },\n} as const\n\nconst slideAnimate = {\n top: { y: 0 },\n bottom: { y: 0 },\n left: { x: 0 },\n right: { x: 0 },\n} as const\n\nconst sheetVariants = cva(\n 'fixed z-modal gap-ds-05 bg-surface-overlay p-ds-06 shadow-overlay',\n {\n variants: {\n side: {\n top: 'inset-x-0 top-0 border-b border-surface-border-strong',\n bottom: 'inset-x-0 bottom-0 border-t border-surface-border-strong',\n left: 'inset-y-0 left-0 h-full w-3/4 border-r border-surface-border-strong sm:max-w-sm',\n right: 'inset-y-0 right-0 h-full w-3/4 border-l border-surface-border-strong sm:max-w-sm',\n },\n },\n defaultVariants: {\n side: 'right',\n },\n },\n)\n\n/**\n * Props for SheetContent — the sliding panel content that appears from one of four screen edges.\n * Built on the Dialog primitive: accessible, focus-trapped, and dismissible with Escape.\n *\n * **`side` variants:** `right` (default, slide from right) | `left` | `top` | `bottom`\n *\n * **Usage pattern:** Wrap the whole sheet in `<Sheet>`, add a `<SheetTrigger>`, and put content\n * inside `<SheetContent>`. Use `<SheetHeader>`, `<SheetTitle>`, and `<SheetDescription>` for\n * accessible structure. A close button is auto-rendered in the top corner.\n *\n * @example\n * // Right-side settings panel (default):\n * <Sheet>\n * <SheetTrigger asChild><Button>Open settings</Button></SheetTrigger>\n * <SheetContent>\n * <SheetHeader>\n * <SheetTitle>Account settings</SheetTitle>\n * <SheetDescription>Manage your profile and preferences.</SheetDescription>\n * </SheetHeader>\n * </SheetContent>\n * </Sheet>\n *\n * @example\n * // Bottom sheet for a mobile-friendly action drawer:\n * <Sheet>\n * <SheetTrigger asChild><Button variant=\"ghost\">More options</Button></SheetTrigger>\n * <SheetContent side=\"bottom\">\n * <SheetTitle>Actions</SheetTitle>\n * <div className=\"flex flex-col gap-ds-03 mt-ds-05\">\n * <Button variant=\"outline\" color=\"error\" fullWidth>Delete item</Button>\n * <Button variant=\"outline\" fullWidth>Duplicate</Button>\n * </div>\n * </SheetContent>\n * </Sheet>\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface SheetContentProps\n extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,\n VariantProps<typeof sheetVariants> {\n /** When true (default), Sheet slides from bottom on mobile with swipe-to-dismiss. */\n responsive?: boolean\n}\n\nconst SheetContent = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Content>,\n SheetContentProps\n>(({ side = 'right', responsive, className, children, ...props }, ref) => {\n const isMobileRaw = useIsMobile()\n const isMobile = responsive !== false && isMobileRaw\n const isReduced = useReducedMotion()\n const { open, onClose } = React.useContext(SheetOpenContext)\n const effectiveSide = isMobile ? 'bottom' : (side ?? 'right')\n\n const internalRef = React.useRef<HTMLDivElement>(null)\n const composedRef = React.useCallback(\n (node: HTMLDivElement | null) => {\n internalRef.current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node\n },\n [ref],\n )\n\n return (\n <AnimatePresence>\n {open && (\n <SheetPortal forceMount>\n <SheetOverlay />\n <SheetPrimitive.Content forceMount asChild>\n <motion.div\n ref={composedRef}\n className={cn(sheetVariants({ side: effectiveSide }), className)}\n initial={slideInitial[effectiveSide]}\n animate={slideAnimate[effectiveSide]}\n exit={slideInitial[effectiveSide]}\n transition={springs.smooth}\n drag={isMobile && !isReduced ? 'y' : false}\n dragConstraints={{ top: 0 }}\n dragElastic={0.2}\n onDragEnd={\n isMobile\n ? (\n _: unknown,\n info: { offset: { y: number }; velocity: { y: number } },\n ) => {\n const h =\n internalRef.current?.getBoundingClientRect().height ?? 300\n if (info.offset.y > h * 0.3 || info.velocity.y > 500)\n onClose()\n }\n : undefined\n }\n {...motionProps(props)}\n >\n {isMobile && (\n <div className=\"flex justify-center pt-ds-03 pb-ds-02\">\n <div className=\"h-1 w-8 rounded-pill bg-surface-border\" />\n </div>\n )}\n <SheetPrimitive.Close title=\"Close\" className=\"absolute right-ds-05 top-ds-05 min-h-ds-xs min-w-ds-xs flex items-center justify-center rounded-control-inner text-surface-fg-subtle transition-colors ease-productive-standard hover:text-surface-fg-muted hover:bg-surface-raised-hover active:scale-90 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 disabled:pointer-events-none\">\n <Icon icon={IconX} size=\"sm\" />\n <span className=\"sr-only\">Close</span>\n </SheetPrimitive.Close>\n {children}\n </motion.div>\n </SheetPrimitive.Content>\n </SheetPortal>\n )}\n </AnimatePresence>\n )\n})\nSheetContent.displayName = SheetPrimitive.Content.displayName\n\nconst SheetHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col space-y-ds-03 text-center sm:text-left',\n className,\n )}\n {...props}\n />\n ),\n)\nSheetHeader.displayName = 'SheetHeader'\n\nconst SheetFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-ds-03',\n className,\n )}\n {...props}\n />\n ),\n)\nSheetFooter.displayName = 'SheetFooter'\n\nconst SheetTitle = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Title\n ref={ref}\n className={cn('text-ds-lg font-semibold text-surface-fg', className)}\n {...props}\n />\n))\nSheetTitle.displayName = SheetPrimitive.Title.displayName\n\nconst SheetDescription = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Description\n ref={ref}\n className={cn('text-ds-md text-surface-fg-muted', className)}\n {...props}\n />\n))\nSheetDescription.displayName = SheetPrimitive.Description.displayName\n\nexport {\n Sheet,\n SheetClose,\n SheetContent,\n SheetDescription,\n SheetFooter,\n SheetHeader,\n SheetOverlay,\n SheetPortal,\n SheetTitle,\n SheetTrigger,\n}\n"],"mappings":"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"}