@craftzbay/ui 0.8.1 → 0.10.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 (172) hide show
  1. package/README.md +72 -6
  2. package/dist-lib/components/ui/Accordion.js +60 -0
  3. package/dist-lib/components/ui/Accordion.js.map +1 -0
  4. package/dist-lib/components/ui/Alert.d.ts +1 -1
  5. package/dist-lib/components/ui/Alert.js +66 -0
  6. package/dist-lib/components/ui/Alert.js.map +1 -0
  7. package/dist-lib/components/ui/Avatar.d.ts +2 -2
  8. package/dist-lib/components/ui/Avatar.js +96 -0
  9. package/dist-lib/components/ui/Avatar.js.map +1 -0
  10. package/dist-lib/components/ui/Badge.d.ts +1 -1
  11. package/dist-lib/components/ui/Badge.js +67 -0
  12. package/dist-lib/components/ui/Badge.js.map +1 -0
  13. package/dist-lib/components/ui/Breadcrumbs.js +34 -0
  14. package/dist-lib/components/ui/Breadcrumbs.js.map +1 -0
  15. package/dist-lib/components/ui/Button.d.ts +1 -1
  16. package/dist-lib/components/ui/Button.js +117 -0
  17. package/dist-lib/components/ui/Button.js.map +1 -0
  18. package/dist-lib/components/ui/Calendar.d.ts +7 -1
  19. package/dist-lib/components/ui/Calendar.js +111 -0
  20. package/dist-lib/components/ui/Calendar.js.map +1 -0
  21. package/dist-lib/components/ui/Card.d.ts +1 -1
  22. package/dist-lib/components/ui/Card.js +116 -0
  23. package/dist-lib/components/ui/Card.js.map +1 -0
  24. package/dist-lib/components/ui/Carousel.d.ts +5 -1
  25. package/dist-lib/components/ui/Carousel.js +143 -0
  26. package/dist-lib/components/ui/Carousel.js.map +1 -0
  27. package/dist-lib/components/ui/Chart.d.ts +26 -4
  28. package/dist-lib/components/ui/Chart.js +253 -0
  29. package/dist-lib/components/ui/Chart.js.map +1 -0
  30. package/dist-lib/components/ui/Checkbox.js +56 -0
  31. package/dist-lib/components/ui/Checkbox.js.map +1 -0
  32. package/dist-lib/components/ui/Combobox.d.ts +7 -0
  33. package/dist-lib/components/ui/Combobox.js +164 -0
  34. package/dist-lib/components/ui/Combobox.js.map +1 -0
  35. package/dist-lib/components/ui/CommandPalette.d.ts +3 -3
  36. package/dist-lib/components/ui/CommandPalette.js +174 -0
  37. package/dist-lib/components/ui/CommandPalette.js.map +1 -0
  38. package/dist-lib/components/ui/ContextMenu.js +150 -0
  39. package/dist-lib/components/ui/ContextMenu.js.map +1 -0
  40. package/dist-lib/components/ui/DataGrid.js +84 -0
  41. package/dist-lib/components/ui/DataGrid.js.map +1 -0
  42. package/dist-lib/components/ui/DatePicker.d.ts +16 -13
  43. package/dist-lib/components/ui/DatePicker.js +174 -0
  44. package/dist-lib/components/ui/DatePicker.js.map +1 -0
  45. package/dist-lib/components/ui/DesignSystemProvider.d.ts +8 -1
  46. package/dist-lib/components/ui/DesignSystemProvider.js +79 -0
  47. package/dist-lib/components/ui/DesignSystemProvider.js.map +1 -0
  48. package/dist-lib/components/ui/Dialog.d.ts +1 -1
  49. package/dist-lib/components/ui/Dialog.js +140 -0
  50. package/dist-lib/components/ui/Dialog.js.map +1 -0
  51. package/dist-lib/components/ui/Drawer.d.ts +6 -0
  52. package/dist-lib/components/ui/Drawer.js +98 -0
  53. package/dist-lib/components/ui/Drawer.js.map +1 -0
  54. package/dist-lib/components/ui/DropdownMenu.js +164 -0
  55. package/dist-lib/components/ui/DropdownMenu.js.map +1 -0
  56. package/dist-lib/components/ui/EmptyState.js +32 -0
  57. package/dist-lib/components/ui/EmptyState.js.map +1 -0
  58. package/dist-lib/components/ui/ErrorState.js +48 -0
  59. package/dist-lib/components/ui/ErrorState.js.map +1 -0
  60. package/dist-lib/components/ui/FileUpload.d.ts +3 -0
  61. package/dist-lib/components/ui/FileUpload.js +108 -0
  62. package/dist-lib/components/ui/FileUpload.js.map +1 -0
  63. package/dist-lib/components/ui/Form.d.ts +1 -0
  64. package/dist-lib/components/ui/Form.js +105 -0
  65. package/dist-lib/components/ui/Form.js.map +1 -0
  66. package/dist-lib/components/ui/Icon.d.ts +34 -0
  67. package/dist-lib/components/ui/Icon.js +26 -0
  68. package/dist-lib/components/ui/Icon.js.map +1 -0
  69. package/dist-lib/components/ui/IconButton.d.ts +1 -1
  70. package/dist-lib/components/ui/IconButton.js +56 -0
  71. package/dist-lib/components/ui/IconButton.js.map +1 -0
  72. package/dist-lib/components/ui/Input.d.ts +6 -3
  73. package/dist-lib/components/ui/Input.js +135 -0
  74. package/dist-lib/components/ui/Input.js.map +1 -0
  75. package/dist-lib/components/ui/Kbd.js +24 -0
  76. package/dist-lib/components/ui/Kbd.js.map +1 -0
  77. package/dist-lib/components/ui/MultiSelect.d.ts +3 -1
  78. package/dist-lib/components/ui/MultiSelect.js +196 -0
  79. package/dist-lib/components/ui/MultiSelect.js.map +1 -0
  80. package/dist-lib/components/ui/Pagination.d.ts +23 -0
  81. package/dist-lib/components/ui/Pagination.js +148 -0
  82. package/dist-lib/components/ui/Pagination.js.map +1 -0
  83. package/dist-lib/components/ui/Popover.js +35 -0
  84. package/dist-lib/components/ui/Popover.js.map +1 -0
  85. package/dist-lib/components/ui/Progress.js +95 -0
  86. package/dist-lib/components/ui/Progress.js.map +1 -0
  87. package/dist-lib/components/ui/RadioGroup.js +64 -0
  88. package/dist-lib/components/ui/RadioGroup.js.map +1 -0
  89. package/dist-lib/components/ui/ScrollArea.js +44 -0
  90. package/dist-lib/components/ui/ScrollArea.js.map +1 -0
  91. package/dist-lib/components/ui/Select.js +131 -0
  92. package/dist-lib/components/ui/Select.js.map +1 -0
  93. package/dist-lib/components/ui/Separator.js +26 -0
  94. package/dist-lib/components/ui/Separator.js.map +1 -0
  95. package/dist-lib/components/ui/Sheet.d.ts +1 -1
  96. package/dist-lib/components/ui/Sheet.js +113 -0
  97. package/dist-lib/components/ui/Sheet.js.map +1 -0
  98. package/dist-lib/components/ui/Sidebar.d.ts +18 -6
  99. package/dist-lib/components/ui/Sidebar.js +169 -0
  100. package/dist-lib/components/ui/Sidebar.js.map +1 -0
  101. package/dist-lib/components/ui/Skeleton.js +28 -0
  102. package/dist-lib/components/ui/Skeleton.js.map +1 -0
  103. package/dist-lib/components/ui/Slider.js +52 -0
  104. package/dist-lib/components/ui/Slider.js.map +1 -0
  105. package/dist-lib/components/ui/Snackbar.d.ts +1 -1
  106. package/dist-lib/components/ui/Snackbar.js +56 -0
  107. package/dist-lib/components/ui/Snackbar.js.map +1 -0
  108. package/dist-lib/components/ui/Spinner.js +42 -0
  109. package/dist-lib/components/ui/Spinner.js.map +1 -0
  110. package/dist-lib/components/ui/Stepper.js +88 -0
  111. package/dist-lib/components/ui/Stepper.js.map +1 -0
  112. package/dist-lib/components/ui/Switch.js +77 -0
  113. package/dist-lib/components/ui/Switch.js.map +1 -0
  114. package/dist-lib/components/ui/Table.d.ts +9 -1
  115. package/dist-lib/components/ui/Table.js +157 -0
  116. package/dist-lib/components/ui/Table.js.map +1 -0
  117. package/dist-lib/components/ui/Tabs.d.ts +1 -1
  118. package/dist-lib/components/ui/Tabs.js +89 -0
  119. package/dist-lib/components/ui/Tabs.js.map +1 -0
  120. package/dist-lib/components/ui/TagInput.d.ts +17 -2
  121. package/dist-lib/components/ui/TagInput.js +111 -0
  122. package/dist-lib/components/ui/TagInput.js.map +1 -0
  123. package/dist-lib/components/ui/Textarea.js +77 -0
  124. package/dist-lib/components/ui/Textarea.js.map +1 -0
  125. package/dist-lib/components/ui/Timeline.d.ts +16 -6
  126. package/dist-lib/components/ui/Timeline.js +52 -0
  127. package/dist-lib/components/ui/Timeline.js.map +1 -0
  128. package/dist-lib/components/ui/Toast.d.ts +1 -1
  129. package/dist-lib/components/ui/Toast.js +171 -0
  130. package/dist-lib/components/ui/Toast.js.map +1 -0
  131. package/dist-lib/components/ui/Tooltip.js +58 -0
  132. package/dist-lib/components/ui/Tooltip.js.map +1 -0
  133. package/dist-lib/components/ui/TopNav.js +52 -0
  134. package/dist-lib/components/ui/TopNav.js.map +1 -0
  135. package/dist-lib/components/ui/Tree.d.ts +27 -5
  136. package/dist-lib/components/ui/Tree.js +167 -0
  137. package/dist-lib/components/ui/Tree.js.map +1 -0
  138. package/dist-lib/hooks/use-field-ids.d.ts +29 -0
  139. package/dist-lib/hooks/use-field-ids.js +18 -0
  140. package/dist-lib/hooks/use-field-ids.js.map +1 -0
  141. package/dist-lib/hooks/use-media-query.js +18 -0
  142. package/dist-lib/hooks/use-media-query.js.map +1 -0
  143. package/dist-lib/hooks/use-strings.d.ts +5 -0
  144. package/dist-lib/hooks/use-strings.js +12 -0
  145. package/dist-lib/hooks/use-strings.js.map +1 -0
  146. package/dist-lib/hooks/use-toast.js +36 -0
  147. package/dist-lib/hooks/use-toast.js.map +1 -0
  148. package/dist-lib/icon.d.ts +8 -0
  149. package/dist-lib/icon.js +7 -0
  150. package/dist-lib/icon.js.map +1 -0
  151. package/dist-lib/icons/index.d.ts +71 -11
  152. package/dist-lib/icons/index.js +145 -0
  153. package/dist-lib/icons/index.js.map +1 -0
  154. package/dist-lib/illustrations/index.js +105 -0
  155. package/dist-lib/illustrations/index.js.map +1 -0
  156. package/dist-lib/index.d.ts +62 -58
  157. package/dist-lib/index.js +268 -4386
  158. package/dist-lib/index.js.map +1 -1
  159. package/dist-lib/lib/strings.d.ts +129 -0
  160. package/dist-lib/lib/strings.js +85 -0
  161. package/dist-lib/lib/strings.js.map +1 -0
  162. package/dist-lib/lib/strings.mn.d.ts +3 -0
  163. package/dist-lib/lib/strings.mn.js +70 -0
  164. package/dist-lib/lib/strings.mn.js.map +1 -0
  165. package/dist-lib/lib/utils.d.ts +0 -1
  166. package/dist-lib/lib/utils.js +10 -0
  167. package/dist-lib/lib/utils.js.map +1 -0
  168. package/dist-lib/styles.css +1 -1
  169. package/dist-lib/theme.css +777 -0
  170. package/package.json +31 -8
  171. package/dist-lib/index.cjs +0 -8
  172. package/dist-lib/index.cjs.map +0 -1
