@craftzbay/ui 0.9.0 → 0.11.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 (208) hide show
  1. package/README.md +82 -10
  2. package/dist-lib/__tests__/helpers/color.d.ts +9 -0
  3. package/dist-lib/__tests__/helpers/theme.d.ts +18 -0
  4. package/dist-lib/components/ui/Accordion.js +71 -0
  5. package/dist-lib/components/ui/Accordion.js.map +1 -0
  6. package/dist-lib/components/ui/Alert.d.ts +17 -1
  7. package/dist-lib/components/ui/Alert.js +79 -0
  8. package/dist-lib/components/ui/Alert.js.map +1 -0
  9. package/dist-lib/components/ui/Avatar.d.ts +3 -3
  10. package/dist-lib/components/ui/Avatar.js +94 -0
  11. package/dist-lib/components/ui/Avatar.js.map +1 -0
  12. package/dist-lib/components/ui/Badge.d.ts +4 -2
  13. package/dist-lib/components/ui/Badge.js +76 -0
  14. package/dist-lib/components/ui/Badge.js.map +1 -0
  15. package/dist-lib/components/ui/Breadcrumbs.d.ts +2 -0
  16. package/dist-lib/components/ui/Breadcrumbs.js +52 -0
  17. package/dist-lib/components/ui/Breadcrumbs.js.map +1 -0
  18. package/dist-lib/components/ui/Button.d.ts +6 -4
  19. package/dist-lib/components/ui/Button.js +131 -0
  20. package/dist-lib/components/ui/Button.js.map +1 -0
  21. package/dist-lib/components/ui/Calendar.d.ts +7 -1
  22. package/dist-lib/components/ui/Calendar.js +139 -0
  23. package/dist-lib/components/ui/Calendar.js.map +1 -0
  24. package/dist-lib/components/ui/Card.d.ts +3 -1
  25. package/dist-lib/components/ui/Card.js +97 -0
  26. package/dist-lib/components/ui/Card.js.map +1 -0
  27. package/dist-lib/components/ui/Carousel.d.ts +11 -7
  28. package/dist-lib/components/ui/Carousel.js +174 -0
  29. package/dist-lib/components/ui/Carousel.js.map +1 -0
  30. package/dist-lib/components/ui/Chart.d.ts +68 -7
  31. package/dist-lib/components/ui/Chart.js +487 -0
  32. package/dist-lib/components/ui/Chart.js.map +1 -0
  33. package/dist-lib/components/ui/Checkbox.js +70 -0
  34. package/dist-lib/components/ui/Checkbox.js.map +1 -0
  35. package/dist-lib/components/ui/Combobox.d.ts +9 -0
  36. package/dist-lib/components/ui/Combobox.js +195 -0
  37. package/dist-lib/components/ui/Combobox.js.map +1 -0
  38. package/dist-lib/components/ui/CommandPalette.d.ts +9 -6
  39. package/dist-lib/components/ui/CommandPalette.js +179 -0
  40. package/dist-lib/components/ui/CommandPalette.js.map +1 -0
  41. package/dist-lib/components/ui/ContextMenu.d.ts +7 -2
  42. package/dist-lib/components/ui/ContextMenu.js +165 -0
  43. package/dist-lib/components/ui/ContextMenu.js.map +1 -0
  44. package/dist-lib/components/ui/DataGrid.d.ts +17 -4
  45. package/dist-lib/components/ui/DataGrid.js +99 -0
  46. package/dist-lib/components/ui/DataGrid.js.map +1 -0
  47. package/dist-lib/components/ui/DatePicker.d.ts +16 -13
  48. package/dist-lib/components/ui/DatePicker.js +193 -0
  49. package/dist-lib/components/ui/DatePicker.js.map +1 -0
  50. package/dist-lib/components/ui/DesignSystemProvider.d.ts +102 -41
  51. package/dist-lib/components/ui/DesignSystemProvider.js +135 -0
  52. package/dist-lib/components/ui/DesignSystemProvider.js.map +1 -0
  53. package/dist-lib/components/ui/Dialog.d.ts +19 -4
  54. package/dist-lib/components/ui/Dialog.js +165 -0
  55. package/dist-lib/components/ui/Dialog.js.map +1 -0
  56. package/dist-lib/components/ui/Drawer.d.ts +23 -2
  57. package/dist-lib/components/ui/Drawer.js +132 -0
  58. package/dist-lib/components/ui/Drawer.js.map +1 -0
  59. package/dist-lib/components/ui/DropdownMenu.js +169 -0
  60. package/dist-lib/components/ui/DropdownMenu.js.map +1 -0
  61. package/dist-lib/components/ui/EmptyState.d.ts +2 -0
  62. package/dist-lib/components/ui/EmptyState.js +46 -0
  63. package/dist-lib/components/ui/EmptyState.js.map +1 -0
  64. package/dist-lib/components/ui/ErrorState.d.ts +13 -2
  65. package/dist-lib/components/ui/ErrorState.js +69 -0
  66. package/dist-lib/components/ui/ErrorState.js.map +1 -0
  67. package/dist-lib/components/ui/FileUpload.d.ts +3 -0
  68. package/dist-lib/components/ui/FileUpload.js +111 -0
  69. package/dist-lib/components/ui/FileUpload.js.map +1 -0
  70. package/dist-lib/components/ui/Form.d.ts +16 -2
  71. package/dist-lib/components/ui/Form.js +131 -0
  72. package/dist-lib/components/ui/Form.js.map +1 -0
  73. package/dist-lib/components/ui/Icon.d.ts +1 -1
  74. package/dist-lib/components/ui/Icon.js +32 -0
  75. package/dist-lib/components/ui/Icon.js.map +1 -0
  76. package/dist-lib/components/ui/IconButton.d.ts +3 -3
  77. package/dist-lib/components/ui/IconButton.js +64 -0
  78. package/dist-lib/components/ui/IconButton.js.map +1 -0
  79. package/dist-lib/components/ui/Input.d.ts +9 -4
  80. package/dist-lib/components/ui/Input.js +149 -0
  81. package/dist-lib/components/ui/Input.js.map +1 -0
  82. package/dist-lib/components/ui/Kbd.js +24 -0
  83. package/dist-lib/components/ui/Kbd.js.map +1 -0
  84. package/dist-lib/components/ui/MultiSelect.d.ts +3 -1
  85. package/dist-lib/components/ui/MultiSelect.js +210 -0
  86. package/dist-lib/components/ui/MultiSelect.js.map +1 -0
  87. package/dist-lib/components/ui/Pagination.d.ts +23 -0
  88. package/dist-lib/components/ui/Pagination.js +153 -0
  89. package/dist-lib/components/ui/Pagination.js.map +1 -0
  90. package/dist-lib/components/ui/Popover.js +35 -0
  91. package/dist-lib/components/ui/Popover.js.map +1 -0
  92. package/dist-lib/components/ui/Progress.d.ts +3 -3
  93. package/dist-lib/components/ui/Progress.js +100 -0
  94. package/dist-lib/components/ui/Progress.js.map +1 -0
  95. package/dist-lib/components/ui/RadioGroup.d.ts +1 -1
  96. package/dist-lib/components/ui/RadioGroup.js +81 -0
  97. package/dist-lib/components/ui/RadioGroup.js.map +1 -0
  98. package/dist-lib/components/ui/RelativeTime.d.ts +19 -0
  99. package/dist-lib/components/ui/RelativeTime.js +31 -0
  100. package/dist-lib/components/ui/RelativeTime.js.map +1 -0
  101. package/dist-lib/components/ui/ScrollArea.d.ts +9 -1
  102. package/dist-lib/components/ui/ScrollArea.js +60 -0
  103. package/dist-lib/components/ui/ScrollArea.js.map +1 -0
  104. package/dist-lib/components/ui/Select.d.ts +6 -1
  105. package/dist-lib/components/ui/Select.js +139 -0
  106. package/dist-lib/components/ui/Select.js.map +1 -0
  107. package/dist-lib/components/ui/Separator.js +26 -0
  108. package/dist-lib/components/ui/Separator.js.map +1 -0
  109. package/dist-lib/components/ui/Sheet.d.ts +10 -1
  110. package/dist-lib/components/ui/Sheet.js +136 -0
  111. package/dist-lib/components/ui/Sheet.js.map +1 -0
  112. package/dist-lib/components/ui/Sidebar.d.ts +29 -14
  113. package/dist-lib/components/ui/Sidebar.js +212 -0
  114. package/dist-lib/components/ui/Sidebar.js.map +1 -0
  115. package/dist-lib/components/ui/Skeleton.d.ts +13 -2
  116. package/dist-lib/components/ui/Skeleton.js +29 -0
  117. package/dist-lib/components/ui/Skeleton.js.map +1 -0
  118. package/dist-lib/components/ui/Slider.js +64 -0
  119. package/dist-lib/components/ui/Slider.js.map +1 -0
  120. package/dist-lib/components/ui/Snackbar.d.ts +1 -1
  121. package/dist-lib/components/ui/Snackbar.js +57 -0
  122. package/dist-lib/components/ui/Snackbar.js.map +1 -0
  123. package/dist-lib/components/ui/Spinner.js +54 -0
  124. package/dist-lib/components/ui/Spinner.js.map +1 -0
  125. package/dist-lib/components/ui/Stepper.d.ts +6 -0
  126. package/dist-lib/components/ui/Stepper.js +111 -0
  127. package/dist-lib/components/ui/Stepper.js.map +1 -0
  128. package/dist-lib/components/ui/Switch.js +80 -0
  129. package/dist-lib/components/ui/Switch.js.map +1 -0
  130. package/dist-lib/components/ui/Table.d.ts +41 -5
  131. package/dist-lib/components/ui/Table.js +179 -0
  132. package/dist-lib/components/ui/Table.js.map +1 -0
  133. package/dist-lib/components/ui/Tabs.d.ts +1 -1
  134. package/dist-lib/components/ui/Tabs.js +91 -0
  135. package/dist-lib/components/ui/Tabs.js.map +1 -0
  136. package/dist-lib/components/ui/TagInput.d.ts +17 -2
  137. package/dist-lib/components/ui/TagInput.js +111 -0
  138. package/dist-lib/components/ui/TagInput.js.map +1 -0
  139. package/dist-lib/components/ui/Textarea.js +88 -0
  140. package/dist-lib/components/ui/Textarea.js.map +1 -0
  141. package/dist-lib/components/ui/Timeline.d.ts +16 -6
  142. package/dist-lib/components/ui/Timeline.js +56 -0
  143. package/dist-lib/components/ui/Timeline.js.map +1 -0
  144. package/dist-lib/components/ui/Toast.d.ts +1 -1
  145. package/dist-lib/components/ui/Toast.js +158 -0
  146. package/dist-lib/components/ui/Toast.js.map +1 -0
  147. package/dist-lib/components/ui/Tooltip.d.ts +4 -1
  148. package/dist-lib/components/ui/Tooltip.js +60 -0
  149. package/dist-lib/components/ui/Tooltip.js.map +1 -0
  150. package/dist-lib/components/ui/TopNav.d.ts +7 -3
  151. package/dist-lib/components/ui/TopNav.js +62 -0
  152. package/dist-lib/components/ui/TopNav.js.map +1 -0
  153. package/dist-lib/components/ui/Tree.d.ts +34 -7
  154. package/dist-lib/components/ui/Tree.js +170 -0
  155. package/dist-lib/components/ui/Tree.js.map +1 -0
  156. package/dist-lib/hooks/use-debounce.d.ts +19 -0
  157. package/dist-lib/hooks/use-debounce.js +36 -0
  158. package/dist-lib/hooks/use-debounce.js.map +1 -0
  159. package/dist-lib/hooks/use-delayed-loading.d.ts +21 -0
  160. package/dist-lib/hooks/use-delayed-loading.js +20 -0
  161. package/dist-lib/hooks/use-delayed-loading.js.map +1 -0
  162. package/dist-lib/hooks/use-field-ids.d.ts +30 -0
  163. package/dist-lib/hooks/use-field-ids.js +18 -0
  164. package/dist-lib/hooks/use-field-ids.js.map +1 -0
  165. package/dist-lib/hooks/use-media-query.d.ts +3 -1
  166. package/dist-lib/hooks/use-media-query.js +22 -0
  167. package/dist-lib/hooks/use-media-query.js.map +1 -0
  168. package/dist-lib/hooks/use-modifier-key.d.ts +13 -0
  169. package/dist-lib/hooks/use-modifier-key.js +19 -0
  170. package/dist-lib/hooks/use-modifier-key.js.map +1 -0
  171. package/dist-lib/hooks/use-strings.d.ts +5 -0
  172. package/dist-lib/hooks/use-strings.js +12 -0
  173. package/dist-lib/hooks/use-strings.js.map +1 -0
  174. package/dist-lib/hooks/use-toast.d.ts +7 -2
  175. package/dist-lib/hooks/use-toast.js +67 -0
  176. package/dist-lib/hooks/use-toast.js.map +1 -0
  177. package/dist-lib/icon.d.ts +8 -0
  178. package/dist-lib/icon.js +7 -0
  179. package/dist-lib/icon.js.map +1 -0
  180. package/dist-lib/icons/index.d.ts +80 -88
  181. package/dist-lib/icons/index.js +163 -0
  182. package/dist-lib/icons/index.js.map +1 -0
  183. package/dist-lib/illustrations/index.d.ts +1 -0
  184. package/dist-lib/illustrations/index.js +114 -0
  185. package/dist-lib/illustrations/index.js.map +1 -0
  186. package/dist-lib/index.d.ts +68 -59
  187. package/dist-lib/index.js +288 -4530
  188. package/dist-lib/index.js.map +1 -1
  189. package/dist-lib/lib/format.d.ts +65 -0
  190. package/dist-lib/lib/format.js +95 -0
  191. package/dist-lib/lib/format.js.map +1 -0
  192. package/dist-lib/lib/return-focus.d.ts +11 -0
  193. package/dist-lib/lib/return-focus.js +12 -0
  194. package/dist-lib/lib/return-focus.js.map +1 -0
  195. package/dist-lib/lib/strings.d.ts +190 -0
  196. package/dist-lib/lib/strings.js +141 -0
  197. package/dist-lib/lib/strings.js.map +1 -0
  198. package/dist-lib/lib/strings.mn.d.ts +3 -0
  199. package/dist-lib/lib/strings.mn.js +115 -0
  200. package/dist-lib/lib/strings.mn.js.map +1 -0
  201. package/dist-lib/lib/utils.d.ts +0 -1
  202. package/dist-lib/lib/utils.js +10 -0
  203. package/dist-lib/lib/utils.js.map +1 -0
  204. package/dist-lib/styles.css +1 -1
  205. package/dist-lib/theme.css +840 -0
  206. package/package.json +38 -8
  207. package/dist-lib/index.cjs +0 -8
  208. package/dist-lib/index.cjs.map +0 -1