@@ -0,0 +1,26 @@
1
+ "use client";
2
+ import { jsx as p } from "react/jsx-runtime";
3
+ import { forwardRef as i } from "react";
4
+ import * as m from "@radix-ui/react-separator";
5
+ import { cn as f } from "../../lib/utils.js";
6
+ const l = i(function({ className: o, orientation: r = "horizontal", decorative: t = !0, ...a }, e) {
7
+ return /* @__PURE__ */ p(
8
+ m.Root,
9
+ {
10
+ ref: e,
11
+ orientation: r,
12
+ decorative: t,
13
+ className: f(
14
+ "shrink-0 bg-border",
15
+ r === "horizontal" ? "h-px w-full" : "h-full w-px",
16
+ o
17
+ ),
18
+ ...a
19
+ }
20
+ );
21
+ });
22
+ l.displayName = "Separator";
23
+ export {
24
+ l as Separator
25
+ };
26
+ //# sourceMappingURL=Separator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Separator.js","sources":["../../../src/components/ui/Separator.tsx"],"sourcesContent":["'use client';\n\nimport {\n forwardRef,\n type ComponentPropsWithoutRef,\n type ElementRef,\n} from 'react';\nimport * as SeparatorPrimitive from '@radix-ui/react-separator';\nimport { cn } from '@/lib/utils';\n\n/**\n * Hairline divider. Decorative by default (no role announced). Pass\n * `decorative={false}` when the separator carries semantic meaning, e.g.\n * splitting two regions in a landmark.\n *\n * @example Section divider\n * <Separator className=\"my-6\" />\n *\n * @example Vertical inside a toolbar\n * <Separator orientation=\"vertical\" className=\"h-5 mx-2\" />\n */\nexport const Separator = forwardRef<\n ElementRef<typeof SeparatorPrimitive.Root>,\n ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>\n>(function Separator(\n { className, orientation = 'horizontal', decorative = true, ...props },\n ref,\n) {\n return (\n <SeparatorPrimitive.Root\n ref={ref}\n orientation={orientation}\n decorative={decorative}\n className={cn(\n 'shrink-0 bg-border',\n orientation === 'horizontal' ? 'h-px w-full' : 'h-full w-px',\n className,\n )}\n {...props}\n />\n );\n});\nSeparator.displayName = 'Separator';\n"],"names":["Separator","forwardRef","className","orientation","decorative","props","ref","jsx","SeparatorPrimitive","cn"],"mappings":";;;;;AAqBO,MAAMA,IAAYC,EAGvB,SACA,EAAE,WAAAC,GAAW,aAAAC,IAAc,cAAc,YAAAC,IAAa,IAAM,GAAGC,EAAA,GAC/DC,GACA;AACA,SACE,gBAAAC;AAAA,IAACC,EAAmB;AAAA,IAAnB;AAAA,MACC,KAAAF;AAAA,MACA,aAAAH;AAAA,MACA,YAAAC;AAAA,MACA,WAAWK;AAAA,QACT;AAAA,QACAN,MAAgB,eAAe,gBAAgB;AAAA,QAC/CD;AAAA,MAAA;AAAA,MAED,GAAGG;AAAA,IAAA;AAAA,EAAA;AAGV,CAAC;AACDL,EAAU,cAAc;"}
@@ -1,5 +1,5 @@
1
1
  import { ComponentPropsWithoutRef, HTMLAttributes } from 'react';
2
- import { VariantProps } from '../../lib/cva';
2
+ import { VariantProps } from '../../lib/cva.js';
3
3
  import * as DialogPrimitive from '@radix-ui/react-dialog';
4
4
  export declare const Sheet: import('react').FC<DialogPrimitive.DialogProps>;
5
5
  export declare const SheetTrigger: import('react').ForwardRefExoticComponent<DialogPrimitive.DialogTriggerProps & import('react').RefAttributes<HTMLButtonElement>>;
@@ -0,0 +1,113 @@
1
+ "use client";
2
+ import { jsxs as d, jsx as o } from "react/jsx-runtime";
3
+ import { forwardRef as n } from "react";
4
+ import * as t from "@radix-ui/react-dialog";
5
+ import { X as h } from "../../icons/index.js";
6
+ import { cn as i } from "../../lib/utils.js";
7
+ import { useStrings as p } from "../../hooks/use-strings.js";
8
+ import { cva as g } from "class-variance-authority";
9
+ const P = t.Root, F = t.Trigger, H = t.Close, b = t.Portal, l = n(function({ className: e, ...r }, s) {
10
+ return /* @__PURE__ */ o(
11
+ t.Overlay,
12
+ {
13
+ ref: s,
14
+ className: i(
15
+ "fixed inset-0 z-[var(--z-overlay)] bg-overlay",
16
+ "data-[state=open]:animate-in data-[state=closed]:animate-out",
17
+ "data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0",
18
+ e
19
+ ),
20
+ ...r
21
+ }
22
+ );
23
+ });
24
+ l.displayName = "SheetOverlay";
25
+ const x = g(
26
+ [
27
+ "fixed z-[var(--z-modal)] bg-card text-card-foreground shadow-lg",
28
+ "flex flex-col gap-4 p-6",
29
+ "data-[state=open]:animate-in data-[state=closed]:animate-out",
30
+ "data-[state=closed]:duration-[var(--duration-base)] data-[state=open]:duration-[var(--duration-slow)]"
31
+ ],
32
+ {
33
+ variants: {
34
+ side: {
35
+ top: "inset-x-0 top-0 border-b border-border data-[state=open]:slide-in-from-top data-[state=closed]:slide-out-to-top",
36
+ bottom: "inset-x-0 bottom-0 border-t border-border data-[state=open]:slide-in-from-bottom data-[state=closed]:slide-out-to-bottom",
37
+ left: "inset-y-0 left-0 h-full w-3/4 max-w-md border-r border-border data-[state=open]:slide-in-from-left data-[state=closed]:slide-out-to-left",
38
+ right: "inset-y-0 right-0 h-full w-3/4 max-w-md border-l border-border data-[state=open]:slide-in-from-right data-[state=closed]:slide-out-to-right"
39
+ }
40
+ },
41
+ defaultVariants: { side: "right" }
42
+ }
43
+ ), v = n(function({ className: e, children: r, side: s = "right", showClose: c = !0, ...f }, m) {
44
+ const u = p();
45
+ return /* @__PURE__ */ d(b, { children: [
46
+ /* @__PURE__ */ o(l, {}),
47
+ /* @__PURE__ */ d(t.Content, { ref: m, className: i(x({ side: s }), e), ...f, children: [
48
+ r,
49
+ c && /* @__PURE__ */ o(
50
+ t.Close,
51
+ {
52
+ "aria-label": u.sheet.close,
53
+ className: i(
54
+ "absolute right-4 top-4 inline-flex size-8 items-center justify-center rounded-md text-foreground-subtle",
55
+ "hover:bg-background-muted hover:text-foreground",
56
+ "outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card",
57
+ "transition-colors duration-[var(--duration-fast)]"
58
+ ),
59
+ children: /* @__PURE__ */ o(h, { className: "size-4", "aria-hidden": !0 })
60
+ }
61
+ )
62
+ ] })
63
+ ] });
64
+ });
65
+ v.displayName = "SheetContent";
66
+ function S({ className: a, ...e }) {
67
+ return /* @__PURE__ */ o("div", { className: i("flex flex-col gap-1", a), ...e });
68
+ }
69
+ S.displayName = "SheetHeader";
70
+ function y({ className: a, ...e }) {
71
+ return /* @__PURE__ */ o(
72
+ "div",
73
+ {
74
+ className: i("mt-auto flex flex-col-reverse gap-2 pt-4 sm:flex-row sm:justify-end", a),
75
+ ...e
76
+ }
77
+ );
78
+ }
79
+ y.displayName = "SheetFooter";
80
+ const N = n(function({ className: e, ...r }, s) {
81
+ return /* @__PURE__ */ o(
82
+ t.Title,
83
+ {
84
+ ref: s,
85
+ className: i("text-lg font-semibold text-foreground leading-tight", e),
86
+ ...r
87
+ }
88
+ );
89
+ });
90
+ N.displayName = "SheetTitle";
91
+ const w = n(function({ className: e, ...r }, s) {
92
+ return /* @__PURE__ */ o(
93
+ t.Description,
94
+ {
95
+ ref: s,
96
+ className: i("text-sm text-foreground-muted", e),
97
+ ...r
98
+ }
99
+ );
100
+ });
101
+ w.displayName = "SheetDescription";
102
+ export {
103
+ P as Sheet,
104
+ H as SheetClose,
105
+ v as SheetContent,
106
+ w as SheetDescription,
107
+ y as SheetFooter,
108
+ S as SheetHeader,
109
+ b as SheetPortal,
110
+ N as SheetTitle,
111
+ F as SheetTrigger
112
+ };
113
+ //# sourceMappingURL=Sheet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Sheet.js","sources":["../../../src/components/ui/Sheet.tsx"],"sourcesContent":["'use client';\n\nimport {\n forwardRef,\n type ComponentPropsWithoutRef,\n type ElementRef,\n type HTMLAttributes,\n} from 'react';\nimport * as DialogPrimitive from '@radix-ui/react-dialog';\nimport { X } from '@/icons';\nimport { cn } from '@/lib/utils';\nimport { useStrings } from '@/hooks/use-strings';\nimport { cva, type VariantProps } from '@/lib/cva';\n\n/* -----------------------------------------------------------------------------\n * Sheet — drawer-style overlay. Built on Radix Dialog (focus trap, escape,\n * click-outside come from there). Slides in from one of four sides.\n * --------------------------------------------------------------------------- */\n\nexport const Sheet = DialogPrimitive.Root;\nexport const SheetTrigger = DialogPrimitive.Trigger;\nexport const SheetClose = DialogPrimitive.Close;\nexport const SheetPortal = DialogPrimitive.Portal;\n\nconst SheetOverlay = forwardRef<\n ElementRef<typeof DialogPrimitive.Overlay>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(function SheetOverlay({ className, ...props }, ref) {\n return (\n <DialogPrimitive.Overlay\n ref={ref}\n className={cn(\n 'fixed inset-0 z-[var(--z-overlay)] bg-overlay',\n 'data-[state=open]:animate-in data-[state=closed]:animate-out',\n 'data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0',\n className,\n )}\n {...props}\n />\n );\n});\nSheetOverlay.displayName = 'SheetOverlay';\n\nconst sheet = cva(\n [\n 'fixed z-[var(--z-modal)] bg-card text-card-foreground shadow-lg',\n 'flex flex-col gap-4 p-6',\n 'data-[state=open]:animate-in data-[state=closed]:animate-out',\n 'data-[state=closed]:duration-[var(--duration-base)] data-[state=open]:duration-[var(--duration-slow)]',\n ],\n {\n variants: {\n side: {\n top: 'inset-x-0 top-0 border-b border-border data-[state=open]:slide-in-from-top data-[state=closed]:slide-out-to-top',\n bottom:\n 'inset-x-0 bottom-0 border-t border-border data-[state=open]:slide-in-from-bottom data-[state=closed]:slide-out-to-bottom',\n left: 'inset-y-0 left-0 h-full w-3/4 max-w-md border-r border-border data-[state=open]:slide-in-from-left data-[state=closed]:slide-out-to-left',\n right:\n 'inset-y-0 right-0 h-full w-3/4 max-w-md border-l border-border data-[state=open]:slide-in-from-right data-[state=closed]:slide-out-to-right',\n },\n },\n defaultVariants: { side: 'right' },\n },\n);\n\nexport interface SheetContentProps\n extends ComponentPropsWithoutRef<typeof DialogPrimitive.Content>,\n VariantProps<typeof sheet> {\n showClose?: boolean;\n}\n\nexport const SheetContent = forwardRef<\n ElementRef<typeof DialogPrimitive.Content>,\n SheetContentProps\n>(function SheetContent({ className, children, side = 'right', showClose = true, ...props }, ref) {\n const strings = useStrings();\n return (\n <SheetPortal>\n <SheetOverlay />\n <DialogPrimitive.Content ref={ref} className={cn(sheet({ side }), className)} {...props}>\n {children}\n {showClose && (\n <DialogPrimitive.Close\n aria-label={strings.sheet.close}\n className={cn(\n 'absolute right-4 top-4 inline-flex size-8 items-center justify-center rounded-md text-foreground-subtle',\n 'hover:bg-background-muted hover:text-foreground',\n 'outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card',\n 'transition-colors duration-[var(--duration-fast)]',\n )}\n >\n <X className=\"size-4\" aria-hidden />\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Content>\n </SheetPortal>\n );\n});\nSheetContent.displayName = 'SheetContent';\n\nexport function SheetHeader({ className, ...props }: HTMLAttributes<HTMLDivElement>) {\n return <div className={cn('flex flex-col gap-1', className)} {...props} />;\n}\nSheetHeader.displayName = 'SheetHeader';\n\nexport function SheetFooter({ className, ...props }: HTMLAttributes<HTMLDivElement>) {\n return (\n <div\n className={cn('mt-auto flex flex-col-reverse gap-2 pt-4 sm:flex-row sm:justify-end', className)}\n {...props}\n />\n );\n}\nSheetFooter.displayName = 'SheetFooter';\n\nexport const SheetTitle = forwardRef<\n ElementRef<typeof DialogPrimitive.Title>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n>(function SheetTitle({ className, ...props }, ref) {\n return (\n <DialogPrimitive.Title\n ref={ref}\n className={cn('text-lg font-semibold text-foreground leading-tight', className)}\n {...props}\n />\n );\n});\nSheetTitle.displayName = 'SheetTitle';\n\nexport const SheetDescription = forwardRef<\n ElementRef<typeof DialogPrimitive.Description>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(function SheetDescription({ className, ...props }, ref) {\n return (\n <DialogPrimitive.Description\n ref={ref}\n className={cn('text-sm text-foreground-muted', className)}\n {...props}\n />\n );\n});\nSheetDescription.displayName = 'SheetDescription';\n\n/**\n * @example Right-side filter drawer\n * <Sheet>\n * <SheetTrigger asChild><Button variant=\"outline\">Filters</Button></SheetTrigger>\n * <SheetContent side=\"right\">\n * <SheetHeader>\n * <SheetTitle>Filters</SheetTitle>\n * <SheetDescription>Refine the result set.</SheetDescription>\n * </SheetHeader>\n * …\n * <SheetFooter>\n * <SheetClose asChild><Button variant=\"outline\">Cancel</Button></SheetClose>\n * <Button>Apply</Button>\n * </SheetFooter>\n * </SheetContent>\n * </Sheet>\n *\n * @do Use right side for filters/inspectors, left for navigation, bottom for\n * mobile sheets.\n * @dont Use a full-screen sheet on desktop — prefer Dialog or a dedicated page.\n */\n"],"names":["Sheet","DialogPrimitive","SheetTrigger","SheetClose","SheetPortal","SheetOverlay","forwardRef","className","props","ref","jsx","cn","sheet","cva","SheetContent","children","side","showClose","strings","useStrings","jsxs","X","SheetHeader","SheetFooter","SheetTitle","SheetDescription"],"mappings":";;;;;;;;AAmBO,MAAMA,IAAQC,EAAgB,MACxBC,IAAeD,EAAgB,SAC/BE,IAAaF,EAAgB,OAC7BG,IAAcH,EAAgB,QAErCI,IAAeC,EAGnB,SAAsB,EAAE,WAAAC,GAAW,GAAGC,EAAA,GAASC,GAAK;AACpD,SACE,gBAAAC;AAAA,IAACT,EAAgB;AAAA,IAAhB;AAAA,MACC,KAAAQ;AAAA,MACA,WAAWE;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACAJ;AAAA,MAAA;AAAA,MAED,GAAGC;AAAA,IAAA;AAAA,EAAA;AAGV,CAAC;AACDH,EAAa,cAAc;AAE3B,MAAMO,IAAQC;AAAA,EACZ;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAAA,EAEF;AAAA,IACE,UAAU;AAAA,MACR,MAAM;AAAA,QACJ,KAAK;AAAA,QACL,QACE;AAAA,QACF,MAAM;AAAA,QACN,OACE;AAAA,MAAA;AAAA,IACJ;AAAA,IAEF,iBAAiB,EAAE,MAAM,QAAA;AAAA,EAAQ;AAErC,GAQaC,IAAeR,EAG1B,SAAsB,EAAE,WAAAC,GAAW,UAAAQ,GAAU,MAAAC,IAAO,SAAS,WAAAC,IAAY,IAAM,GAAGT,EAAA,GAASC,GAAK;AAChG,QAAMS,IAAUC,EAAA;AAChB,2BACGf,GAAA,EACC,UAAA;AAAA,IAAA,gBAAAM,EAACL,GAAA,EAAa;AAAA,IACd,gBAAAe,EAACnB,EAAgB,SAAhB,EAAwB,KAAAQ,GAAU,WAAWE,EAAGC,EAAM,EAAE,MAAAI,GAAM,GAAGT,CAAS,GAAI,GAAGC,GAC/E,UAAA;AAAA,MAAAO;AAAA,MACAE,KACC,gBAAAP;AAAA,QAACT,EAAgB;AAAA,QAAhB;AAAA,UACC,cAAYiB,EAAQ,MAAM;AAAA,UAC1B,WAAWP;AAAA,YACT;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UAAA;AAAA,UAGF,UAAA,gBAAAD,EAACW,GAAA,EAAE,WAAU,UAAS,eAAW,GAAA,CAAC;AAAA,QAAA;AAAA,MAAA;AAAA,IACpC,EAAA,CAEJ;AAAA,EAAA,GACF;AAEJ,CAAC;AACDP,EAAa,cAAc;AAEpB,SAASQ,EAAY,EAAE,WAAAf,GAAW,GAAGC,KAAyC;AACnF,SAAO,gBAAAE,EAAC,SAAI,WAAWC,EAAG,uBAAuBJ,CAAS,GAAI,GAAGC,GAAO;AAC1E;AACAc,EAAY,cAAc;AAEnB,SAASC,EAAY,EAAE,WAAAhB,GAAW,GAAGC,KAAyC;AACnF,SACE,gBAAAE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWC,EAAG,uEAAuEJ,CAAS;AAAA,MAC7F,GAAGC;AAAA,IAAA;AAAA,EAAA;AAGV;AACAe,EAAY,cAAc;AAEnB,MAAMC,IAAalB,EAGxB,SAAoB,EAAE,WAAAC,GAAW,GAAGC,EAAA,GAASC,GAAK;AAClD,SACE,gBAAAC;AAAA,IAACT,EAAgB;AAAA,IAAhB;AAAA,MACC,KAAAQ;AAAA,MACA,WAAWE,EAAG,uDAAuDJ,CAAS;AAAA,MAC7E,GAAGC;AAAA,IAAA;AAAA,EAAA;AAGV,CAAC;AACDgB,EAAW,cAAc;AAElB,MAAMC,IAAmBnB,EAG9B,SAA0B,EAAE,WAAAC,GAAW,GAAGC,EAAA,GAASC,GAAK;AACxD,SACE,gBAAAC;AAAA,IAACT,EAAgB;AAAA,IAAhB;AAAA,MACC,KAAAQ;AAAA,MACA,WAAWE,EAAG,iCAAiCJ,CAAS;AAAA,MACvD,GAAGC;AAAA,IAAA;AAAA,EAAA;AAGV,CAAC;AACDiB,EAAiB,cAAc;"}
@@ -1,4 +1,4 @@
1
- import { HTMLAttributes, ReactNode } from 'react';
1
+ import { AnchorHTMLAttributes, ButtonHTMLAttributes, HTMLAttributes, ReactNode } from 'react';
2
2
  interface SidebarContextValue {
3
3
  collapsed: boolean;
4
4
  }