@@ -0,0 +1,111 @@
1
+ "use client";
2
+ import { jsxs as f, jsx as o } from "react/jsx-runtime";
3
+ import { forwardRef as q, useState as k, useCallback as A } from "react";
4
+ import { X as G } from "../../icons/index.js";
5
+ import { cn as m } from "../../lib/utils.js";
6
+ import { useStrings as J } from "../../hooks/use-strings.js";
7
+ import { formatString as L } from "../../lib/strings.js";
8
+ import { useFieldIds as O } from "../../hooks/use-field-ids.js";
9
+ const P = q(function({
10
+ value: s,
11
+ defaultValue: B = [],
12
+ onChange: i,
13
+ label: a,
14
+ hideLabel: E,
15
+ description: l,
16
+ placeholder: D,
17
+ max: g,
18
+ disabled: p,
19
+ error: c,
20
+ separators: S = ["Enter", ","],
21
+ id: b,
22
+ "aria-describedby": T,
23
+ "aria-label": j,
24
+ className: F
25
+ }, K) {
26
+ const [$, z] = k(B), [n, d] = k(""), r = s ?? $, h = J(), x = D ?? h.tagInput.placeholder, u = !!c, v = u && c !== !0, { fieldId: y, helperId: H, errorId: M, describedBy: R } = O(b, {
27
+ hasHelper: !!l,
28
+ hasError: v,
29
+ extra: T
30
+ }), w = A(
31
+ (e) => {
32
+ s === void 0 && z(e), i == null || i(e);
33
+ },
34
+ [i, s]
35
+ ), I = (e) => {
36
+ const t = e.trim();
37
+ !t || r.includes(t) || g !== void 0 && r.length >= g || w([...r, t]);
38
+ }, N = (e) => w(r.filter((t, _) => _ !== e)), X = (e) => {
39
+ S.includes(e.key) ? (e.preventDefault(), I(n), d("")) : e.key === "Backspace" && !n && r.length && N(r.length - 1);
40
+ };
41
+ return /* @__PURE__ */ f("div", { ref: K, className: m("flex flex-col gap-1.5", F), children: [
42
+ a && /* @__PURE__ */ o(
43
+ "label",
44
+ {
45
+ htmlFor: y,
46
+ className: m("text-foreground text-sm font-medium", E && "sr-only"),
47
+ children: a
48
+ }
49
+ ),
50
+ /* @__PURE__ */ f(
51
+ "div",
52
+ {
53
+ className: m(
54
+ // Cap growth at ~3 chip rows and scroll inside — an unbounded field
55
+ // pushes the surrounding layout around as tags are added.
56
+ "bg-card flex max-h-24 min-h-9 w-full flex-wrap items-center gap-1.5 overflow-y-auto rounded-md border px-2 py-1.5",
57
+ "transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out)]",
58
+ "focus-within:ring-offset-background focus-within:ring-2 focus-within:ring-offset-2",
59
+ u ? "border-danger focus-within:border-danger focus-within:ring-danger" : "border-border-input focus-within:border-accent focus-within:ring-ring",
60
+ p && "pointer-events-none opacity-50"
61
+ ),
62
+ children: [
63
+ r.map((e, t) => /* @__PURE__ */ f(
64
+ "span",
65
+ {
66
+ className: "bg-background-muted inline-flex items-center gap-1 rounded-sm px-2 py-0.5 text-xs",
67
+ children: [
68
+ e,
69
+ /* @__PURE__ */ o(
70
+ "button",
71
+ {
72
+ type: "button",
73
+ onClick: () => N(t),
74
+ className: "text-foreground-muted hover:bg-background-subtle hover:text-foreground focus-visible:ring-ring focus-visible:ring-offset-background relative rounded-sm p-0.5 outline-none before:absolute before:-inset-1.5 before:content-[''] focus-visible:ring-2 focus-visible:ring-offset-1",
75
+ "aria-label": L(h.tagInput.remove, { tag: e }),
76
+ children: /* @__PURE__ */ o(G, { className: "size-3", "aria-hidden": !0 })
77
+ }
78
+ )
79
+ ]
80
+ },
81
+ `${e}-${t}`
82
+ )),
83
+ /* @__PURE__ */ o(
84
+ "input",
85
+ {
86
+ id: y,
87
+ value: n,
88
+ disabled: p,
89
+ onChange: (e) => d(e.target.value),
90
+ onKeyDown: X,
91
+ onBlur: () => {
92
+ n && (I(n), d(""));
93
+ },
94
+ placeholder: r.length === 0 ? x : void 0,
95
+ "aria-label": j ?? (a || b ? void 0 : x),
96
+ "aria-invalid": u || void 0,
97
+ "aria-describedby": R,
98
+ className: "placeholder:text-foreground-subtle min-w-[8ch] flex-1 bg-transparent text-lg outline-none md:text-sm"
99
+ }
100
+ )
101
+ ]
102
+ }
103
+ ),
104
+ v ? /* @__PURE__ */ o("p", { id: M, className: "text-danger-text text-xs", children: c }) : l ? /* @__PURE__ */ o("p", { id: H, className: "text-foreground-subtle text-xs", children: l }) : null
105
+ ] });
106
+ });
107
+ P.displayName = "TagInput";
108
+ export {
109
+ P as TagInput
110
+ };
111
+ //# sourceMappingURL=TagInput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TagInput.js","sources":["../../../src/components/ui/TagInput.tsx"],"sourcesContent":["'use client';\n\nimport { forwardRef, useCallback, useState, type KeyboardEvent, type ReactNode } from 'react';\nimport { X } from '@/icons';\nimport { cn } from '@/lib/utils';\nimport { useStrings } from '@/hooks/use-strings';\nimport { formatString } from '@/lib/strings';\nimport { useFieldIds } from '@/hooks/use-field-ids';\n\nexport interface TagInputProps {\n /** Controlled list of tags. */\n value?: string[];\n /** Default tags when uncontrolled. */\n defaultValue?: string[];\n /** Called when the tag list changes. */\n onChange?: (tags: string[]) => void;\n /** Visible label rendered above the field. */\n label?: ReactNode;\n /** Visually conceal the label while keeping it for screen readers. */\n hideLabel?: boolean;\n /** Hint below the field. Hidden while `error` is set. */\n description?: ReactNode;\n /** Placeholder shown inside the inline input. */\n placeholder?: string;\n /** Maximum number of tags. */\n max?: number;\n /** Disable the editor. */\n disabled?: boolean;\n /**\n * Validation state. `true` only paints the danger border; a ReactNode also\n * renders the message below the field and wires `aria-describedby`.\n */\n error?: boolean | ReactNode;\n /** Treat these characters as separators (default: Enter + comma). */\n separators?: string[];\n /** Consumer-supplied id for the inline input. */\n id?: string;\n /** Extra ids to append to `aria-describedby`. */\n 'aria-describedby'?: string;\n 'aria-label'?: string;\n className?: string;\n}\n\n/**\n * Chip-based multi-value input. Press Enter or comma to add. Backspace on an\n * empty input removes the last tag.\n */\nexport const TagInput = forwardRef<HTMLDivElement, TagInputProps>(function TagInput(\n {\n value,\n defaultValue = [],\n onChange,\n label,\n hideLabel,\n description,\n placeholder: placeholderProp,\n max,\n disabled,\n error,\n separators = ['Enter', ','],\n id,\n 'aria-describedby': ariaDescribedby,\n 'aria-label': ariaLabel,\n className,\n },\n ref,\n) {\n const [internal, setInternal] = useState<string[]>(defaultValue);\n const [draft, setDraft] = useState('');\n const tags = value ?? internal;\n\n const strings = useStrings();\n const placeholder = placeholderProp ?? strings.tagInput.placeholder;\n const isError = Boolean(error);\n const hasErrorMessage = isError && error !== true;\n const { fieldId, helperId, errorId, describedBy } = useFieldIds(id, {\n hasHelper: Boolean(description),\n hasError: hasErrorMessage,\n extra: ariaDescribedby,\n });\n\n const update = useCallback(\n (next: string[]) => {\n if (value === undefined) setInternal(next);\n onChange?.(next);\n },\n [onChange, value],\n );\n\n const commit = (raw: string) => {\n const t = raw.trim();\n if (!t || tags.includes(t) || (max !== undefined && tags.length >= max)) return;\n update([...tags, t]);\n };\n\n const remove = (idx: number) => update(tags.filter((_, i) => i !== idx));\n\n const onKey = (e: KeyboardEvent<HTMLInputElement>) => {\n if (separators.includes(e.key)) {\n e.preventDefault();\n commit(draft);\n setDraft('');\n } else if (e.key === 'Backspace' && !draft && tags.length) {\n remove(tags.length - 1);\n }\n };\n\n return (\n <div ref={ref} className={cn('flex flex-col gap-1.5', className)}>\n {label && (\n <label\n htmlFor={fieldId}\n className={cn('text-foreground text-sm font-medium', hideLabel && 'sr-only')}\n >\n {label}\n </label>\n )}\n <div\n className={cn(\n // Cap growth at ~3 chip rows and scroll inside — an unbounded field\n // pushes the surrounding layout around as tags are added.\n 'bg-card flex max-h-24 min-h-9 w-full flex-wrap items-center gap-1.5 overflow-y-auto rounded-md border px-2 py-1.5',\n 'transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out)]',\n 'focus-within:ring-offset-background focus-within:ring-2 focus-within:ring-offset-2',\n isError\n ? 'border-danger focus-within:border-danger focus-within:ring-danger'\n : 'border-border-input focus-within:border-accent focus-within:ring-ring',\n disabled && 'pointer-events-none opacity-50',\n )}\n >\n {tags.map((t, i) => (\n <span\n key={`${t}-${i}`}\n className=\"bg-background-muted inline-flex items-center gap-1 rounded-sm px-2 py-0.5 text-xs\"\n >\n {t}\n <button\n type=\"button\"\n onClick={() => remove(i)}\n // 16px glyph box + halo → ≥24px hit area (WCAG 2.5.8) without growing the chip.\n className=\"text-foreground-muted hover:bg-background-subtle hover:text-foreground focus-visible:ring-ring focus-visible:ring-offset-background relative rounded-sm p-0.5 outline-none before:absolute before:-inset-1.5 before:content-[''] focus-visible:ring-2 focus-visible:ring-offset-1\"\n aria-label={formatString(strings.tagInput.remove, { tag: t })}\n >\n <X className=\"size-3\" aria-hidden />\n </button>\n </span>\n ))}\n <input\n id={fieldId}\n value={draft}\n disabled={disabled}\n onChange={(e) => setDraft(e.target.value)}\n onKeyDown={onKey}\n onBlur={() => {\n if (draft) {\n commit(draft);\n setDraft('');\n }\n }}\n placeholder={tags.length === 0 ? placeholder : undefined}\n // Unlabelled field: fall back to the placeholder. A consumer `id`\n // implies an external <label htmlFor>.\n aria-label={ariaLabel ?? (label || id ? undefined : placeholder)}\n aria-invalid={isError || undefined}\n aria-describedby={describedBy}\n className=\"placeholder:text-foreground-subtle min-w-[8ch] flex-1 bg-transparent text-lg outline-none md:text-sm\"\n />\n </div>\n {hasErrorMessage ? (\n <p id={errorId} className=\"text-danger-text text-xs\">\n {error}\n </p>\n ) : description ? (\n <p id={helperId} className=\"text-foreground-subtle text-xs\">\n {description}\n </p>\n ) : null}\n </div>\n );\n});\nTagInput.displayName = 'TagInput';\n"],"names":["TagInput","forwardRef","value","defaultValue","onChange","label","hideLabel","description","placeholderProp","max","disabled","error","separators","id","ariaDescribedby","ariaLabel","className","ref","internal","setInternal","useState","draft","setDraft","tags","strings","useStrings","placeholder","isError","hasErrorMessage","fieldId","helperId","errorId","describedBy","useFieldIds","update","useCallback","next","commit","raw","remove","idx","_","i","onKey","cn","jsx","jsxs","t","formatString","X"],"mappings":"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"}
@@ -0,0 +1,88 @@
1
+ "use client";
2
+ import { jsxs as Y, jsx as n } from "react/jsx-runtime";
3
+ import { forwardRef as $, useRef as q, useCallback as A, useEffect as H } from "react";
4
+ import { cn as b } from "../../lib/utils.js";
5
+ import { useFieldIds as D } from "../../hooks/use-field-ids.js";
6
+ const G = $(function({
7
+ className: N,
8
+ label: p,
9
+ helperText: a,
10
+ error: i,
11
+ autoResize: r,
12
+ minRows: d = 3,
13
+ maxRows: m = 12,
14
+ hideLabel: E,
15
+ id: T,
16
+ onChange: l,
17
+ value: g,
18
+ defaultValue: x,
19
+ "aria-describedby": j,
20
+ "aria-invalid": c,
21
+ ...k
22
+ }, s) {
23
+ const w = !!i || c === !0 || c === "true", { fieldId: h, helperId: I, errorId: M, describedBy: O } = D(T, {
24
+ hasHelper: !!a,
25
+ hasError: !!i,
26
+ extra: j
27
+ }), f = q(null), W = (e) => {
28
+ f.current = e, typeof s == "function" ? s(e) : s && (s.current = e);
29
+ }, o = A(() => {
30
+ const e = f.current;
31
+ if (!e || !r) return;
32
+ const t = getComputedStyle(e), v = parseFloat(t.lineHeight) || 20, y = (parseFloat(t.paddingTop) || 0) + (parseFloat(t.paddingBottom) || 0), u = (parseFloat(t.borderTopWidth) || 0) + (parseFloat(t.borderBottomWidth) || 0), S = v * d + y + u, F = v * m + y + u;
33
+ e.style.height = "auto";
34
+ const B = e.scrollHeight + u;
35
+ e.style.height = `${Math.min(Math.max(B, S), F)}px`, e.style.overflowY = B > F ? "auto" : "hidden";
36
+ }, [r, d, m]);
37
+ return H(() => {
38
+ r && o();
39
+ }, [r, o, g, x]), H(() => {
40
+ const e = f.current;
41
+ if (!r || !e || typeof ResizeObserver > "u") return;
42
+ const t = new ResizeObserver(() => o());
43
+ return t.observe(e), () => t.disconnect();
44
+ }, [r, o]), /* @__PURE__ */ Y("div", { className: b("flex flex-col gap-1.5", N), children: [
45
+ p && /* @__PURE__ */ n(
46
+ "label",
47
+ {
48
+ htmlFor: h,
49
+ className: b("text-foreground text-sm font-medium", E && "sr-only"),
50
+ children: p
51
+ }
52
+ ),
53
+ /* @__PURE__ */ n(
54
+ "textarea",
55
+ {
56
+ ref: W,
57
+ id: h,
58
+ rows: d,
59
+ value: g,
60
+ defaultValue: x,
61
+ onChange: (e) => {
62
+ l == null || l(e), r && o();
63
+ },
64
+ "aria-invalid": w ? !0 : c,
65
+ "aria-describedby": O,
66
+ className: b(
67
+ "bg-card text-foreground rounded-md border px-3 py-2 text-lg md:text-sm",
68
+ "placeholder:text-foreground-subtle",
69
+ "transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out)]",
70
+ "outline-none",
71
+ "focus-visible:ring-ring focus-visible:ring-2 focus-visible:ring-offset-2",
72
+ "focus-visible:ring-offset-background",
73
+ "disabled:cursor-not-allowed disabled:opacity-50",
74
+ "border-border-input focus-visible:border-accent",
75
+ "aria-invalid:border-danger aria-invalid:focus-visible:border-danger aria-invalid:focus-visible:ring-danger",
76
+ r ? "resize-none" : "min-h-20 resize-y"
77
+ ),
78
+ ...k
79
+ }
80
+ ),
81
+ i ? /* @__PURE__ */ n("p", { id: M, className: "text-danger-text text-xs", children: i }) : a ? /* @__PURE__ */ n("p", { id: I, className: "text-foreground-subtle text-xs", children: a }) : null
82
+ ] });
83
+ });
84
+ G.displayName = "Textarea";
85
+ export {
86
+ G as Textarea
87
+ };
88
+ //# sourceMappingURL=Textarea.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Textarea.js","sources":["../../../src/components/ui/Textarea.tsx"],"sourcesContent":["'use client';\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useRef,\n type TextareaHTMLAttributes,\n type ReactNode,\n} from 'react';\nimport { cn } from '@/lib/utils';\nimport { useFieldIds } from '@/hooks/use-field-ids';\n\nexport interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {\n /** Visible label above the field. */\n label?: ReactNode;\n /** Hint below the field. Hidden when `error` is set. */\n helperText?: ReactNode;\n /** Validation message. Sets `aria-invalid`. */\n error?: ReactNode;\n /** Grow vertically as content is added. */\n autoResize?: boolean;\n /** Minimum rows when `autoResize`. Defaults to 3. */\n minRows?: number;\n /** Maximum rows before scrolling when `autoResize`. Defaults to 12. */\n maxRows?: number;\n /** Visually hide the label while keeping it accessible. */\n hideLabel?: boolean;\n}\n\n/**\n * Multi-line text input. With `autoResize`, height tracks content from\n * `minRows` to `maxRows`. Without it, behaves like a native `<textarea>`.\n *\n * @example Comment box\n * <Textarea label=\"Note\" autoResize minRows={3} maxRows={10} />\n *\n * @example With error\n * <Textarea label=\"Description\"\n * error={errors.description?.message}\n * {...register('description')} />\n *\n * @do Default to `autoResize` for multi-line free-form input.\n * @dont Add `resize-none` without auto-resize — users will be stuck with a\n * 3-line box for long content.\n */\nexport const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(function Textarea(\n {\n className,\n label,\n helperText,\n error,\n autoResize,\n minRows = 3,\n maxRows = 12,\n hideLabel,\n id,\n onChange,\n value,\n defaultValue,\n 'aria-describedby': ariaDescribedby,\n 'aria-invalid': ariaInvalid,\n ...props\n },\n ref,\n) {\n const isError = Boolean(error) || ariaInvalid === true || ariaInvalid === 'true';\n const { fieldId, helperId, errorId, describedBy } = useFieldIds(id, {\n hasHelper: Boolean(helperText),\n hasError: Boolean(error),\n extra: ariaDescribedby,\n });\n const innerRef = useRef<HTMLTextAreaElement | null>(null);\n\n // Stash a ref locally and forward to the consumer.\n const setRef = (node: HTMLTextAreaElement | null) => {\n innerRef.current = node;\n if (typeof ref === 'function') ref(node);\n else if (ref) (ref as React.MutableRefObject<HTMLTextAreaElement | null>).current = node;\n };\n\n const recompute = useCallback(() => {\n const el = innerRef.current;\n if (!el || !autoResize) return;\n const cs = getComputedStyle(el);\n const lineHeight = parseFloat(cs.lineHeight) || 20;\n // scrollHeight includes padding but not borders; the element is border-box.\n const padding = (parseFloat(cs.paddingTop) || 0) + (parseFloat(cs.paddingBottom) || 0);\n const border = (parseFloat(cs.borderTopWidth) || 0) + (parseFloat(cs.borderBottomWidth) || 0);\n const minH = lineHeight * minRows + padding + border;\n const maxH = lineHeight * maxRows + padding + border;\n el.style.height = 'auto';\n const content = el.scrollHeight + border;\n el.style.height = `${Math.min(Math.max(content, minH), maxH)}px`;\n el.style.overflowY = content > maxH ? 'auto' : 'hidden';\n }, [autoResize, minRows, maxRows]);\n\n useEffect(() => {\n if (autoResize) recompute();\n }, [autoResize, recompute, value, defaultValue]);\n\n // Width changes re-wrap the text, so recompute on resize too.\n useEffect(() => {\n const el = innerRef.current;\n if (!autoResize || !el || typeof ResizeObserver === 'undefined') return;\n const ro = new ResizeObserver(() => recompute());\n ro.observe(el);\n return () => ro.disconnect();\n }, [autoResize, recompute]);\n\n return (\n <div className={cn('flex flex-col gap-1.5', className)}>\n {label && (\n <label\n htmlFor={fieldId}\n className={cn('text-foreground text-sm font-medium', hideLabel && 'sr-only')}\n >\n {label}\n </label>\n )}\n <textarea\n ref={setRef}\n id={fieldId}\n rows={minRows}\n value={value}\n defaultValue={defaultValue}\n onChange={(e) => {\n onChange?.(e);\n if (autoResize) recompute();\n }}\n aria-invalid={isError ? true : ariaInvalid}\n aria-describedby={describedBy}\n className={cn(\n 'bg-card text-foreground rounded-md border px-3 py-2 text-lg md:text-sm',\n 'placeholder:text-foreground-subtle',\n 'transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out)]',\n 'outline-none',\n 'focus-visible:ring-ring focus-visible:ring-2 focus-visible:ring-offset-2',\n 'focus-visible:ring-offset-background',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n 'border-border-input focus-visible:border-accent',\n 'aria-invalid:border-danger aria-invalid:focus-visible:border-danger aria-invalid:focus-visible:ring-danger',\n autoResize ? 'resize-none' : 'min-h-20 resize-y',\n )}\n {...props}\n />\n {error ? (\n <p id={errorId} className=\"text-danger-text text-xs\">\n {error}\n </p>\n ) : helperText ? (\n <p id={helperId} className=\"text-foreground-subtle text-xs\">\n {helperText}\n </p>\n ) : null}\n </div>\n );\n});\n\nTextarea.displayName = 'Textarea';\n"],"names":["Textarea","forwardRef","className","label","helperText","error","autoResize","minRows","maxRows","hideLabel","id","onChange","value","defaultValue","ariaDescribedby","ariaInvalid","props","ref","isError","fieldId","helperId","errorId","describedBy","useFieldIds","innerRef","useRef","setRef","node","recompute","useCallback","el","cs","lineHeight","padding","border","minH","maxH","content","useEffect","ro","cn","jsx"],"mappings":"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"}
@@ -1,6 +1,5 @@
1
- import { HTMLAttributes, ReactNode } from 'react';
2
- export interface TimelineProps extends HTMLAttributes<HTMLOListElement> {
3
- }
1
+ import { HTMLAttributes, ReactNode, TimeHTMLAttributes } from 'react';
2
+ export type TimelineProps = HTMLAttributes<HTMLOListElement>;
4
3
  export declare const Timeline: import('react').ForwardRefExoticComponent<TimelineProps & import('react').RefAttributes<HTMLOListElement>>;