@@ -20,6 +20,7 @@ export interface SidebarProps extends HTMLAttributes<HTMLElement> {
20
20
  /**
21
21
  * App-level navigation rail. Holds `SidebarSection` → `SidebarItem` lists,
22
22
  * and optionally a `footer`. Supports collapse to icon-only on desktop.
23
+ * Below `md` the rail is hidden — pair it with a Sheet / Drawer for mobile.
23
24
  *
24
25
  * @example
25
26
  * <Sidebar footer={<UserCard />}>
@@ -45,20 +46,31 @@ export declare function SidebarSection({ label, className, children, ...props }:
45
46
  export declare namespace SidebarSection {
46
47
  var displayName: string;
47
48
  }
48
- export interface SidebarItemProps extends HTMLAttributes<HTMLAnchorElement> {
49
+ interface SidebarItemBaseProps {
49
50
  /** Lucide icon shown to the left. */
50
51
  icon?: ReactNode;
51
52
  /** Mark as the current page. */
52
53
  active?: boolean;
53
- /** Optional `href` — when absent, renders as a `<button>` so consumers can
54
- * bind their own handler / routing wrapper via `onClick`. */
55
- href?: string;
56
54
  /** Trailing badge / counter slot. */
57
55
  trailing?: ReactNode;
58
56
  /** Render a sub-item indented under a parent. */
59
57
  sub?: boolean;
58
+ /**
59
+ * Tooltip text shown while the sidebar is collapsed. Defaults to `children`
60
+ * when that is a plain string.
61
+ */
62
+ tooltip?: ReactNode;
60
63
  }
61
- export declare function SidebarItem({ icon, active, href, trailing, sub, className, children, ...props }: SidebarItemProps): import("react/jsx-runtime").JSX.Element;
64
+ type SidebarItemAnchorProps = SidebarItemBaseProps & AnchorHTMLAttributes<HTMLAnchorElement> & {
65
+ /** Renders an `<a>`. Omit to render a `<button>`. */
66
+ href: string;
67
+ };
68
+ type SidebarItemButtonProps = SidebarItemBaseProps & ButtonHTMLAttributes<HTMLButtonElement> & {
69
+ href?: undefined;
70
+ };
71
+ /** Discriminated on `href`: with it the item is an anchor, without it a button. */
72
+ export type SidebarItemProps = SidebarItemAnchorProps | SidebarItemButtonProps;
73
+ export declare function SidebarItem(props: SidebarItemProps): import("react/jsx-runtime").JSX.Element;
62
74
  export declare namespace SidebarItem {
63
75
  var displayName: string;
64
76
  }