5
4
  export interface TimelineItemProps extends HTMLAttributes<HTMLLIElement> {
6
5
  /** Optional bullet override. Default: small accent dot. */
@@ -9,15 +8,26 @@ export interface TimelineItemProps extends HTMLAttributes<HTMLLIElement> {
9
8
  isLast?: boolean;
10
9
  }
11
10
  export declare const TimelineItem: import('react').ForwardRefExoticComponent<TimelineItemProps & import('react').RefAttributes<HTMLLIElement>>;
12
- export declare function TimelineTime({ className, children }: {
13
- className?: string;
11
+ export interface TimelineTimeProps extends TimeHTMLAttributes<HTMLTimeElement> {
12
+ /** Machine-readable value (ISO 8601). Defaults to `children` when it is a string. */
13
+ dateTime?: string;
14
14
  children: ReactNode;
15
- }): import("react/jsx-runtime").JSX.Element;
15
+ }
16
+ export declare function TimelineTime({ className, children, dateTime, ...props }: TimelineTimeProps): import("react/jsx-runtime").JSX.Element;
17
+ export declare namespace TimelineTime {
18
+ var displayName: string;
19
+ }
16
20
  export declare function TimelineTitle({ className, children, }: {
17
21
  className?: string;
18
22
  children: ReactNode;
19
23
  }): import("react/jsx-runtime").JSX.Element;
24
+ export declare namespace TimelineTitle {
25
+ var displayName: string;
26
+ }
20
27
  export declare function TimelineDescription({ className, children, }: {
21
28
  className?: string;
22
29
  children: ReactNode;
23
30
  }): import("react/jsx-runtime").JSX.Element;
31
+ export declare namespace TimelineDescription {
32
+ var displayName: string;
33
+ }
@@ -0,0 +1,56 @@
1
+ "use client";
2
+ import { jsx as t, jsxs as a } from "react/jsx-runtime";
3
+ import { forwardRef as s } from "react";
4
+ import { cn as l } from "../../lib/utils.js";
5
+ const c = s(function({ className: i, children: r, ...n }, m) {
6
+ return /* @__PURE__ */ t("ol", { ref: m, className: l("relative flex flex-col gap-6", i), ...n, children: r });
7
+ });
8
+ c.displayName = "Timeline";
9
+ const u = s(function({ bullet: i, isLast: r, className: n, children: m, ...o }, d) {
10
+ return /* @__PURE__ */ a("li", { ref: d, className: l("relative flex gap-4 pb-1", n), ...o, children: [
11
+ /* @__PURE__ */ a("div", { className: "relative flex shrink-0 flex-col items-center", children: [
12
+ /* @__PURE__ */ t("div", { className: "border-border bg-card text-foreground-muted flex size-6 items-center justify-center rounded-full border", children: i ?? /* @__PURE__ */ t("span", { className: "bg-accent size-2 rounded-full", "aria-hidden": !0 }) }),
13
+ !r && /* @__PURE__ */ t("span", { className: "bg-border mt-1 w-px flex-1", "aria-hidden": !0 })
14
+ ] }),
15
+ /* @__PURE__ */ t("div", { className: "min-w-0 flex-1 pb-4", children: m })
16
+ ] });
17
+ });
18
+ u.displayName = "TimelineItem";
19
+ function f(e) {
20
+ if (!(!e || Number.isNaN(Date.parse(e))))
21
+ return e;
22
+ }
23
+ function p({ className: e, children: i, dateTime: r, ...n }) {
24
+ return /* @__PURE__ */ t(
25
+ "time",
26
+ {
27
+ dateTime: f(r ?? (typeof i == "string" ? i : void 0)),
28
+ className: l("text-foreground-subtle block text-xs", e),
29
+ ...n,
30
+ children: i
31
+ }
32
+ );
33
+ }
34
+ p.displayName = "TimelineTime";
35
+ function x({
36
+ className: e,
37
+ children: i
38
+ }) {
39
+ return /* @__PURE__ */ t("p", { className: l("text-sm font-medium", e), children: i });
40
+ }
41
+ x.displayName = "TimelineTitle";
42
+ function N({
43
+ className: e,
44
+ children: i
45
+ }) {
46
+ return /* @__PURE__ */ t("p", { className: l("text-foreground-muted mt-0.5 text-sm", e), children: i });
47
+ }
48
+ N.displayName = "TimelineDescription";
49
+ export {
50
+ c as Timeline,
51
+ N as TimelineDescription,
52
+ u as TimelineItem,
53
+ p as TimelineTime,
54
+ x as TimelineTitle
55
+ };
56
+ //# sourceMappingURL=Timeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Timeline.js","sources":["../../../src/components/ui/Timeline.tsx"],"sourcesContent":["'use client';\n\nimport { forwardRef, type HTMLAttributes, type ReactNode, type TimeHTMLAttributes } from 'react';\nimport { cn } from '@/lib/utils';\n\nexport type TimelineProps = HTMLAttributes<HTMLOListElement>;\n\nexport const Timeline = forwardRef<HTMLOListElement, TimelineProps>(function Timeline(\n { className, children, ...props },\n ref,\n) {\n return (\n <ol ref={ref} className={cn('relative flex flex-col gap-6', className)} {...props}>\n {children}\n </ol>\n );\n});\nTimeline.displayName = 'Timeline';\n\nexport interface TimelineItemProps extends HTMLAttributes<HTMLLIElement> {\n /** Optional bullet override. Default: small accent dot. */\n bullet?: ReactNode;\n /** Hide the connector line below this item — use for the last item. */\n isLast?: boolean;\n}\n\nexport const TimelineItem = forwardRef<HTMLLIElement, TimelineItemProps>(function TimelineItem(\n { bullet, isLast, className, children, ...props },\n ref,\n) {\n return (\n <li ref={ref} className={cn('relative flex gap-4 pb-1', className)} {...props}>\n <div className=\"relative flex shrink-0 flex-col items-center\">\n <div className=\"border-border bg-card text-foreground-muted flex size-6 items-center justify-center rounded-full border\">\n {bullet ?? <span className=\"bg-accent size-2 rounded-full\" aria-hidden />}\n </div>\n {!isLast && <span className=\"bg-border mt-1 w-px flex-1\" aria-hidden />}\n </div>\n <div className=\"min-w-0 flex-1 pb-4\">{children}</div>\n </li>\n );\n});\nTimelineItem.displayName = 'TimelineItem';\n\nexport interface TimelineTimeProps extends TimeHTMLAttributes<HTMLTimeElement> {\n /** Machine-readable value (ISO 8601). Defaults to `children` when it is a string. */\n dateTime?: string;\n children: ReactNode;\n}\n\n/** Accept only values `Date` can parse — an invalid `dateTime` is worse than none. */\nfunction validDateTime(v: string | undefined): string | undefined {\n if (!v || Number.isNaN(Date.parse(v))) return undefined;\n return v;\n}\n\nexport function TimelineTime({ className, children, dateTime, ...props }: TimelineTimeProps) {\n return (\n <time\n dateTime={validDateTime(dateTime ?? (typeof children === 'string' ? children : undefined))}\n className={cn('text-foreground-subtle block text-xs', className)}\n {...props}\n >\n {children}\n </time>\n );\n}\nTimelineTime.displayName = 'TimelineTime';\n\nexport function TimelineTitle({\n className,\n children,\n}: {\n className?: string;\n children: ReactNode;\n}) {\n return <p className={cn('text-sm font-medium', className)}>{children}</p>;\n}\nTimelineTitle.displayName = 'TimelineTitle';\n\nexport function TimelineDescription({\n className,\n children,\n}: {\n className?: string;\n children: ReactNode;\n}) {\n return <p className={cn('text-foreground-muted mt-0.5 text-sm', className)}>{children}</p>;\n}\nTimelineDescription.displayName = 'TimelineDescription';\n"],"names":["Timeline","forwardRef","className","children","props","ref","jsx","cn","TimelineItem","bullet","isLast","jsxs","validDateTime","v","TimelineTime","dateTime","TimelineTitle","TimelineDescription"],"mappings":";;;;AAOO,MAAMA,IAAWC,EAA4C,SAClE,EAAE,WAAAC,GAAW,UAAAC,GAAU,GAAGC,EAAA,GAC1BC,GACA;AACA,SACE,gBAAAC,EAAC,MAAA,EAAG,KAAAD,GAAU,WAAWE,EAAG,gCAAgCL,CAAS,GAAI,GAAGE,GACzE,UAAAD,EAAA,CACH;AAEJ,CAAC;AACDH,EAAS,cAAc;AAShB,MAAMQ,IAAeP,EAA6C,SACvE,EAAE,QAAAQ,GAAQ,QAAAC,GAAQ,WAAAR,GAAW,UAAAC,GAAU,GAAGC,EAAA,GAC1CC,GACA;AACA,SACE,gBAAAM,EAAC,QAAG,KAAAN,GAAU,WAAWE,EAAG,4BAA4BL,CAAS,GAAI,GAAGE,GACtE,UAAA;AAAA,IAAA,gBAAAO,EAAC,OAAA,EAAI,WAAU,gDACb,UAAA;AAAA,MAAA,gBAAAL,EAAC,OAAA,EAAI,WAAU,2GACZ,UAAAG,KAAU,gBAAAH,EAAC,UAAK,WAAU,iCAAgC,eAAW,GAAA,CAAC,EAAA,CACzE;AAAA,MACC,CAACI,KAAU,gBAAAJ,EAAC,UAAK,WAAU,8BAA6B,eAAW,GAAA,CAAC;AAAA,IAAA,GACvE;AAAA,IACA,gBAAAA,EAAC,OAAA,EAAI,WAAU,uBAAuB,UAAAH,EAAA,CAAS;AAAA,EAAA,GACjD;AAEJ,CAAC;AACDK,EAAa,cAAc;AAS3B,SAASI,EAAcC,GAA2C;AAChE,MAAI,GAACA,KAAK,OAAO,MAAM,KAAK,MAAMA,CAAC,CAAC;AACpC,WAAOA;AACT;AAEO,SAASC,EAAa,EAAE,WAAAZ,GAAW,UAAAC,GAAU,UAAAY,GAAU,GAAGX,KAA4B;AAC3F,SACE,gBAAAE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,UAAUM,EAAcG,MAAa,OAAOZ,KAAa,WAAWA,IAAW,OAAU;AAAA,MACzF,WAAWI,EAAG,wCAAwCL,CAAS;AAAA,MAC9D,GAAGE;AAAA,MAEH,UAAAD;AAAA,IAAA;AAAA,EAAA;AAGP;AACAW,EAAa,cAAc;AAEpB,SAASE,EAAc;AAAA,EAC5B,WAAAd;AAAA,EACA,UAAAC;AACF,GAGG;AACD,2BAAQ,KAAA,EAAE,WAAWI,EAAG,uBAAuBL,CAAS,GAAI,UAAAC,GAAS;AACvE;AACAa,EAAc,cAAc;AAErB,SAASC,EAAoB;AAAA,EAClC,WAAAf;AAAA,EACA,UAAAC;AACF,GAGG;AACD,2BAAQ,KAAA,EAAE,WAAWI,EAAG,wCAAwCL,CAAS,GAAI,UAAAC,GAAS;AACxF;AACAc,EAAoB,cAAc;"}
@@ -1,5 +1,5 @@
1
1
  import { ComponentPropsWithoutRef } from 'react';
2
- import { VariantProps } from '../../lib/cva';
2
+ import { VariantProps } from '../../lib/cva.js';
3
3
  import * as ToastPrimitive from '@radix-ui/react-toast';
4
4
  export declare const ToastProvider: import('react').FC<ToastPrimitive.ToastProviderProps>;
5
5
  export declare const ToastViewport: import('react').ForwardRefExoticComponent<Omit<ToastPrimitive.ToastViewportProps & import('react').RefAttributes<HTMLOListElement>, "ref"> & import('react').RefAttributes<HTMLOListElement>>;
@@ -0,0 +1,158 @@
1
+ "use client";
2
+ import { jsxs as f, jsx as s } from "react/jsx-runtime";
3
+ import { forwardRef as l, useEffect as v } from "react";
4
+ import * as n from "@radix-ui/react-toast";
5
+ import { X as T, Info as w, XCircle as N, AlertTriangle as y, CheckCircle2 as C } from "../../icons/index.js";
6
+ import { cn as c } from "../../lib/utils.js";
7
+ import { useStrings as m } from "../../hooks/use-strings.js";
8
+ import { useToast as k } from "../../hooks/use-toast.js";
9
+ import { cva as z } from "class-variance-authority";
10
+ const A = n.Provider, u = l(function({ className: o, label: e, ...a }, t) {
11
+ const r = m();
12
+ return /* @__PURE__ */ s(
13
+ n.Viewport,
14
+ {
15
+ ref: t,
16
+ label: e ?? r.toast.region,
17
+ className: c(
18
+ "fixed right-0 bottom-0 z-[var(--z-toast)] flex max-h-dvh w-full flex-col-reverse gap-2 p-6",
19
+ // Respect notched/home-indicator insets (consumers set viewport-fit=cover).
20
+ "pr-[max(1.5rem,env(safe-area-inset-right))] pb-[max(1.5rem,env(safe-area-inset-bottom))] pl-[max(1.5rem,env(safe-area-inset-left))]",
21
+ "sm:top-4 sm:right-4 sm:bottom-auto sm:max-w-sm sm:flex-col",
22
+ o
23
+ ),
24
+ ...a
25
+ }
26
+ );
27
+ });
28
+ u.displayName = "ToastViewport";
29
+ const V = z(
30
+ [
31
+ "group pointer-events-auto relative flex w-full items-start gap-3",
32
+ "overflow-hidden rounded-lg border p-4 pr-8 shadow-md",
33
+ "data-[state=open]:animate-in data-[state=closed]:animate-out",
34
+ "data-[state=closed]:fade-out-80 data-[state=open]:slide-in-from-right-full",
35
+ "data-[state=closed]:slide-out-to-right-full",
36
+ "data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)]",
37
+ "data-[swipe=cancel]:translate-x-0 data-[swipe=cancel]:transition-transform",
38
+ "data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)]"
39
+ ],
40
+ {
41
+ variants: {
42
+ variant: {
43
+ default: "border-border bg-card text-card-foreground",
44
+ success: "border-success-border-soft bg-success-soft text-success-text",
45
+ warning: "border-warning-border-soft bg-warning-soft text-warning-text",
46
+ danger: "border-danger-border-soft bg-danger-soft text-danger-text",
47
+ info: "border-info-border-soft bg-info-soft text-info-text"
48
+ }
49
+ },
50
+ defaultVariants: { variant: "default" }
51
+ }
52
+ ), j = {
53
+ default: null,
54
+ success: /* @__PURE__ */ s(C, { className: "text-success-text mt-0.5 size-5 shrink-0", "aria-hidden": !0 }),
55
+ warning: /* @__PURE__ */ s(y, { className: "text-warning-text mt-0.5 size-5 shrink-0", "aria-hidden": !0 }),
56
+ danger: /* @__PURE__ */ s(N, { className: "text-danger-text mt-0.5 size-5 shrink-0", "aria-hidden": !0 }),
57
+ info: /* @__PURE__ */ s(w, { className: "text-info-text mt-0.5 size-5 shrink-0", "aria-hidden": !0 })
58
+ }, p = l(function({ className: o, variant: e = "default", children: a, ...t }, r) {
59
+ return /* @__PURE__ */ f(n.Root, { ref: r, className: c(V({ variant: e }), o), ...t, children: [
60
+ j[e ?? "default"],
61
+ /* @__PURE__ */ s("div", { className: "flex-1 space-y-1", children: a })
62
+ ] });
63
+ });
64
+ p.displayName = "Toast";
65
+ const g = l(function({ className: o, ...e }, a) {
66
+ return /* @__PURE__ */ s(n.Title, { ref: a, className: c("text-sm font-medium", o), ...e });
67
+ });
68
+ g.displayName = "ToastTitle";
69
+ const x = l(function({ className: o, ...e }, a) {
70
+ return /* @__PURE__ */ s(
71
+ n.Description,
72
+ {
73
+ ref: a,
74
+ className: c("text-sm opacity-90", o),
75
+ ...e
76
+ }
77
+ );
78
+ });
79
+ x.displayName = "ToastDescription";
80
+ const b = l(function({ className: o, ...e }, a) {
81
+ return /* @__PURE__ */ s(
82
+ n.Action,
83
+ {
84
+ ref: a,
85
+ className: c(
86
+ "inline-flex h-8 shrink-0 items-center justify-center rounded-md border border-current bg-transparent px-3 text-sm font-medium",
87
+ "transition-colors outline-none hover:bg-current/10",
88
+ "focus-visible:ring-ring focus-visible:ring-offset-card focus-visible:ring-2 focus-visible:ring-offset-2",
89
+ o
90
+ ),
91
+ ...e
92
+ }
93
+ );
94
+ });
95
+ b.displayName = "ToastAction";
96
+ const h = l(function({ className: o, ...e }, a) {
97
+ const t = m();
98
+ return /* @__PURE__ */ s(
99
+ n.Close,
100
+ {
101
+ ref: a,
102
+ "aria-label": e["aria-label"] ?? t.toast.close,
103
+ className: c(
104
+ "text-foreground-subtle absolute top-2 right-2 inline-flex size-7 items-center justify-center rounded-md",
105
+ "hover:text-foreground opacity-0 transition-opacity group-hover:opacity-100",
106
+ "focus-visible:ring-ring focus-visible:ring-offset-card outline-none focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-offset-2",
107
+ o
108
+ ),
109
+ "toast-close": "",
110
+ ...e,
111
+ children: /* @__PURE__ */ s(T, { className: "size-4", "aria-hidden": !0 })
112
+ }
113
+ );
114
+ });
115
+ h.displayName = "ToastClose";
116
+ function D() {
117
+ const { toasts: i, dismiss: o, remove: e } = k();
118
+ v(() => {
119
+ const t = i.filter((d) => !d.open);
120
+ if (t.length === 0) return;
121
+ const r = t.map((d) => window.setTimeout(() => e(d.id), 200));
122
+ return () => r.forEach((d) => window.clearTimeout(d));
123
+ }, [i, e]);
124
+ const a = m();
125
+ return /* @__PURE__ */ f(A, { label: a.toast.region, children: [
126
+ i.map((t) => /* @__PURE__ */ f(
127
+ p,
128
+ {
129
+ variant: t.variant ?? "default",
130
+ open: t.open,
131
+ duration: t.duration === 0 ? 1 / 0 : t.duration,
132
+ onOpenChange: (r) => {
133
+ r || o(t.id);
134
+ },
135
+ children: [
136
+ t.title && /* @__PURE__ */ s(g, { children: t.title }),
137
+ t.description && /* @__PURE__ */ s(x, { children: t.description }),
138
+ t.action && /* @__PURE__ */ s(b, { altText: t.action.altText, onClick: t.action.onClick, className: "mt-1", children: t.action.label }),
139
+ /* @__PURE__ */ s(h, {})
140
+ ]
141
+ },
142
+ t.id
143
+ )),
144
+ /* @__PURE__ */ s(u, {})
145
+ ] });
146
+ }
147
+ D.displayName = "Toaster";
148
+ export {
149
+ p as Toast,
150
+ b as ToastAction,
151
+ h as ToastClose,
152
+ x as ToastDescription,
153
+ A as ToastProvider,
154
+ g as ToastTitle,
155
+ u as ToastViewport,
156
+ D as Toaster
157
+ };
158
+ //# sourceMappingURL=Toast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Toast.js","sources":["../../../src/components/ui/Toast.tsx"],"sourcesContent":["'use client';\n\nimport {\n forwardRef,\n useEffect,\n type ComponentPropsWithoutRef,\n type ElementRef,\n type ReactElement,\n} from 'react';\nimport * as ToastPrimitive from '@radix-ui/react-toast';\nimport { AlertTriangle, CheckCircle2, Info, X, XCircle } from '@/icons';\nimport { cn } from '@/lib/utils';\nimport { useStrings } from '@/hooks/use-strings';\nimport { cva, type VariantProps } from '@/lib/cva';\nimport { useToast } from '@/hooks/use-toast';\n\nexport const ToastProvider = ToastPrimitive.Provider;\n\nexport const ToastViewport = forwardRef<\n ElementRef<typeof ToastPrimitive.Viewport>,\n ComponentPropsWithoutRef<typeof ToastPrimitive.Viewport>\n>(function ToastViewport({ className, label, ...props }, ref) {\n const strings = useStrings();\n return (\n <ToastPrimitive.Viewport\n ref={ref}\n // Radix's default is \"Notifications ({hotkey})\" — route it through the\n // strings so the region landmark is localised like the rest.\n label={label ?? strings.toast.region}\n className={cn(\n 'fixed right-0 bottom-0 z-[var(--z-toast)] flex max-h-dvh w-full flex-col-reverse gap-2 p-6',\n // Respect notched/home-indicator insets (consumers set viewport-fit=cover).\n 'pr-[max(1.5rem,env(safe-area-inset-right))] pb-[max(1.5rem,env(safe-area-inset-bottom))] pl-[max(1.5rem,env(safe-area-inset-left))]',\n 'sm:top-4 sm:right-4 sm:bottom-auto sm:max-w-sm sm:flex-col',\n className,\n )}\n {...props}\n />\n );\n});\nToastViewport.displayName = 'ToastViewport';\n\nconst toast = cva(\n [\n 'group pointer-events-auto relative flex w-full items-start gap-3',\n 'overflow-hidden rounded-lg border p-4 pr-8 shadow-md',\n 'data-[state=open]:animate-in data-[state=closed]:animate-out',\n 'data-[state=closed]:fade-out-80 data-[state=open]:slide-in-from-right-full',\n 'data-[state=closed]:slide-out-to-right-full',\n 'data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)]',\n 'data-[swipe=cancel]:translate-x-0 data-[swipe=cancel]:transition-transform',\n 'data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)]',\n ],\n {\n variants: {\n variant: {\n default: 'border-border bg-card text-card-foreground',\n success: 'border-success-border-soft bg-success-soft text-success-text',\n warning: 'border-warning-border-soft bg-warning-soft text-warning-text',\n danger: 'border-danger-border-soft bg-danger-soft text-danger-text',\n info: 'border-info-border-soft bg-info-soft text-info-text',\n },\n },\n defaultVariants: { variant: 'default' },\n },\n);\n\nconst iconMap = {\n default: null,\n success: <CheckCircle2 className=\"text-success-text mt-0.5 size-5 shrink-0\" aria-hidden />,\n warning: <AlertTriangle className=\"text-warning-text mt-0.5 size-5 shrink-0\" aria-hidden />,\n danger: <XCircle className=\"text-danger-text mt-0.5 size-5 shrink-0\" aria-hidden />,\n info: <Info className=\"text-info-text mt-0.5 size-5 shrink-0\" aria-hidden />,\n} satisfies Record<'default' | 'success' | 'warning' | 'danger' | 'info', ReactElement | null>;\n\nexport interface ToastProps\n extends ComponentPropsWithoutRef<typeof ToastPrimitive.Root>, VariantProps<typeof toast> {}\n\nexport const Toast = forwardRef<ElementRef<typeof ToastPrimitive.Root>, ToastProps>(function Toast(\n { className, variant = 'default', children, ...props },\n ref,\n) {\n return (\n <ToastPrimitive.Root ref={ref} className={cn(toast({ variant }), className)} {...props}>\n {iconMap[variant ?? 'default']}\n <div className=\"flex-1 space-y-1\">{children}</div>\n </ToastPrimitive.Root>\n );\n});\nToast.displayName = 'Toast';\n\nexport const ToastTitle = forwardRef<\n ElementRef<typeof ToastPrimitive.Title>,\n ComponentPropsWithoutRef<typeof ToastPrimitive.Title>\n>(function ToastTitle({ className, ...props }, ref) {\n return (\n <ToastPrimitive.Title ref={ref} className={cn('text-sm font-medium', className)} {...props} />\n );\n});\nToastTitle.displayName = 'ToastTitle';\n\nexport const ToastDescription = forwardRef<\n ElementRef<typeof ToastPrimitive.Description>,\n ComponentPropsWithoutRef<typeof ToastPrimitive.Description>\n>(function ToastDescription({ className, ...props }, ref) {\n return (\n <ToastPrimitive.Description\n ref={ref}\n className={cn('text-sm opacity-90', className)}\n {...props}\n />\n );\n});\nToastDescription.displayName = 'ToastDescription';\n\nexport const ToastAction = forwardRef<\n ElementRef<typeof ToastPrimitive.Action>,\n ComponentPropsWithoutRef<typeof ToastPrimitive.Action>\n>(function ToastAction({ className, ...props }, ref) {\n return (\n <ToastPrimitive.Action\n ref={ref}\n className={cn(\n 'inline-flex h-8 shrink-0 items-center justify-center rounded-md border border-current bg-transparent px-3 text-sm font-medium',\n 'transition-colors outline-none hover:bg-current/10',\n 'focus-visible:ring-ring focus-visible:ring-offset-card focus-visible:ring-2 focus-visible:ring-offset-2',\n className,\n )}\n {...props}\n />\n );\n});\nToastAction.displayName = 'ToastAction';\n\nexport const ToastClose = forwardRef<\n ElementRef<typeof ToastPrimitive.Close>,\n ComponentPropsWithoutRef<typeof ToastPrimitive.Close>\n>(function ToastClose({ className, ...props }, ref) {\n const strings = useStrings();\n return (\n <ToastPrimitive.Close\n ref={ref}\n aria-label={props['aria-label'] ?? strings.toast.close}\n className={cn(\n 'text-foreground-subtle absolute top-2 right-2 inline-flex size-7 items-center justify-center rounded-md',\n 'hover:text-foreground opacity-0 transition-opacity group-hover:opacity-100',\n 'focus-visible:ring-ring focus-visible:ring-offset-card outline-none focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-offset-2',\n className,\n )}\n toast-close=\"\"\n {...props}\n >\n <X className=\"size-4\" aria-hidden />\n </ToastPrimitive.Close>\n );\n});\nToastClose.displayName = 'ToastClose';\n\n/**\n * Drop-in host that connects the `useToast()` queue to the Radix primitives.\n * Mount it once near your app root — then `useToast().push({...})` (or the\n * standalone `toast()`) from anywhere renders here. Self-contained: it brings\n * its own ToastProvider + Viewport, so no other Toast wiring is needed.\n *\n * @example\n * function App() {\n * return (\n * <>\n * <Routes />\n * <Toaster />\n * </>\n * );\n * }\n */\nexport function Toaster() {\n const { toasts, dismiss, remove } = useToast();\n\n // Closing a toast sets open:false so Radix can play the slide-out; drop it\n // from the queue once that animation has had time to finish.\n useEffect(() => {\n const closing = toasts.filter((t) => !t.open);\n if (closing.length === 0) return;\n const timers = closing.map((t) => window.setTimeout(() => remove(t.id), 200));\n return () => timers.forEach((id) => window.clearTimeout(id));\n }, [toasts, remove]);\n\n const strings = useStrings();\n return (\n <ToastProvider label={strings.toast.region}>\n {toasts.map((t) => (\n <Toast\n key={t.id}\n variant={t.variant ?? 'default'}\n open={t.open}\n // Radix treats 0 as \"dismiss immediately\"; the queue's 0 means \"keep open\".\n duration={t.duration === 0 ? Infinity : t.duration}\n onOpenChange={(open) => {\n if (!open) dismiss(t.id);\n }}\n >\n {t.title && <ToastTitle>{t.title}</ToastTitle>}\n {t.description && <ToastDescription>{t.description}</ToastDescription>}\n {t.action && (\n <ToastAction altText={t.action.altText} onClick={t.action.onClick} className=\"mt-1\">\n {t.action.label}\n </ToastAction>\n )}\n <ToastClose />\n </Toast>\n ))}\n <ToastViewport />\n </ToastProvider>\n );\n}\nToaster.displayName = 'Toaster';\n\n/**\n * @example\n * <ToastProvider>\n * …app…\n * <Toast variant=\"success\">\n * <ToastTitle>Saved</ToastTitle>\n * <ToastDescription>Your changes are live.</ToastDescription>\n * <ToastAction altText=\"Undo\">Undo</ToastAction>\n * <ToastClose />\n * </Toast>\n * <ToastViewport />\n * </ToastProvider>\n *\n * @do Use the `useToast()` hook (in `src/hooks/use-toast.ts`) in app code —\n * the components here are the primitives the hook renders.\n * @dont Stack more than two toasts at a time. Newer toasts replace older ones.\n */\n"],"names":["ToastProvider","ToastPrimitive","ToastViewport","forwardRef","className","label","props","ref","strings","useStrings","jsx","cn","toast","cva","iconMap","CheckCircle2","AlertTriangle","XCircle","Info","Toast","variant","children","jsxs","ToastTitle","ToastDescription","ToastAction","ToastClose","X","Toaster","toasts","dismiss","remove","useToast","useEffect","closing","t","timers","id","open"],"mappings":";;;;;;;;;AAgBO,MAAMA,IAAgBC,EAAe,UAE/BC,IAAgBC,EAG3B,SAAuB,EAAE,WAAAC,GAAW,OAAAC,GAAO,GAAGC,EAAA,GAASC,GAAK;AAC5D,QAAMC,IAAUC,EAAA;AAChB,SACE,gBAAAC;AAAA,IAACT,EAAe;AAAA,IAAf;AAAA,MACC,KAAAM;AAAA,MAGA,OAAOF,KAASG,EAAQ,MAAM;AAAA,MAC9B,WAAWG;AAAA,QACT;AAAA;AAAA,QAEA;AAAA,QACA;AAAA,QACAP;AAAA,MAAA;AAAA,MAED,GAAGE;AAAA,IAAA;AAAA,EAAA;AAGV,CAAC;AACDJ,EAAc,cAAc;AAE5B,MAAMU,IAAQC;AAAA,EACZ;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAAA,EAEF;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,SAAS;AAAA,QACT,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,MAAM;AAAA,MAAA;AAAA,IACR;AAAA,IAEF,iBAAiB,EAAE,SAAS,UAAA;AAAA,EAAU;AAE1C,GAEMC,IAAU;AAAA,EACd,SAAS;AAAA,EACT,SAAS,gBAAAJ,EAACK,GAAA,EAAa,WAAU,4CAA2C,eAAW,IAAC;AAAA,EACxF,SAAS,gBAAAL,EAACM,GAAA,EAAc,WAAU,4CAA2C,eAAW,IAAC;AAAA,EACzF,QAAQ,gBAAAN,EAACO,GAAA,EAAQ,WAAU,2CAA0C,eAAW,IAAC;AAAA,EACjF,MAAM,gBAAAP,EAACQ,GAAA,EAAK,WAAU,yCAAwC,eAAW,GAAA,CAAC;AAC5E,GAKaC,IAAQhB,EAA+D,SAClF,EAAE,WAAAC,GAAW,SAAAgB,IAAU,WAAW,UAAAC,GAAU,GAAGf,EAAA,GAC/CC,GACA;AACA,SACE,gBAAAe,EAACrB,EAAe,MAAf,EAAoB,KAAAM,GAAU,WAAWI,EAAGC,EAAM,EAAE,SAAAQ,GAAS,GAAGhB,CAAS,GAAI,GAAGE,GAC9E,UAAA;AAAA,IAAAQ,EAAQM,KAAW,SAAS;AAAA,IAC7B,gBAAAV,EAAC,OAAA,EAAI,WAAU,oBAAoB,UAAAW,EAAA,CAAS;AAAA,EAAA,GAC9C;AAEJ,CAAC;AACDF,EAAM,cAAc;AAEb,MAAMI,IAAapB,EAGxB,SAAoB,EAAE,WAAAC,GAAW,GAAGE,EAAA,GAASC,GAAK;AAClD,SACE,gBAAAG,EAACT,EAAe,OAAf,EAAqB,KAAAM,GAAU,WAAWI,EAAG,uBAAuBP,CAAS,GAAI,GAAGE,EAAA,CAAO;AAEhG,CAAC;AACDiB,EAAW,cAAc;AAElB,MAAMC,IAAmBrB,EAG9B,SAA0B,EAAE,WAAAC,GAAW,GAAGE,EAAA,GAASC,GAAK;AACxD,SACE,gBAAAG;AAAA,IAACT,EAAe;AAAA,IAAf;AAAA,MACC,KAAAM;AAAA,MACA,WAAWI,EAAG,sBAAsBP,CAAS;AAAA,MAC5C,GAAGE;AAAA,IAAA;AAAA,EAAA;AAGV,CAAC;AACDkB,EAAiB,cAAc;AAExB,MAAMC,IAActB,EAGzB,SAAqB,EAAE,WAAAC,GAAW,GAAGE,EAAA,GAASC,GAAK;AACnD,SACE,gBAAAG;AAAA,IAACT,EAAe;AAAA,IAAf;AAAA,MACC,KAAAM;AAAA,MACA,WAAWI;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACAP;AAAA,MAAA;AAAA,MAED,GAAGE;AAAA,IAAA;AAAA,EAAA;AAGV,CAAC;AACDmB,EAAY,cAAc;AAEnB,MAAMC,IAAavB,EAGxB,SAAoB,EAAE,WAAAC,GAAW,GAAGE,EAAA,GAASC,GAAK;AAClD,QAAMC,IAAUC,EAAA;AAChB,SACE,gBAAAC;AAAA,IAACT,EAAe;AAAA,IAAf;AAAA,MACC,KAAAM;AAAA,MACA,cAAYD,EAAM,YAAY,KAAKE,EAAQ,MAAM;AAAA,MACjD,WAAWG;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACAP;AAAA,MAAA;AAAA,MAEF,eAAY;AAAA,MACX,GAAGE;AAAA,MAEJ,UAAA,gBAAAI,EAACiB,GAAA,EAAE,WAAU,UAAS,eAAW,GAAA,CAAC;AAAA,IAAA;AAAA,EAAA;AAGxC,CAAC;AACDD,EAAW,cAAc;AAkBlB,SAASE,IAAU;AACxB,QAAM,EAAE,QAAAC,GAAQ,SAAAC,GAAS,QAAAC,EAAA,IAAWC,EAAA;AAIpC,EAAAC,EAAU,MAAM;AACd,UAAMC,IAAUL,EAAO,OAAO,CAACM,MAAM,CAACA,EAAE,IAAI;AAC5C,QAAID,EAAQ,WAAW,EAAG;AAC1B,UAAME,IAASF,EAAQ,IAAI,CAACC,MAAM,OAAO,WAAW,MAAMJ,EAAOI,EAAE,EAAE,GAAG,GAAG,CAAC;AAC5E,WAAO,MAAMC,EAAO,QAAQ,CAACC,MAAO,OAAO,aAAaA,CAAE,CAAC;AAAA,EAC7D,GAAG,CAACR,GAAQE,CAAM,CAAC;AAEnB,QAAMvB,IAAUC,EAAA;AAChB,SACE,gBAAAa,EAACtB,GAAA,EAAc,OAAOQ,EAAQ,MAAM,QACjC,UAAA;AAAA,IAAAqB,EAAO,IAAI,CAAC,MACX,gBAAAP;AAAA,MAACH;AAAA,MAAA;AAAA,QAEC,SAAS,EAAE,WAAW;AAAA,QACtB,MAAM,EAAE;AAAA,QAER,UAAU,EAAE,aAAa,IAAI,QAAW,EAAE;AAAA,QAC1C,cAAc,CAACmB,MAAS;AACtB,UAAKA,KAAMR,EAAQ,EAAE,EAAE;AAAA,QACzB;AAAA,QAEC,UAAA;AAAA,UAAA,EAAE,SAAS,gBAAApB,EAACa,GAAA,EAAY,UAAA,EAAE,OAAM;AAAA,UAChC,EAAE,eAAe,gBAAAb,EAACc,GAAA,EAAkB,YAAE,aAAY;AAAA,UAClD,EAAE,UACD,gBAAAd,EAACe,GAAA,EAAY,SAAS,EAAE,OAAO,SAAS,SAAS,EAAE,OAAO,SAAS,WAAU,QAC1E,UAAA,EAAE,OAAO,OACZ;AAAA,4BAEDC,GAAA,CAAA,CAAW;AAAA,QAAA;AAAA,MAAA;AAAA,MAhBP,EAAE;AAAA,IAAA,CAkBV;AAAA,sBACAxB,GAAA,CAAA,CAAc;AAAA,EAAA,GACjB;AAEJ;AACA0B,EAAQ,cAAc;"}
@@ -4,7 +4,10 @@ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
4
4
  * Wrap the app in a single `<TooltipProvider>` near the root. All Tooltips
5
5
  * share the same `delayDuration` and `skipDelayDuration`.
6
6
  */
7
- export declare const TooltipProvider: ({ delayDuration, skipDelayDuration, ...props }: ComponentPropsWithoutRef<typeof TooltipPrimitive.Provider>) => import("react/jsx-runtime").JSX.Element;
7
+ export declare const TooltipProvider: {
8
+ ({ delayDuration, skipDelayDuration, ...props }: ComponentPropsWithoutRef<typeof TooltipPrimitive.Provider>): import("react/jsx-runtime").JSX.Element;
9
+ displayName: string;
10
+ };
8
11
  export declare const TooltipRoot: import('react').FC<TooltipPrimitive.TooltipProps>;
9
12
  export declare const TooltipTrigger: import('react').ForwardRefExoticComponent<TooltipPrimitive.TooltipTriggerProps & import('react').RefAttributes<HTMLButtonElement>>;
10
13
  export declare const TooltipContent: import('react').ForwardRefExoticComponent<Omit<TooltipPrimitive.TooltipContentProps & import('react').RefAttributes<HTMLDivElement>, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,60 @@
1
+ "use client";
2
+ import { jsx as o, Fragment as p, jsxs as l } from "react/jsx-runtime";
3
+ import { forwardRef as m } from "react";
4
+ import * as a from "@radix-ui/react-tooltip";
5
+ import { cn as c } from "../../lib/utils.js";
6
+ const f = ({
7
+ delayDuration: t = 500,
8
+ skipDelayDuration: e = 200,
9
+ ...i
10
+ }) => /* @__PURE__ */ o(
11
+ a.Provider,
12
+ {
13
+ delayDuration: t,
14
+ skipDelayDuration: e,
15
+ ...i
16
+ }
17
+ );
18
+ f.displayName = "TooltipProvider";
19
+ const u = a.Root, T = a.Trigger, d = m(function({ className: e, sideOffset: i = 4, ...r }, n) {
20
+ return /* @__PURE__ */ o(a.Portal, { children: /* @__PURE__ */ o(
21
+ a.Content,
22
+ {
23
+ ref: n,
24
+ sideOffset: i,
25
+ className: c(
26
+ "z-[var(--z-tooltip)] overflow-hidden rounded-md px-2 py-1 text-xs font-medium",
27
+ "bg-tooltip text-tooltip-foreground",
28
+ "max-w-xs shadow-sm",
29
+ "data-[state=open]:animate-in data-[state=closed]:animate-out",
30
+ "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
31
+ "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
32
+ e
33
+ ),
34
+ ...r
35
+ }
36
+ ) });
37
+ });
38
+ d.displayName = "TooltipContent";
39
+ function x({
40
+ children: t,
41
+ label: e,
42
+ side: i = "top",
43
+ align: r = "center",
44
+ disabled: n,
45
+ delayDuration: s
46
+ }) {
47
+ return n ? /* @__PURE__ */ o(p, { children: t }) : /* @__PURE__ */ l(u, { delayDuration: s, children: [
48
+ /* @__PURE__ */ o(T, { asChild: !0, children: t }),
49
+ /* @__PURE__ */ o(d, { side: i, align: r, children: e })
50
+ ] });
51
+ }
52
+ x.displayName = "Tooltip";
53
+ export {
54
+ x as Tooltip,
55
+ d as TooltipContent,
56
+ f as TooltipProvider,
57
+ u as TooltipRoot,
58
+ T as TooltipTrigger
59
+ };
60
+ //# sourceMappingURL=Tooltip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tooltip.js","sources":["../../../src/components/ui/Tooltip.tsx"],"sourcesContent":["'use client';\n\nimport { forwardRef, type ComponentPropsWithoutRef, type ElementRef, type ReactNode } from 'react';\nimport * as TooltipPrimitive from '@radix-ui/react-tooltip';\nimport { cn } from '@/lib/utils';\n\n/**\n * Wrap the app in a single `<TooltipProvider>` near the root. All Tooltips\n * share the same `delayDuration` and `skipDelayDuration`.\n */\nexport const TooltipProvider = ({\n delayDuration = 500,\n skipDelayDuration = 200,\n ...props\n}: ComponentPropsWithoutRef<typeof TooltipPrimitive.Provider>) => (\n <TooltipPrimitive.Provider\n delayDuration={delayDuration}\n skipDelayDuration={skipDelayDuration}\n {...props}\n />\n);\nTooltipProvider.displayName = 'TooltipProvider';\n\nexport const TooltipRoot = TooltipPrimitive.Root;\nexport const TooltipTrigger = TooltipPrimitive.Trigger;\n\nexport const TooltipContent = forwardRef<\n ElementRef<typeof TooltipPrimitive.Content>,\n ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>\n>(function TooltipContent({ className, sideOffset = 4, ...props }, ref) {\n return (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n 'z-[var(--z-tooltip)] overflow-hidden rounded-md px-2 py-1 text-xs font-medium',\n 'bg-tooltip text-tooltip-foreground',\n 'max-w-xs shadow-sm',\n 'data-[state=open]:animate-in data-[state=closed]:animate-out',\n 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',\n 'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',\n className,\n )}\n {...props}\n />\n </TooltipPrimitive.Portal>\n );\n});\nTooltipContent.displayName = 'TooltipContent';\n\nexport interface TooltipProps {\n children: ReactNode;\n label: ReactNode;\n side?: 'top' | 'right' | 'bottom' | 'left';\n align?: 'start' | 'center' | 'end';\n /** Disable showing the tooltip (e.g. when text is not truncated). */\n disabled?: boolean;\n /** Override the global delay. */\n delayDuration?: number;\n}\n\n/**\n * Shorthand for the most common Tooltip case.\n *\n * @example\n * <Tooltip label=\"Copy link\"><IconButton aria-label=\"Copy\" icon={<Copy/>} /></Tooltip>\n *\n * @do Keep tooltip text short — one line, no full sentences. Use a Popover\n * for any content that needs structure.\n * @dont Wrap disabled buttons in Tooltip without `asChild + tabIndex={0}`.\n * Disabled elements don't receive focus, so the tooltip never opens.\n */\nexport function Tooltip({\n children,\n label,\n side = 'top',\n align = 'center',\n disabled,\n delayDuration,\n}: TooltipProps) {\n if (disabled) return <>{children}</>;\n return (\n <TooltipRoot delayDuration={delayDuration}>\n <TooltipTrigger asChild>{children}</TooltipTrigger>\n <TooltipContent side={side} align={align}>\n {label}\n </TooltipContent>\n </TooltipRoot>\n );\n}\nTooltip.displayName = 'Tooltip';\n"],"names":["TooltipProvider","delayDuration","skipDelayDuration","props","jsx","TooltipPrimitive","TooltipRoot","TooltipTrigger","TooltipContent","forwardRef","className","sideOffset","ref","cn","Tooltip","children","label","side","align","disabled","Fragment","jsxs"],"mappings":";;;;;AAUO,MAAMA,IAAkB,CAAC;AAAA,EAC9B,eAAAC,IAAgB;AAAA,EAChB,mBAAAC,IAAoB;AAAA,EACpB,GAAGC;AACL,MACE,gBAAAC;AAAA,EAACC,EAAiB;AAAA,EAAjB;AAAA,IACC,eAAAJ;AAAA,IACA,mBAAAC;AAAA,IACC,GAAGC;AAAA,EAAA;AACN;AAEFH,EAAgB,cAAc;AAEvB,MAAMM,IAAcD,EAAiB,MAC/BE,IAAiBF,EAAiB,SAElCG,IAAiBC,EAG5B,SAAwB,EAAE,WAAAC,GAAW,YAAAC,IAAa,GAAG,GAAGR,EAAA,GAASS,GAAK;AACtE,SACE,gBAAAR,EAACC,EAAiB,QAAjB,EACC,UAAA,gBAAAD;AAAA,IAACC,EAAiB;AAAA,IAAjB;AAAA,MACC,KAAAO;AAAA,MACA,YAAAD;AAAA,MACA,WAAWE;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACAH;AAAA,MAAA;AAAA,MAED,GAAGP;AAAA,IAAA;AAAA,EAAA,GAER;AAEJ,CAAC;AACDK,EAAe,cAAc;AAwBtB,SAASM,EAAQ;AAAA,EACtB,UAAAC;AAAA,EACA,OAAAC;AAAA,EACA,MAAAC,IAAO;AAAA,EACP,OAAAC,IAAQ;AAAA,EACR,UAAAC;AAAA,EACA,eAAAlB;AACF,GAAiB;AACf,SAAIkB,IAAiB,gBAAAf,EAAAgB,GAAA,EAAG,UAAAL,EAAA,CAAS,IAE/B,gBAAAM,EAACf,KAAY,eAAAL,GACX,UAAA;AAAA,IAAA,gBAAAG,EAACG,GAAA,EAAe,SAAO,IAAE,UAAAQ,EAAA,CAAS;AAAA,IAClC,gBAAAX,EAACI,GAAA,EAAe,MAAAS,GAAY,OAAAC,GACzB,UAAAF,EAAA,CACH;AAAA,EAAA,GACF;AAEJ;AACAF,EAAQ,cAAc;"}