@@ -0,0 +1,169 @@
1
+ "use client";
2
+ import { jsx as e, jsxs as m, Fragment as S } from "react/jsx-runtime";
3
+ import { forwardRef as z, useState as y, useContext as N, createContext as j } from "react";
4
+ import { ChevronsRight as I, ChevronsLeft as P, ChevronDown as _ } from "../../icons/index.js";
5
+ import { cn as u } from "../../lib/utils.js";
6
+ import { useStrings as G } from "../../hooks/use-strings.js";
7
+ import { Tooltip as R } from "./Tooltip.js";
8
+ const g = j({ collapsed: !1 });
9
+ function H() {
10
+ return N(g);
11
+ }
12
+ const T = z(function({
13
+ defaultCollapsed: n = !1,
14
+ collapsed: s,
15
+ onCollapsedChange: t,
16
+ header: o,
17
+ footer: a,
18
+ className: b,
19
+ children: l,
20
+ ...f
21
+ }, c) {
22
+ const d = G(), [x, h] = y(n), r = s ?? x, v = (p) => {
23
+ s === void 0 && h(p), t == null || t(p);
24
+ };
25
+ return /* @__PURE__ */ e(g.Provider, { value: { collapsed: r }, children: /* @__PURE__ */ m(
26
+ "aside",
27
+ {
28
+ ref: c,
29
+ "aria-label": f["aria-label"] ?? d.sidebar.label,
30
+ className: u(
31
+ "border-border bg-background-subtle sticky top-0 hidden h-screen shrink-0 flex-col gap-2 border-r md:flex",
32
+ "transition-[width] duration-[var(--duration-base)] ease-[var(--ease-out)]",
33
+ r ? "w-14" : "w-60",
34
+ b
35
+ ),
36
+ ...f,
37
+ children: [
38
+ o && /* @__PURE__ */ e(
39
+ "div",
40
+ {
41
+ className: u(
42
+ "border-border flex h-14 shrink-0 items-center overflow-hidden border-b",
43
+ r ? "justify-center px-2" : "px-3"
44
+ ),
45
+ children: o
46
+ }
47
+ ),
48
+ /* @__PURE__ */ e("div", { className: "flex-1 overflow-y-auto py-3", children: l }),
49
+ a && /* @__PURE__ */ e("div", { className: "border-border border-t p-2", children: a }),
50
+ /* @__PURE__ */ m(
51
+ "button",
52
+ {
53
+ type: "button",
54
+ onClick: () => v(!r),
55
+ "aria-label": r ? d.sidebar.expand : d.sidebar.collapse,
56
+ "aria-expanded": !r,
57
+ className: u(
58
+ "text-foreground-subtle mx-2 mb-2 flex h-8 items-center gap-2 rounded-md px-2",
59
+ "hover:bg-background-muted hover:text-foreground outline-none",
60
+ "focus-visible:ring-ring focus-visible:ring-offset-background focus-visible:ring-2 focus-visible:ring-offset-2",
61
+ "transition-colors duration-[var(--duration-fast)]"
62
+ ),
63
+ children: [
64
+ r ? /* @__PURE__ */ e(I, { className: "size-4", "aria-hidden": !0 }) : /* @__PURE__ */ e(P, { className: "size-4", "aria-hidden": !0 }),
65
+ !r && /* @__PURE__ */ e("span", { className: "text-xs font-medium", children: d.sidebar.collapseShort })
66
+ ]
67
+ }
68
+ )
69
+ ]
70
+ }
71
+ ) });
72
+ });
73
+ T.displayName = "Sidebar";
74
+ function C({ label: i, className: n, children: s, ...t }) {
75
+ const { collapsed: o } = N(g);
76
+ return /* @__PURE__ */ m("div", { className: u("mb-3", n), ...t, children: [
77
+ i && !o && /* @__PURE__ */ e("div", { className: "text-foreground-subtle px-4 pt-2 pb-1 text-xs font-medium tracking-wide uppercase", children: i }),
78
+ /* @__PURE__ */ e("ul", { className: "flex flex-col gap-px", children: s })
79
+ ] });
80
+ }
81
+ C.displayName = "SidebarSection";
82
+ function D(i) {
83
+ const { icon: n, active: s, trailing: t, sub: o, tooltip: a, className: b, children: l, ...f } = i, { collapsed: c } = N(g), d = u(
84
+ "flex h-8 w-full items-center gap-2 rounded-md px-2 text-sm outline-none",
85
+ "transition-colors duration-[var(--duration-fast)]",
86
+ "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
87
+ s ? "bg-background-muted text-foreground font-medium" : "text-foreground-muted hover:bg-background-muted hover:text-foreground",
88
+ o && !c && "ml-6",
89
+ c && "justify-center",
90
+ b
91
+ ), x = typeof l == "string" ? l : void 0, h = /* @__PURE__ */ m(S, { children: [
92
+ n && /* @__PURE__ */ e("span", { className: "flex shrink-0 items-center [&_svg]:size-4", children: n }),
93
+ c ? /* @__PURE__ */ e("span", { className: "sr-only", children: l }) : /* @__PURE__ */ e("span", { className: "flex-1 truncate text-left", title: x, children: l }),
94
+ !c && t && /* @__PURE__ */ e("span", { className: "ml-auto", children: t })
95
+ ] });
96
+ let r;
97
+ if (f.href !== void 0) {
98
+ const { href: p, ...k } = f;
99
+ r = /* @__PURE__ */ e(
100
+ "a",
101
+ {
102
+ href: p,
103
+ "aria-current": s ? "page" : void 0,
104
+ className: d,
105
+ ...k,
106
+ children: h
107
+ }
108
+ );
109
+ } else {
110
+ const {
111
+ href: p,
112
+ type: k,
113
+ ...w
114
+ } = f;
115
+ r = /* @__PURE__ */ e(
116
+ "button",
117
+ {
118
+ type: k ?? "button",
119
+ "aria-current": s ? "page" : void 0,
120
+ className: d,
121
+ ...w,
122
+ children: h
123
+ }
124
+ );
125
+ }
126
+ const v = a ?? x;
127
+ return /* @__PURE__ */ e("li", { className: "px-2", children: c && v ? /* @__PURE__ */ e(R, { label: v, side: "right", children: r }) : r });
128
+ }
129
+ D.displayName = "SidebarItem";
130
+ function F({ icon: i, label: n, defaultOpen: s = !0, children: t }) {
131
+ const { collapsed: o } = N(g), [a, b] = y(s);
132
+ return o ? /* @__PURE__ */ e(S, { children: t }) : /* @__PURE__ */ m("li", { children: [
133
+ /* @__PURE__ */ m(
134
+ "button",
135
+ {
136
+ type: "button",
137
+ onClick: () => b((l) => !l),
138
+ "aria-expanded": a,
139
+ className: u(
140
+ "text-foreground-muted mx-2 flex h-8 w-[calc(100%-1rem)] items-center gap-2 rounded-md px-2 text-sm outline-none",
141
+ "transition-colors duration-[var(--duration-fast)]",
142
+ "hover:bg-background-muted hover:text-foreground",
143
+ "focus-visible:ring-ring focus-visible:ring-offset-background focus-visible:ring-2 focus-visible:ring-offset-2"
144
+ ),
145
+ children: [
146
+ i && /* @__PURE__ */ e("span", { className: "flex shrink-0 items-center [&_svg]:size-4", children: i }),
147
+ /* @__PURE__ */ e("span", { className: "flex-1 text-left", children: n }),
148
+ /* @__PURE__ */ e(
149
+ _,
150
+ {
151
+ className: u("size-3.5 transition-transform", a && "rotate-180"),
152
+ "aria-hidden": !0
153
+ }
154
+ )
155
+ ]
156
+ }
157
+ ),
158
+ a && /* @__PURE__ */ e("ul", { className: "flex flex-col gap-px", children: t })
159
+ ] });
160
+ }
161
+ F.displayName = "SidebarGroup";
162
+ export {
163
+ T as Sidebar,
164
+ F as SidebarGroup,
165
+ D as SidebarItem,
166
+ C as SidebarSection,
167
+ H as useSidebar
168
+ };
169
+ //# sourceMappingURL=Sidebar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Sidebar.js","sources":["../../../src/components/ui/Sidebar.tsx"],"sourcesContent":["'use client';\n\nimport {\n createContext,\n forwardRef,\n useContext,\n useState,\n type AnchorHTMLAttributes,\n type ButtonHTMLAttributes,\n type HTMLAttributes,\n type ReactNode,\n} from 'react';\nimport { ChevronDown, ChevronsLeft, ChevronsRight } from '@/icons';\nimport { cn } from '@/lib/utils';\nimport { useStrings } from '@/hooks/use-strings';\nimport { Tooltip } from './Tooltip';\n\ninterface SidebarContextValue {\n collapsed: boolean;\n}\nconst SidebarContext = createContext<SidebarContextValue>({ collapsed: false });\n\n/** Read the parent Sidebar's collapsed state. Useful for brand/footer slots\n * that need to swap between full and compact rendering. */\nexport function useSidebar(): SidebarContextValue {\n return useContext(SidebarContext);\n}\n\nexport interface SidebarProps extends HTMLAttributes<HTMLElement> {\n /** Default state on first mount. Use `defaultCollapsed` for uncontrolled. */\n defaultCollapsed?: boolean;\n /** Controlled collapsed state. */\n collapsed?: boolean;\n /** Called when the user toggles via the rail or keyboard. */\n onCollapsedChange?: (next: boolean) => void;\n /** Header slot pinned to the top (brand, workspace switcher, etc.). */\n header?: ReactNode;\n /** Footer slot pinned to the bottom (user card, version, etc.). */\n footer?: ReactNode;\n}\n\n/**\n * App-level navigation rail. Holds `SidebarSection` → `SidebarItem` lists,\n * and optionally a `footer`. Supports collapse to icon-only on desktop.\n * Below `md` the rail is hidden — pair it with a Sheet / Drawer for mobile.\n *\n * @example\n * <Sidebar footer={<UserCard />}>\n * <SidebarSection label=\"Workspace\">\n * <SidebarItem icon={<Home />} active>Home</SidebarItem>\n * <SidebarItem icon={<Folder />}>Projects</SidebarItem>\n * </SidebarSection>\n * <SidebarSection label=\"Account\">\n * <SidebarItem icon={<Settings />}>Settings</SidebarItem>\n * </SidebarSection>\n * </Sidebar>\n *\n * @do Use 1–3 sections. More than that signals the IA needs restructuring.\n * @dont Hide critical navigation under the collapsed state — keep icons\n * always visible with tooltips.\n */\nexport const Sidebar = forwardRef<HTMLElement, SidebarProps>(function Sidebar(\n {\n defaultCollapsed = false,\n collapsed: controlled,\n onCollapsedChange,\n header,\n footer,\n className,\n children,\n ...props\n },\n ref,\n) {\n const strings = useStrings();\n const [internal, setInternal] = useState(defaultCollapsed);\n const collapsed = controlled ?? internal;\n const setCollapsed = (next: boolean) => {\n if (controlled === undefined) setInternal(next);\n onCollapsedChange?.(next);\n };\n\n return (\n <SidebarContext.Provider value={{ collapsed }}>\n <aside\n ref={ref}\n aria-label={props['aria-label'] ?? strings.sidebar.label}\n className={cn(\n 'border-border bg-background-subtle sticky top-0 hidden h-screen shrink-0 flex-col gap-2 border-r md:flex',\n 'transition-[width] duration-[var(--duration-base)] ease-[var(--ease-out)]',\n collapsed ? 'w-14' : 'w-60',\n className,\n )}\n {...props}\n >\n {header && (\n <div\n className={cn(\n 'border-border flex h-14 shrink-0 items-center overflow-hidden border-b',\n collapsed ? 'justify-center px-2' : 'px-3',\n )}\n >\n {header}\n </div>\n )}\n <div className=\"flex-1 overflow-y-auto py-3\">{children}</div>\n {footer && <div className=\"border-border border-t p-2\">{footer}</div>}\n <button\n type=\"button\"\n onClick={() => setCollapsed(!collapsed)}\n aria-label={collapsed ? strings.sidebar.expand : strings.sidebar.collapse}\n aria-expanded={!collapsed}\n className={cn(\n 'text-foreground-subtle mx-2 mb-2 flex h-8 items-center gap-2 rounded-md px-2',\n 'hover:bg-background-muted hover:text-foreground outline-none',\n 'focus-visible:ring-ring focus-visible:ring-offset-background focus-visible:ring-2 focus-visible:ring-offset-2',\n 'transition-colors duration-[var(--duration-fast)]',\n )}\n >\n {collapsed ? (\n <ChevronsRight className=\"size-4\" aria-hidden />\n ) : (\n <ChevronsLeft className=\"size-4\" aria-hidden />\n )}\n {!collapsed && <span className=\"text-xs font-medium\">{strings.sidebar.collapseShort}</span>}\n </button>\n </aside>\n </SidebarContext.Provider>\n );\n});\nSidebar.displayName = 'Sidebar';\n\nexport interface SidebarSectionProps extends HTMLAttributes<HTMLDivElement> {\n /** Visible section header. Hidden when collapsed. */\n label?: ReactNode;\n}\n\nexport function SidebarSection({ label, className, children, ...props }: SidebarSectionProps) {\n const { collapsed } = useContext(SidebarContext);\n return (\n <div className={cn('mb-3', className)} {...props}>\n {label && !collapsed && (\n <div className=\"text-foreground-subtle px-4 pt-2 pb-1 text-xs font-medium tracking-wide uppercase\">\n {label}\n </div>\n )}\n <ul className=\"flex flex-col gap-px\">{children}</ul>\n </div>\n );\n}\nSidebarSection.displayName = 'SidebarSection';\n\ninterface SidebarItemBaseProps {\n /** Lucide icon shown to the left. */\n icon?: ReactNode;\n /** Mark as the current page. */\n active?: boolean;\n /** Trailing badge / counter slot. */\n trailing?: ReactNode;\n /** Render a sub-item indented under a parent. */\n sub?: boolean;\n /**\n * Tooltip text shown while the sidebar is collapsed. Defaults to `children`\n * when that is a plain string.\n */\n tooltip?: ReactNode;\n}\n\ntype SidebarItemAnchorProps = SidebarItemBaseProps &\n AnchorHTMLAttributes<HTMLAnchorElement> & {\n /** Renders an `<a>`. Omit to render a `<button>`. */\n href: string;\n };\n\ntype SidebarItemButtonProps = SidebarItemBaseProps &\n ButtonHTMLAttributes<HTMLButtonElement> & {\n href?: undefined;\n };\n\n/** Discriminated on `href`: with it the item is an anchor, without it a button. */\nexport type SidebarItemProps = SidebarItemAnchorProps | SidebarItemButtonProps;\n\nexport function SidebarItem(props: SidebarItemProps) {\n const { icon, active, trailing, sub, tooltip, className, children, ...rest } = props;\n const { collapsed } = useContext(SidebarContext);\n\n const classes = cn(\n 'flex h-8 w-full items-center gap-2 rounded-md px-2 text-sm outline-none',\n 'transition-colors duration-[var(--duration-fast)]',\n 'focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background',\n active\n ? 'bg-background-muted text-foreground font-medium'\n : 'text-foreground-muted hover:bg-background-muted hover:text-foreground',\n sub && !collapsed && 'ml-6',\n collapsed && 'justify-center',\n className,\n );\n\n const labelTitle = typeof children === 'string' ? children : undefined;\n\n const content = (\n <>\n {icon && <span className=\"flex shrink-0 items-center [&_svg]:size-4\">{icon}</span>}\n {collapsed ? (\n <span className=\"sr-only\">{children}</span>\n ) : (\n <span className=\"flex-1 truncate text-left\" title={labelTitle}>\n {children}\n </span>\n )}\n {!collapsed && trailing && <span className=\"ml-auto\">{trailing}</span>}\n </>\n );\n\n let element: ReactNode;\n if (rest.href !== undefined) {\n const { href, ...anchorProps } = rest as Omit<\n SidebarItemAnchorProps,\n keyof SidebarItemBaseProps\n >;\n element = (\n <a\n href={href}\n aria-current={active ? 'page' : undefined}\n className={classes}\n {...anchorProps}\n >\n {content}\n </a>\n );\n } else {\n const {\n href: _href,\n type,\n ...buttonProps\n } = rest as Omit<SidebarItemButtonProps, keyof SidebarItemBaseProps>;\n element = (\n <button\n type={type ?? 'button'}\n aria-current={active ? 'page' : undefined}\n className={classes}\n {...buttonProps}\n >\n {content}\n </button>\n );\n }\n\n const tip = tooltip ?? labelTitle;\n return (\n <li className=\"px-2\">\n {collapsed && tip ? (\n <Tooltip label={tip} side=\"right\">\n {element}\n </Tooltip>\n ) : (\n element\n )}\n </li>\n );\n}\nSidebarItem.displayName = 'SidebarItem';\n\n/** Lightweight collapsible sub-section inside the sidebar. */\nexport interface SidebarGroupProps {\n icon?: ReactNode;\n label: ReactNode;\n defaultOpen?: boolean;\n children: ReactNode;\n}\n\nexport function SidebarGroup({ icon, label, defaultOpen = true, children }: SidebarGroupProps) {\n const { collapsed } = useContext(SidebarContext);\n const [open, setOpen] = useState(defaultOpen);\n if (collapsed) return <>{children}</>;\n return (\n <li>\n <button\n type=\"button\"\n onClick={() => setOpen((o) => !o)}\n aria-expanded={open}\n className={cn(\n 'text-foreground-muted mx-2 flex h-8 w-[calc(100%-1rem)] items-center gap-2 rounded-md px-2 text-sm outline-none',\n 'transition-colors duration-[var(--duration-fast)]',\n 'hover:bg-background-muted hover:text-foreground',\n 'focus-visible:ring-ring focus-visible:ring-offset-background focus-visible:ring-2 focus-visible:ring-offset-2',\n )}\n >\n {icon && <span className=\"flex shrink-0 items-center [&_svg]:size-4\">{icon}</span>}\n <span className=\"flex-1 text-left\">{label}</span>\n <ChevronDown\n className={cn('size-3.5 transition-transform', open && 'rotate-180')}\n aria-hidden\n />\n </button>\n {open && <ul className=\"flex flex-col gap-px\">{children}</ul>}\n </li>\n );\n}\nSidebarGroup.displayName = 'SidebarGroup';\n"],"names":["SidebarContext","createContext","useSidebar","useContext","Sidebar","forwardRef","defaultCollapsed","controlled","onCollapsedChange","header","footer","className","children","props","ref","strings","useStrings","internal","setInternal","useState","collapsed","setCollapsed","next","jsxs","cn","jsx","ChevronsRight","ChevronsLeft","SidebarSection","label","SidebarItem","icon","active","trailing","sub","tooltip","rest","classes","labelTitle","content","Fragment","element","href","anchorProps","_href","type","buttonProps","tip","Tooltip","SidebarGroup","defaultOpen","open","setOpen","o","ChevronDown"],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ "use client";
2
+ import { jsx as u } from "react/jsx-runtime";
3
+ import { forwardRef as t } from "react";
4
+ import { cn as l } from "../../lib/utils.js";
5
+ const n = t(function({ className: d, variant: e, ...o }, r) {
6
+ return /* @__PURE__ */ u(
7
+ "div",
8
+ {
9
+ ref: r,
10
+ "aria-hidden": !0,
11
+ className: l(
12
+ "animate-pulse bg-background-muted",
13
+ e === "text" && "h-3 rounded-sm",
14
+ e === "circle" && "rounded-full aspect-square",
15
+ e === "avatar" && "size-8 rounded-full",
16
+ e === "card" && "rounded-lg",
17
+ !e && "rounded-md",
18
+ d
19
+ ),
20
+ ...o
21
+ }
22
+ );
23
+ });
24
+ n.displayName = "Skeleton";
25
+ export {
26
+ n as Skeleton
27
+ };
28
+ //# sourceMappingURL=Skeleton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Skeleton.js","sources":["../../../src/components/ui/Skeleton.tsx"],"sourcesContent":["'use client';\n\nimport { forwardRef, type HTMLAttributes } from 'react';\nimport { cn } from '@/lib/utils';\n\nexport interface SkeletonProps extends HTMLAttributes<HTMLDivElement> {\n /** Predefined silhouette presets. */\n variant?: 'text' | 'circle' | 'card' | 'avatar';\n}\n\n/**\n * Animated placeholder. Use `Skeleton.Text` / `Skeleton.Avatar` for common\n * shapes; pass `className` directly for one-off sizes.\n *\n * @example List item\n * <div className=\"flex items-center gap-3\">\n * <Skeleton variant=\"avatar\" />\n * <div className=\"space-y-1.5 flex-1\">\n * <Skeleton variant=\"text\" className=\"w-1/3\" />\n * <Skeleton variant=\"text\" className=\"w-1/2\" />\n * </div>\n * </div>\n *\n * @example Card\n * <Skeleton variant=\"card\" className=\"h-32\" />\n *\n * @do Match the silhouette of the eventual content so the layout doesn't\n * shift when data arrives.\n * @dont Show a full-page skeleton for sub-300ms loads — use a single Spinner.\n */\nexport const Skeleton = forwardRef<HTMLDivElement, SkeletonProps>(function Skeleton(\n { className, variant, ...props },\n ref,\n) {\n return (\n <div\n ref={ref}\n aria-hidden\n className={cn(\n 'animate-pulse bg-background-muted',\n variant === 'text' && 'h-3 rounded-sm',\n variant === 'circle' && 'rounded-full aspect-square',\n variant === 'avatar' && 'size-8 rounded-full',\n variant === 'card' && 'rounded-lg',\n !variant && 'rounded-md',\n className,\n )}\n {...props}\n />\n );\n});\nSkeleton.displayName = 'Skeleton';\n"],"names":["Skeleton","forwardRef","className","variant","props","ref","jsx","cn"],"mappings":";;;;AA8BO,MAAMA,IAAWC,EAA0C,SAChE,EAAE,WAAAC,GAAW,SAAAC,GAAS,GAAGC,EAAA,GACzBC,GACA;AACA,SACE,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAAD;AAAA,MACA,eAAW;AAAA,MACX,WAAWE;AAAA,QACT;AAAA,QACAJ,MAAY,UAAU;AAAA,QACtBA,MAAY,YAAY;AAAA,QACxBA,MAAY,YAAY;AAAA,QACxBA,MAAY,UAAU;AAAA,QACtB,CAACA,KAAW;AAAA,QACZD;AAAA,MAAA;AAAA,MAED,GAAGE;AAAA,IAAA;AAAA,EAAA;AAGV,CAAC;AACDJ,EAAS,cAAc;"}
@@ -0,0 +1,52 @@
1
+ "use client";
2
+ import { jsxs as d, jsx as o } from "react/jsx-runtime";
3
+ import { forwardRef as N, useId as y } from "react";
4
+ import * as i from "@radix-ui/react-slider";
5
+ import { cn as v } from "../../lib/utils.js";
6
+ import { useStrings as w } from "../../hooks/use-strings.js";
7
+ const S = N(
8
+ function({ className: h, label: e, showValue: c, formatValue: s = (r) => String(r), value: f, defaultValue: m, ...u }, p) {
9
+ const r = f ?? m ?? [0], t = r.length > 1, n = y(), a = w(), l = typeof e == "string" ? e : void 0, x = (b) => t ? b === 0 ? a.slider.minimum : a.slider.maximum : l ?? u["aria-label"] ?? a.slider.value;
10
+ return /* @__PURE__ */ d("div", { className: v("flex flex-col gap-2", h), children: [
11
+ (e || c) && /* @__PURE__ */ d("div", { className: "flex items-center justify-between", children: [
12
+ e && /* @__PURE__ */ o("span", { id: n, className: "text-foreground text-sm font-medium", children: e }),
13
+ c && /* @__PURE__ */ o("span", { className: "tabular text-foreground-muted font-mono text-xs", children: t ? `${s(r[0])} – ${s(r[1])}` : s(r[0]) })
14
+ ] }),
15
+ /* @__PURE__ */ d(
16
+ i.Root,
17
+ {
18
+ ref: p,
19
+ value: f,
20
+ defaultValue: m,
21
+ className: "relative flex w-full touch-none items-center py-3.5 select-none",
22
+ "aria-labelledby": e && !l ? n : void 0,
23
+ ...u,
24
+ children: [
25
+ /* @__PURE__ */ o(i.Track, { className: "bg-background-muted relative h-1 w-full grow overflow-hidden rounded-full", children: /* @__PURE__ */ o(i.Range, { className: "bg-accent absolute h-full" }) }),
26
+ r.map((b, g) => /* @__PURE__ */ o(
27
+ i.Thumb,
28
+ {
29
+ className: v(
30
+ "border-accent bg-card relative block size-4 rounded-full border-2 shadow-sm",
31
+ // 44px touch target without growing the visible thumb.
32
+ 'before:absolute before:top-1/2 before:left-1/2 before:size-11 before:-translate-x-1/2 before:-translate-y-1/2 before:rounded-full before:content-[""]',
33
+ "focus-visible:ring-ring focus-visible:ring-offset-background outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
34
+ "transition-transform duration-[var(--duration-fast)] ease-[var(--ease-out)]",
35
+ "hover:scale-110 disabled:pointer-events-none disabled:opacity-50"
36
+ ),
37
+ "aria-label": x(g),
38
+ "aria-labelledby": !t && e && !l ? n : void 0
39
+ },
40
+ g
41
+ ))
42
+ ]
43
+ }
44
+ )
45
+ ] });
46
+ }
47
+ );
48
+ S.displayName = "Slider";
49
+ export {
50
+ S as Slider
51
+ };
52
+ //# sourceMappingURL=Slider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Slider.js","sources":["../../../src/components/ui/Slider.tsx"],"sourcesContent":["'use client';\n\nimport {\n forwardRef,\n useId,\n type ComponentPropsWithoutRef,\n type ElementRef,\n type ReactNode,\n} from 'react';\nimport * as SliderPrimitive from '@radix-ui/react-slider';\nimport { cn } from '@/lib/utils';\nimport { useStrings } from '@/hooks/use-strings';\n\nexport interface SliderProps extends Omit<\n ComponentPropsWithoutRef<typeof SliderPrimitive.Root>,\n 'value' | 'defaultValue'\n> {\n /**\n * Controlled value. Pass `[n]` for a single-thumb slider, `[a, b]` for a range slider.\n */\n value?: number[];\n defaultValue?: number[];\n /** Inline label rendered above the slider. */\n label?: ReactNode;\n /** Show the numeric value next to the label. */\n showValue?: boolean;\n /** Format the displayed value (e.g. `(v) => \\`${v}%\\``). */\n formatValue?: (value: number) => string;\n}\n\n/**\n * Single- or range-thumb slider. Pass one item in `value` for a single\n * thumb, two for a range.\n *\n * @example Single value\n * <Slider label=\"Volume\" showValue defaultValue={[60]} max={100} step={1} />\n *\n * @example Price range\n * <Slider label=\"Price\"\n * defaultValue={[50, 250]}\n * min={0} max={500} step={10}\n * formatValue={(v) => \\`$\\${v}\\`}\n * showValue />\n *\n * @do Use `showValue` when the absolute number matters (price, volume, weight).\n * @dont Hide the value when users will need to reason about exact thresholds.\n */\nexport const Slider = forwardRef<ElementRef<typeof SliderPrimitive.Root>, SliderProps>(\n function Slider(\n { className, label, showValue, formatValue = (v) => String(v), value, defaultValue, ...props },\n ref,\n ) {\n const currentValue = value ?? defaultValue ?? [0];\n const isRange = currentValue.length > 1;\n const labelId = useId();\n const strings = useStrings();\n // Only a string label can double as aria-label; ReactNode labels are\n // referenced by id instead.\n const stringLabel = typeof label === 'string' ? label : undefined;\n const thumbLabel = (i: number) =>\n isRange\n ? i === 0\n ? strings.slider.minimum\n : strings.slider.maximum\n : (stringLabel ?? props['aria-label'] ?? strings.slider.value);\n\n return (\n <div className={cn('flex flex-col gap-2', className)}>\n {(label || showValue) && (\n <div className=\"flex items-center justify-between\">\n {label && (\n <span id={labelId} className=\"text-foreground text-sm font-medium\">\n {label}\n </span>\n )}\n {showValue && (\n <span className=\"tabular text-foreground-muted font-mono text-xs\">\n {isRange\n ? `${formatValue(currentValue[0])} – ${formatValue(currentValue[1])}`\n : formatValue(currentValue[0])}\n </span>\n )}\n </div>\n )}\n\n <SliderPrimitive.Root\n ref={ref}\n value={value}\n defaultValue={defaultValue}\n className=\"relative flex w-full touch-none items-center py-3.5 select-none\"\n aria-labelledby={label && !stringLabel ? labelId : undefined}\n {...props}\n >\n <SliderPrimitive.Track className=\"bg-background-muted relative h-1 w-full grow overflow-hidden rounded-full\">\n <SliderPrimitive.Range className=\"bg-accent absolute h-full\" />\n </SliderPrimitive.Track>\n {currentValue.map((_, i) => (\n <SliderPrimitive.Thumb\n key={i}\n className={cn(\n 'border-accent bg-card relative block size-4 rounded-full border-2 shadow-sm',\n // 44px touch target without growing the visible thumb.\n 'before:absolute before:top-1/2 before:left-1/2 before:size-11 before:-translate-x-1/2 before:-translate-y-1/2 before:rounded-full before:content-[\"\"]',\n 'focus-visible:ring-ring focus-visible:ring-offset-background outline-none focus-visible:ring-2 focus-visible:ring-offset-2',\n 'transition-transform duration-[var(--duration-fast)] ease-[var(--ease-out)]',\n 'hover:scale-110 disabled:pointer-events-none disabled:opacity-50',\n )}\n aria-label={thumbLabel(i)}\n aria-labelledby={!isRange && label && !stringLabel ? labelId : undefined}\n />\n ))}\n </SliderPrimitive.Root>\n </div>\n );\n },\n);\n\nSlider.displayName = 'Slider';\n"],"names":["Slider","forwardRef","className","label","showValue","formatValue","v","value","defaultValue","props","ref","currentValue","isRange","labelId","useId","strings","useStrings","stringLabel","thumbLabel","i","cn","jsxs","SliderPrimitive","jsx","_"],"mappings":";;;;;;AA+CO,MAAMA,IAASC;AAAA,EACpB,SACE,EAAE,WAAAC,GAAW,OAAAC,GAAO,WAAAC,GAAW,aAAAC,IAAc,CAACC,MAAM,OAAOA,CAAC,GAAG,OAAAC,GAAO,cAAAC,GAAc,GAAGC,EAAA,GACvFC,GACA;AACA,UAAMC,IAAeJ,KAASC,KAAgB,CAAC,CAAC,GAC1CI,IAAUD,EAAa,SAAS,GAChCE,IAAUC,EAAA,GACVC,IAAUC,EAAA,GAGVC,IAAc,OAAOd,KAAU,WAAWA,IAAQ,QAClDe,IAAa,CAACC,MAClBP,IACIO,MAAM,IACJJ,EAAQ,OAAO,UACfA,EAAQ,OAAO,UAChBE,KAAeR,EAAM,YAAY,KAAKM,EAAQ,OAAO;AAE5D,6BACG,OAAA,EAAI,WAAWK,EAAG,uBAAuBlB,CAAS,GAC/C,UAAA;AAAA,OAAAC,KAASC,MACT,gBAAAiB,EAAC,OAAA,EAAI,WAAU,qCACZ,UAAA;AAAA,QAAAlB,uBACE,QAAA,EAAK,IAAIU,GAAS,WAAU,uCAC1B,UAAAV,GACH;AAAA,QAEDC,uBACE,QAAA,EAAK,WAAU,mDACb,UAAAQ,IACG,GAAGP,EAAYM,EAAa,CAAC,CAAC,CAAC,MAAMN,EAAYM,EAAa,CAAC,CAAC,CAAC,KACjEN,EAAYM,EAAa,CAAC,CAAC,EAAA,CACjC;AAAA,MAAA,GAEJ;AAAA,MAGF,gBAAAU;AAAA,QAACC,EAAgB;AAAA,QAAhB;AAAA,UACC,KAAAZ;AAAA,UACA,OAAAH;AAAA,UACA,cAAAC;AAAA,UACA,WAAU;AAAA,UACV,mBAAiBL,KAAS,CAACc,IAAcJ,IAAU;AAAA,UAClD,GAAGJ;AAAA,UAEJ,UAAA;AAAA,YAAA,gBAAAc,EAACD,EAAgB,OAAhB,EAAsB,WAAU,6EAC/B,UAAA,gBAAAC,EAACD,EAAgB,OAAhB,EAAsB,WAAU,4BAAA,CAA4B,EAAA,CAC/D;AAAA,YACCX,EAAa,IAAI,CAACa,GAAGL,MACpB,gBAAAI;AAAA,cAACD,EAAgB;AAAA,cAAhB;AAAA,gBAEC,WAAWF;AAAA,kBACT;AAAA;AAAA,kBAEA;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,gBAAA;AAAA,gBAEF,cAAYF,EAAWC,CAAC;AAAA,gBACxB,mBAAiB,CAACP,KAAWT,KAAS,CAACc,IAAcJ,IAAU;AAAA,cAAA;AAAA,cAV1DM;AAAA,YAAA,CAYR;AAAA,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,IACH,GACF;AAAA,EAEJ;AACF;AAEAnB,EAAO,cAAc;"}
@@ -1,5 +1,5 @@
1
1
  import { HTMLAttributes, ReactNode } from 'react';
2
- import { VariantProps } from '../../lib/cva';
2
+ import { VariantProps } from '../../lib/cva.js';
3
3
  declare const snackbar: (props?: ({
4
4
  variant?: "default" | "success" | "warning" | "danger" | "info" | null | undefined;
5
5
  } & import('class-variance-authority/types').ClassProp) | undefined) => string;
@@ -0,0 +1,56 @@
1
+ "use client";
2
+ import { jsxs as o, jsx as e } from "react/jsx-runtime";
3
+ import { forwardRef as f } from "react";
4
+ import { X as b, XCircle as g, AlertTriangle as x, CheckCircle2 as h, Info as p } from "../../icons/index.js";
5
+ import { cn as k } from "../../lib/utils.js";
6
+ import { useStrings as N } from "../../hooks/use-strings.js";
7
+ import { cva as v } from "class-variance-authority";
8
+ const w = v(
9
+ [
10
+ "relative pointer-events-auto w-full max-w-md",
11
+ "flex items-start gap-3 rounded-md border bg-card p-3 shadow-md",
12
+ "text-sm text-foreground"
13
+ ],
14
+ {
15
+ variants: {
16
+ variant: {
17
+ default: "border-border",
18
+ info: "border-info-border-soft",
19
+ success: "border-success-border-soft",
20
+ warning: "border-warning-border-soft",
21
+ danger: "border-danger-border-soft"
22
+ }
23
+ },
24
+ defaultVariants: { variant: "default" }
25
+ }
26
+ ), z = {
27
+ default: null,
28
+ info: /* @__PURE__ */ e(p, { className: "size-4 shrink-0 mt-0.5 text-info-text", "aria-hidden": !0 }),
29
+ success: /* @__PURE__ */ e(h, { className: "size-4 shrink-0 mt-0.5 text-success-text", "aria-hidden": !0 }),
30
+ warning: /* @__PURE__ */ e(x, { className: "size-4 shrink-0 mt-0.5 text-warning-text", "aria-hidden": !0 }),
31
+ danger: /* @__PURE__ */ e(g, { className: "size-4 shrink-0 mt-0.5 text-danger-text", "aria-hidden": !0 })
32
+ }, A = f(function({ className: d, variant: r = "default", title: t, action: i, onClose: a, icon: s, children: n, ...c }, m) {
33
+ const l = N(), u = s === !1 ? null : s ?? z[r ?? "default"];
34
+ return /* @__PURE__ */ o("div", { ref: m, role: "status", className: k(w({ variant: r }), d), ...c, children: [
35
+ u,
36
+ /* @__PURE__ */ o("div", { className: "min-w-0 flex-1", children: [
37
+ t && /* @__PURE__ */ e("p", { className: "font-medium", children: t }),
38
+ n && /* @__PURE__ */ e("p", { className: "text-foreground-muted", children: n })
39
+ ] }),
40
+ i,
41
+ a && /* @__PURE__ */ e(
42
+ "button",
43
+ {
44
+ type: "button",
45
+ onClick: a,
46
+ "aria-label": l.snackbar.dismiss,
47
+ className: "rounded p-1 text-foreground-muted hover:bg-background-muted hover:text-foreground",
48
+ children: /* @__PURE__ */ e(b, { className: "size-4" })
49
+ }
50
+ )
51
+ ] });
52
+ });
53
+ export {
54
+ A as Snackbar
55
+ };
56
+ //# sourceMappingURL=Snackbar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Snackbar.js","sources":["../../../src/components/ui/Snackbar.tsx"],"sourcesContent":["'use client';\n\nimport { forwardRef, type HTMLAttributes, type ReactNode } from 'react';\nimport { CheckCircle2, Info, AlertTriangle, XCircle, X } from '@/icons';\nimport { cn } from '@/lib/utils';\nimport { useStrings } from '@/hooks/use-strings';\nimport { cva, type VariantProps } from '@/lib/cva';\n\nconst snackbar = cva(\n [\n 'relative pointer-events-auto w-full max-w-md',\n 'flex items-start gap-3 rounded-md border bg-card p-3 shadow-md',\n 'text-sm text-foreground',\n ],\n {\n variants: {\n variant: {\n default: 'border-border',\n info: 'border-info-border-soft',\n success: 'border-success-border-soft',\n warning: 'border-warning-border-soft',\n danger: 'border-danger-border-soft',\n },\n },\n defaultVariants: { variant: 'default' },\n },\n);\n\nconst iconForVariant: Record<NonNullable<VariantProps<typeof snackbar>['variant']>, ReactNode> = {\n default: null,\n info: <Info className=\"size-4 shrink-0 mt-0.5 text-info-text\" aria-hidden />,\n success: <CheckCircle2 className=\"size-4 shrink-0 mt-0.5 text-success-text\" aria-hidden />,\n warning: <AlertTriangle className=\"size-4 shrink-0 mt-0.5 text-warning-text\" aria-hidden />,\n danger: <XCircle className=\"size-4 shrink-0 mt-0.5 text-danger-text\" aria-hidden />,\n};\n\nexport interface SnackbarProps\n extends Omit<HTMLAttributes<HTMLDivElement>, 'title'>,\n VariantProps<typeof snackbar> {\n /** Headline. */\n title?: ReactNode;\n /** Action button rendered on the right. */\n action?: ReactNode;\n /** Show a close (×) button on the right. */\n onClose?: () => void;\n /** Override the variant's default icon. Pass `false` to hide. */\n icon?: ReactNode | false;\n}\n\n/**\n * Persistent inline notification. Unlike Toast, Snackbar does **not** auto-\n * dismiss. Pair with an `action` button or an `onClose` handler.\n */\nexport const Snackbar = forwardRef<HTMLDivElement, SnackbarProps>(function Snackbar(\n { className, variant = 'default', title, action, onClose, icon, children, ...props },\n ref,\n) {\n const strings = useStrings();\n const renderedIcon = icon === false ? null : icon ?? iconForVariant[variant ?? 'default'];\n\n return (\n <div ref={ref} role=\"status\" className={cn(snackbar({ variant }), className)} {...props}>\n {renderedIcon}\n <div className=\"min-w-0 flex-1\">\n {title && <p className=\"font-medium\">{title}</p>}\n {children && <p className=\"text-foreground-muted\">{children}</p>}\n </div>\n {action}\n {onClose && (\n <button\n type=\"button\"\n onClick={onClose}\n aria-label={strings.snackbar.dismiss}\n className=\"rounded p-1 text-foreground-muted hover:bg-background-muted hover:text-foreground\"\n >\n <X className=\"size-4\" />\n </button>\n )}\n </div>\n );\n});\n"],"names":["snackbar","cva","iconForVariant","jsx","Info","CheckCircle2","AlertTriangle","XCircle","Snackbar","forwardRef","className","variant","title","action","onClose","icon","children","props","ref","strings","useStrings","renderedIcon","jsxs","cn","X"],"mappings":";;;;;;;AAQA,MAAMA,IAAWC;AAAA,EACf;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAAA,EAEF;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,MAAM;AAAA,QACN,SAAS;AAAA,QACT,SAAS;AAAA,QACT,QAAQ;AAAA,MAAA;AAAA,IACV;AAAA,IAEF,iBAAiB,EAAE,SAAS,UAAA;AAAA,EAAU;AAE1C,GAEMC,IAA2F;AAAA,EAC/F,SAAS;AAAA,EACT,MAAM,gBAAAC,EAACC,GAAA,EAAK,WAAU,yCAAwC,eAAW,IAAC;AAAA,EAC1E,SAAS,gBAAAD,EAACE,GAAA,EAAa,WAAU,4CAA2C,eAAW,IAAC;AAAA,EACxF,SAAS,gBAAAF,EAACG,GAAA,EAAc,WAAU,4CAA2C,eAAW,IAAC;AAAA,EACzF,QAAQ,gBAAAH,EAACI,GAAA,EAAQ,WAAU,2CAA0C,eAAW,GAAA,CAAC;AACnF,GAmBaC,IAAWC,EAA0C,SAChE,EAAE,WAAAC,GAAW,SAAAC,IAAU,WAAW,OAAAC,GAAO,QAAAC,GAAQ,SAAAC,GAAS,MAAAC,GAAM,UAAAC,GAAU,GAAGC,EAAA,GAC7EC,GACA;AACA,QAAMC,IAAUC,EAAA,GACVC,IAAeN,MAAS,KAAQ,OAAOA,KAAQb,EAAeS,KAAW,SAAS;AAExF,SACE,gBAAAW,EAAC,OAAA,EAAI,KAAAJ,GAAU,MAAK,UAAS,WAAWK,EAAGvB,EAAS,EAAE,SAAAW,GAAS,GAAGD,CAAS,GAAI,GAAGO,GAC/E,UAAA;AAAA,IAAAI;AAAA,IACD,gBAAAC,EAAC,OAAA,EAAI,WAAU,kBACZ,UAAA;AAAA,MAAAV,KAAS,gBAAAT,EAAC,KAAA,EAAE,WAAU,eAAe,UAAAS,GAAM;AAAA,MAC3CI,KAAY,gBAAAb,EAAC,KAAA,EAAE,WAAU,yBAAyB,UAAAa,EAAA,CAAS;AAAA,IAAA,GAC9D;AAAA,IACCH;AAAA,IACAC,KACC,gBAAAX;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,SAASW;AAAA,QACT,cAAYK,EAAQ,SAAS;AAAA,QAC7B,WAAU;AAAA,QAEV,UAAA,gBAAAhB,EAACqB,GAAA,EAAE,WAAU,SAAA,CAAS;AAAA,MAAA;AAAA,IAAA;AAAA,EACxB,GAEJ;AAEJ,CAAC;"}