@lerianstudio/sindarian-ui 2.0.0-beta.2 → 2.0.0-beta.20

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 (211) hide show
  1. package/LICENSE +93 -0
  2. package/README.md +52 -1
  3. package/dist/components/breadcrumb/index.d.ts.map +1 -1
  4. package/dist/components/breadcrumb/index.js +25 -1
  5. package/dist/components/card/account-card/index.js +5 -5
  6. package/dist/components/card/basic-card/index.d.ts.map +1 -1
  7. package/dist/components/card/basic-card/index.js +2 -2
  8. package/dist/components/card/entity-card/index.js +1 -1
  9. package/dist/components/dialog/confirmation-dialog/index.d.ts.map +1 -1
  10. package/dist/components/dialog/confirmation-dialog/index.js +4 -1
  11. package/dist/components/entity-box/index.d.ts +18 -2
  12. package/dist/components/entity-box/index.d.ts.map +1 -1
  13. package/dist/components/entity-box/index.js +32 -4
  14. package/dist/components/form/date-picker-field/index.js +1 -1
  15. package/dist/components/form/date-range-field/index.js +1 -1
  16. package/dist/components/form/date-time-picker-field/index.js +1 -1
  17. package/dist/components/form/password-field/index.d.ts +5 -1
  18. package/dist/components/form/password-field/index.d.ts.map +1 -1
  19. package/dist/components/form/password-field/index.js +2 -2
  20. package/dist/components/form/select-field/index.d.ts +15 -1
  21. package/dist/components/form/select-field/index.d.ts.map +1 -1
  22. package/dist/components/form/select-field/index.js +28 -3
  23. package/dist/components/form/switch-field/index.d.ts.map +1 -1
  24. package/dist/components/form/switch-field/index.js +6 -1
  25. package/dist/components/page/index.d.ts +35 -1
  26. package/dist/components/page/index.d.ts.map +1 -1
  27. package/dist/components/page/index.js +6 -2
  28. package/dist/components/page-header/index.js +1 -1
  29. package/dist/components/table/id-table-cell.d.ts +13 -1
  30. package/dist/components/table/id-table-cell.d.ts.map +1 -1
  31. package/dist/components/table/id-table-cell.js +99 -9
  32. package/dist/components/table/index.d.ts +1 -0
  33. package/dist/components/table/index.d.ts.map +1 -1
  34. package/dist/components/table/index.js +1 -0
  35. package/dist/components/table/locked-table-actions.d.ts +24 -0
  36. package/dist/components/table/locked-table-actions.d.ts.map +1 -1
  37. package/dist/components/table/locked-table-actions.js +31 -1
  38. package/dist/components/table/name-table-cell.d.ts +57 -4
  39. package/dist/components/table/name-table-cell.d.ts.map +1 -1
  40. package/dist/components/table/name-table-cell.js +50 -2
  41. package/dist/components/ui/autocomplete/index.d.ts +24 -0
  42. package/dist/components/ui/autocomplete/index.d.ts.map +1 -1
  43. package/dist/components/ui/autocomplete/index.js +24 -0
  44. package/dist/components/ui/badge/index.d.ts +11 -7
  45. package/dist/components/ui/badge/index.d.ts.map +1 -1
  46. package/dist/components/ui/badge/index.js +20 -8
  47. package/dist/components/ui/button/index.d.ts +3 -3
  48. package/dist/components/ui/copy-field/index.d.ts +25 -1
  49. package/dist/components/ui/copy-field/index.d.ts.map +1 -1
  50. package/dist/components/ui/copy-field/index.js +16 -8
  51. package/dist/components/ui/dialog/index.d.ts +1 -1
  52. package/dist/components/ui/dialog/index.d.ts.map +1 -1
  53. package/dist/components/ui/dialog/index.js +2 -2
  54. package/dist/components/ui/file-upload/index.d.ts +159 -0
  55. package/dist/components/ui/file-upload/index.d.ts.map +1 -1
  56. package/dist/components/ui/file-upload/index.js +308 -6
  57. package/dist/components/ui/icon-button/index.d.ts +1 -1
  58. package/dist/components/ui/icon-button/styles.css +42 -0
  59. package/dist/components/ui/input/styles.css +79 -4
  60. package/dist/components/ui/otp-input/index.js +1 -1
  61. package/dist/components/ui/radio-group/index.js +1 -1
  62. package/dist/components/ui/select/index.d.ts.map +1 -1
  63. package/dist/components/ui/select/index.js +8 -4
  64. package/dist/components/ui/select/styles.css +1 -1
  65. package/dist/components/ui/sheet/index.d.ts +42 -0
  66. package/dist/components/ui/sheet/index.d.ts.map +1 -1
  67. package/dist/components/ui/sheet/index.js +47 -14
  68. package/dist/components/ui/sidebar/index.d.ts +1 -0
  69. package/dist/components/ui/sidebar/index.d.ts.map +1 -1
  70. package/dist/components/ui/sidebar/index.js +1 -0
  71. package/dist/components/ui/sidebar/sidebar-expand-button.d.ts +1 -1
  72. package/dist/components/ui/sidebar/sidebar-expand-button.d.ts.map +1 -1
  73. package/dist/components/ui/sidebar/sidebar-expand-button.js +15 -1
  74. package/dist/components/ui/sidebar/sidebar-item.d.ts +1 -1
  75. package/dist/components/ui/sidebar/sidebar-item.d.ts.map +1 -1
  76. package/dist/components/ui/sidebar/sidebar-item.js +28 -4
  77. package/dist/components/ui/sidebar/sidebar-provider.d.ts +58 -0
  78. package/dist/components/ui/sidebar/sidebar-provider.d.ts.map +1 -1
  79. package/dist/components/ui/sidebar/sidebar-provider.js +146 -4
  80. package/dist/components/ui/sidebar/sidebar-root.d.ts +38 -1
  81. package/dist/components/ui/sidebar/sidebar-root.d.ts.map +1 -1
  82. package/dist/components/ui/sidebar/sidebar-root.js +111 -5
  83. package/dist/components/ui/sidebar/sidebar-trigger.d.ts +45 -0
  84. package/dist/components/ui/sidebar/sidebar-trigger.d.ts.map +1 -0
  85. package/dist/components/ui/sidebar/sidebar-trigger.js +57 -0
  86. package/dist/components/ui/textarea/index.js +1 -1
  87. package/dist/components/ui/toast/toaster.d.ts +5 -1
  88. package/dist/components/ui/toast/toaster.d.ts.map +1 -1
  89. package/dist/components/ui/toast/toaster.js +3 -2
  90. package/dist/enterprise/data-table/index.d.ts +77 -7
  91. package/dist/enterprise/data-table/index.d.ts.map +1 -1
  92. package/dist/enterprise/data-table/index.js +56 -11
  93. package/dist/enterprise/date-range-picker/index.js +4 -4
  94. package/dist/enterprise/number-input/index.d.ts.map +1 -1
  95. package/dist/enterprise/number-input/index.js +1 -1
  96. package/dist/esm/components/breadcrumb/index.d.ts.map +1 -1
  97. package/dist/esm/components/breadcrumb/index.js +25 -1
  98. package/dist/esm/components/card/account-card/index.js +5 -5
  99. package/dist/esm/components/card/basic-card/index.d.ts.map +1 -1
  100. package/dist/esm/components/card/basic-card/index.js +2 -2
  101. package/dist/esm/components/card/entity-card/index.js +1 -1
  102. package/dist/esm/components/dialog/confirmation-dialog/index.d.ts.map +1 -1
  103. package/dist/esm/components/dialog/confirmation-dialog/index.js +4 -1
  104. package/dist/esm/components/entity-box/index.d.ts +18 -2
  105. package/dist/esm/components/entity-box/index.d.ts.map +1 -1
  106. package/dist/esm/components/entity-box/index.js +29 -4
  107. package/dist/esm/components/form/date-picker-field/index.js +1 -1
  108. package/dist/esm/components/form/date-range-field/index.js +1 -1
  109. package/dist/esm/components/form/date-time-picker-field/index.js +1 -1
  110. package/dist/esm/components/form/password-field/index.d.ts +5 -1
  111. package/dist/esm/components/form/password-field/index.d.ts.map +1 -1
  112. package/dist/esm/components/form/password-field/index.js +2 -2
  113. package/dist/esm/components/form/select-field/index.d.ts +15 -1
  114. package/dist/esm/components/form/select-field/index.d.ts.map +1 -1
  115. package/dist/esm/components/form/select-field/index.js +29 -4
  116. package/dist/esm/components/form/switch-field/index.d.ts.map +1 -1
  117. package/dist/esm/components/form/switch-field/index.js +7 -2
  118. package/dist/esm/components/page/index.d.ts +35 -1
  119. package/dist/esm/components/page/index.d.ts.map +1 -1
  120. package/dist/esm/components/page/index.js +6 -2
  121. package/dist/esm/components/page-header/index.js +1 -1
  122. package/dist/esm/components/table/id-table-cell.d.ts +13 -1
  123. package/dist/esm/components/table/id-table-cell.d.ts.map +1 -1
  124. package/dist/esm/components/table/id-table-cell.js +100 -7
  125. package/dist/esm/components/table/index.d.ts +1 -0
  126. package/dist/esm/components/table/index.d.ts.map +1 -1
  127. package/dist/esm/components/table/index.js +1 -0
  128. package/dist/esm/components/table/locked-table-actions.d.ts +24 -0
  129. package/dist/esm/components/table/locked-table-actions.d.ts.map +1 -1
  130. package/dist/esm/components/table/locked-table-actions.js +31 -1
  131. package/dist/esm/components/table/name-table-cell.d.ts +57 -4
  132. package/dist/esm/components/table/name-table-cell.d.ts.map +1 -1
  133. package/dist/esm/components/table/name-table-cell.js +50 -2
  134. package/dist/esm/components/ui/autocomplete/index.d.ts +24 -0
  135. package/dist/esm/components/ui/autocomplete/index.d.ts.map +1 -1
  136. package/dist/esm/components/ui/autocomplete/index.js +24 -0
  137. package/dist/esm/components/ui/badge/index.d.ts +11 -7
  138. package/dist/esm/components/ui/badge/index.d.ts.map +1 -1
  139. package/dist/esm/components/ui/badge/index.js +20 -8
  140. package/dist/esm/components/ui/button/index.d.ts +3 -3
  141. package/dist/esm/components/ui/copy-field/index.d.ts +25 -1
  142. package/dist/esm/components/ui/copy-field/index.d.ts.map +1 -1
  143. package/dist/esm/components/ui/copy-field/index.js +16 -8
  144. package/dist/esm/components/ui/dialog/index.d.ts +1 -1
  145. package/dist/esm/components/ui/dialog/index.d.ts.map +1 -1
  146. package/dist/esm/components/ui/dialog/index.js +3 -3
  147. package/dist/esm/components/ui/file-upload/index.d.ts +159 -0
  148. package/dist/esm/components/ui/file-upload/index.d.ts.map +1 -1
  149. package/dist/esm/components/ui/file-upload/index.js +307 -5
  150. package/dist/esm/components/ui/icon-button/index.d.ts +1 -1
  151. package/dist/esm/components/ui/otp-input/index.js +1 -1
  152. package/dist/esm/components/ui/radio-group/index.js +1 -1
  153. package/dist/esm/components/ui/select/index.d.ts.map +1 -1
  154. package/dist/esm/components/ui/select/index.js +8 -4
  155. package/dist/esm/components/ui/sheet/index.d.ts +42 -0
  156. package/dist/esm/components/ui/sheet/index.d.ts.map +1 -1
  157. package/dist/esm/components/ui/sheet/index.js +48 -15
  158. package/dist/esm/components/ui/sidebar/index.d.ts +1 -0
  159. package/dist/esm/components/ui/sidebar/index.d.ts.map +1 -1
  160. package/dist/esm/components/ui/sidebar/index.js +1 -0
  161. package/dist/esm/components/ui/sidebar/sidebar-expand-button.d.ts +1 -1
  162. package/dist/esm/components/ui/sidebar/sidebar-expand-button.d.ts.map +1 -1
  163. package/dist/esm/components/ui/sidebar/sidebar-expand-button.js +15 -1
  164. package/dist/esm/components/ui/sidebar/sidebar-item.d.ts +1 -1
  165. package/dist/esm/components/ui/sidebar/sidebar-item.d.ts.map +1 -1
  166. package/dist/esm/components/ui/sidebar/sidebar-item.js +28 -4
  167. package/dist/esm/components/ui/sidebar/sidebar-provider.d.ts +58 -0
  168. package/dist/esm/components/ui/sidebar/sidebar-provider.d.ts.map +1 -1
  169. package/dist/esm/components/ui/sidebar/sidebar-provider.js +143 -1
  170. package/dist/esm/components/ui/sidebar/sidebar-root.d.ts +38 -1
  171. package/dist/esm/components/ui/sidebar/sidebar-root.d.ts.map +1 -1
  172. package/dist/esm/components/ui/sidebar/sidebar-root.js +113 -7
  173. package/dist/esm/components/ui/sidebar/sidebar-trigger.d.ts +45 -0
  174. package/dist/esm/components/ui/sidebar/sidebar-trigger.d.ts.map +1 -0
  175. package/dist/esm/components/ui/sidebar/sidebar-trigger.js +53 -0
  176. package/dist/esm/components/ui/textarea/index.js +1 -1
  177. package/dist/esm/components/ui/toast/toaster.d.ts +5 -1
  178. package/dist/esm/components/ui/toast/toaster.d.ts.map +1 -1
  179. package/dist/esm/components/ui/toast/toaster.js +3 -2
  180. package/dist/esm/enterprise/data-table/index.d.ts +77 -7
  181. package/dist/esm/enterprise/data-table/index.d.ts.map +1 -1
  182. package/dist/esm/enterprise/data-table/index.js +57 -12
  183. package/dist/esm/enterprise/date-range-picker/index.js +4 -4
  184. package/dist/esm/enterprise/number-input/index.d.ts.map +1 -1
  185. package/dist/esm/enterprise/number-input/index.js +1 -1
  186. package/dist/esm/hooks/use-toast.d.ts +18 -2
  187. package/dist/esm/hooks/use-toast.d.ts.map +1 -1
  188. package/dist/esm/hooks/use-toast.js +60 -16
  189. package/dist/esm/index.d.ts +2 -0
  190. package/dist/esm/index.d.ts.map +1 -1
  191. package/dist/esm/index.js +2 -0
  192. package/dist/esm/lib/utils.d.ts +2 -0
  193. package/dist/esm/lib/utils.d.ts.map +1 -1
  194. package/dist/esm/lib/utils.js +10 -0
  195. package/dist/esm/toast/helpers.d.ts +13 -0
  196. package/dist/esm/toast/helpers.d.ts.map +1 -1
  197. package/dist/esm/toast/helpers.js +8 -1
  198. package/dist/globals.css +81 -31
  199. package/dist/hooks/use-toast.d.ts +18 -2
  200. package/dist/hooks/use-toast.d.ts.map +1 -1
  201. package/dist/hooks/use-toast.js +61 -16
  202. package/dist/index.d.ts +2 -0
  203. package/dist/index.d.ts.map +1 -1
  204. package/dist/index.js +2 -0
  205. package/dist/lib/utils.d.ts +2 -0
  206. package/dist/lib/utils.d.ts.map +1 -1
  207. package/dist/lib/utils.js +11 -0
  208. package/dist/toast/helpers.d.ts +13 -0
  209. package/dist/toast/helpers.d.ts.map +1 -1
  210. package/dist/toast/helpers.js +8 -1
  211. package/package.json +7 -4
@@ -210,5 +210,5 @@ export function NumberInput({ value, onValueChange, min, max, step = 1, precisio
210
210
  };
211
211
  const atMin = typeof min === 'number' && value !== null && value <= min;
212
212
  const atMax = typeof max === 'number' && value !== null && value >= max;
213
- return (_jsxs("div", { className: cn('inline-flex items-stretch gap-1', className), children: [_jsx(IconButton, { type: "button", variant: "outline", disabled: disabled || atMin, "aria-label": `Decrease${ariaLabel ? ` ${ariaLabel}` : ''}`, onClick: () => stepBy(-1), tabIndex: -1, children: _jsx(Minus, { className: "size-4", "aria-hidden": true }) }), _jsx("div", { className: "w-28", children: _jsx(Input, { id: id, inputMode: "decimal", role: "spinbutton", "aria-valuenow": value ?? undefined, "aria-valuemin": min, "aria-valuemax": max, className: "text-right tabular-nums", value: displayValue, placeholder: placeholder, disabled: disabled, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, onChange: onChange, onKeyDown: onKeyDown, onFocus: onFocus, onBlur: onBlur }) }), _jsx(IconButton, { type: "button", variant: "outline", disabled: disabled || atMax, "aria-label": `Increase${ariaLabel ? ` ${ariaLabel}` : ''}`, onClick: () => stepBy(1), tabIndex: -1, children: _jsx(Plus, { className: "size-4", "aria-hidden": true }) })] }));
213
+ return (_jsxs("div", { className: cn('inline-flex items-stretch gap-1', className), children: [_jsx(IconButton, { className: "shrink-0", type: "button", variant: "outline", disabled: disabled || atMin, "aria-label": `Decrease${ariaLabel ? ` ${ariaLabel}` : ''}`, onClick: () => stepBy(-1), tabIndex: -1, children: _jsx(Minus, { className: "size-4", "aria-hidden": true }) }), _jsx("div", { className: "w-28 min-w-0", children: _jsx(Input, { id: id, inputMode: "decimal", role: "spinbutton", "aria-valuenow": value ?? undefined, "aria-valuemin": min, "aria-valuemax": max, className: "text-right tabular-nums", value: displayValue, placeholder: placeholder, disabled: disabled, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, onChange: onChange, onKeyDown: onKeyDown, onFocus: onFocus, onBlur: onBlur }) }), _jsx(IconButton, { className: "shrink-0", type: "button", variant: "outline", disabled: disabled || atMax, "aria-label": `Increase${ariaLabel ? ` ${ariaLabel}` : ''}`, onClick: () => stepBy(1), tabIndex: -1, children: _jsx(Plus, { className: "size-4", "aria-hidden": true }) })] }));
214
214
  }
@@ -1,4 +1,10 @@
1
1
  import type { ToastActionElement } from '../components/ui/toast/index.js';
2
+ /**
3
+ * Lifetime of every non-destructive toast, and the `<Toaster />` fallback for
4
+ * anything raised without one. The two must not drift apart, so the Toaster
5
+ * imports this rather than repeating the literal.
6
+ */
7
+ export declare const DEFAULT_DURATION = 10000;
2
8
  type ToastVariant = 'default' | 'success' | 'warning' | 'destructive';
3
9
  type ToasterToast = {
4
10
  id: string | number;
@@ -6,9 +12,19 @@ type ToasterToast = {
6
12
  description?: React.ReactNode;
7
13
  variant?: ToastVariant;
8
14
  action?: ToastActionElement;
15
+ /**
16
+ * Auto-dismiss delay in ms, which must be greater than 0: sonner resolves it
17
+ * as `toast.duration || toasterDuration || default`, so `0` reads as unset
18
+ * and the toast silently takes the `<Toaster />` default instead of closing
19
+ * at once. Omit it to take the variant's own lifetime: `destructive` stays
20
+ * until dismissed, every other variant closes after 10s.
21
+ */
22
+ duration?: number;
23
+ };
24
+ type Toast = Omit<ToasterToast, 'id'> & {
25
+ id?: ToasterToast['id'];
9
26
  };
10
- type Toast = Omit<ToasterToast, 'id'>;
11
- declare function toast({ title, description, variant, ...rest }: Toast): {
27
+ declare function toast({ title, description, variant, duration, id, ...rest }: Toast): {
12
28
  id: string | number;
13
29
  dismiss: () => string | number;
14
30
  update: (props: Partial<ToasterToast>) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"use-toast.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-toast.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAI/D,KAAK,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAA;AAErE,KAAK,YAAY,GAAG;IAClB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB,MAAM,CAAC,EAAE,kBAAkB,CAAA;CAC5B,CAAA;AAED,KAAK,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;AAErC,iBAAS,KAAK,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,EAAE,KAAK;;;oBA+B1C,OAAO,CAAC,YAAY,CAAC;EAQxC;AAED;;;;;;;GAOG;AACH,iBAAS,QAAQ;;wBAGO,MAAM,GAAG,MAAM;YAOrB,YAAY,EAAE;EAE/B;AAED,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;AAC1B,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,CAAA"}
1
+ {"version":3,"file":"use-toast.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-toast.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAE/D;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,QAAQ,CAAA;AAerC,KAAK,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAA;AAErE,KAAK,YAAY,GAAG;IAClB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB,MAAM,CAAC,EAAE,kBAAkB,CAAA;IAC3B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,KAAK,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,GAAG;IAAE,EAAE,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAA;CAAE,CAAA;AAiCnE,iBAAS,KAAK,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,EAAE,KAAK;;;oBAsCxD,OAAO,CAAC,YAAY,CAAC;EASxC;AAED;;;;;;;GAOG;AACH,iBAAS,QAAQ;;wBAGO,MAAM,GAAG,MAAM;YAOrB,YAAY,EAAE;EAE/B;AAED,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;AAC1B,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,CAAA"}
@@ -1,39 +1,83 @@
1
1
  'use client';
2
2
  import { toast as sonnerToast } from 'sonner';
3
- const DEFAULT_DURATION = 10000;
4
- function toast({ title, description, variant, ...rest }) {
3
+ /**
4
+ * Lifetime of every non-destructive toast, and the `<Toaster />` fallback for
5
+ * anything raised without one. The two must not drift apart, so the Toaster
6
+ * imports this rather than repeating the literal.
7
+ */
8
+ export const DEFAULT_DURATION = 10000;
9
+ /**
10
+ * A destructive toast reports something the operator has to read -- a refused
11
+ * money operation, a failed copy of a show-once secret, a language switch that
12
+ * did not take. It stays up until dismissed instead of auto-closing.
13
+ *
14
+ * `Infinity` is how sonner disables the auto-close timer (it short-circuits the
15
+ * timer effect rather than calling `setTimeout(fn, Infinity)`, which would fire
16
+ * immediately). `<Toaster />` already passes `closeButton`, and sonner gates the
17
+ * close button on that flag alone, never on the duration -- so a persistent
18
+ * toast still renders its dismiss affordance.
19
+ */
20
+ const PERSIST_UNTIL_DISMISSED = Infinity;
21
+ const isPlainText = (value) => value === undefined || typeof value === 'string';
22
+ /**
23
+ * Two identical errors share one toast instead of stacking: same variant, same
24
+ * text -- same id, and sonner updates the one already on screen.
25
+ *
26
+ * Unbounded stacking is worse for a persistent toast than for a transient one.
27
+ * `<Toaster />` shows three at a time and renders the rest `opacity: 0;
28
+ * pointer-events: none`, so a fourth error nobody can read is also a fourth
29
+ * error nobody can close -- and without an auto-dismiss, nothing ahead of it
30
+ * clears on its own.
31
+ *
32
+ * Only plain-text toasts collapse. A `ReactNode` has no stable key and
33
+ * `String(node)` would fold unrelated errors onto one id.
34
+ *
35
+ * ponytail: the ceiling is still three. Distinct persistent errors past the
36
+ * third queue behind the front three until one is dismissed; lifting that means
37
+ * raising `visibleToasts`, not more work here.
38
+ */
39
+ function collapseKey(title, description) {
40
+ if (!isPlainText(title) || !isPlainText(description)) {
41
+ return undefined;
42
+ }
43
+ return `destructive:${JSON.stringify([title ?? null, description ?? null])}`;
44
+ }
45
+ function toast({ title, description, variant, duration, id, ...rest }) {
5
46
  const message = title ?? '';
47
+ const toastId = variant === 'destructive' && id === undefined
48
+ ? collapseKey(title, description)
49
+ : id;
6
50
  const options = {
7
51
  description,
8
- ...rest
52
+ ...rest,
53
+ ...(toastId !== undefined && { id: toastId }),
54
+ duration: duration ??
55
+ (variant === 'destructive' ? PERSIST_UNTIL_DISMISSED : DEFAULT_DURATION)
9
56
  };
10
- let id;
57
+ let raisedId;
11
58
  switch (variant) {
12
59
  case 'success':
13
- options.duration = DEFAULT_DURATION;
14
- id = sonnerToast.success(message, options);
60
+ raisedId = sonnerToast.success(message, options);
15
61
  break;
16
62
  case 'warning':
17
- options.duration = DEFAULT_DURATION;
18
- id = sonnerToast.warning(message, options);
63
+ raisedId = sonnerToast.warning(message, options);
19
64
  break;
20
65
  case 'destructive':
21
- options.duration = DEFAULT_DURATION;
22
- id = sonnerToast.error(message, options);
66
+ raisedId = sonnerToast.error(message, options);
23
67
  break;
24
68
  default:
25
- options.duration = DEFAULT_DURATION;
26
- id = sonnerToast(message, options);
69
+ raisedId = sonnerToast(message, options);
27
70
  break;
28
71
  }
29
72
  return {
30
- id,
31
- dismiss: () => sonnerToast.dismiss(id),
73
+ id: raisedId,
74
+ dismiss: () => sonnerToast.dismiss(raisedId),
32
75
  update: (props) => {
33
76
  sonnerToast(props.title ?? message, {
34
- id,
77
+ ...rest,
78
+ id: raisedId,
35
79
  description: props.description ?? description,
36
- ...rest
80
+ duration: props.duration ?? options.duration
37
81
  });
38
82
  }
39
83
  };
@@ -1,5 +1,6 @@
1
1
  export * from './components/ui/alert/index.js';
2
2
  export * from './components/ui/autocomplete/index.js';
3
+ export * from './hooks/use-click-away.js';
3
4
  export * from './components/ui/autosize-textarea/index.js';
4
5
  export * from './components/ui/avatar/index.js';
5
6
  export * from './components/ui/badge/index.js';
@@ -39,6 +40,7 @@ export * from './components/ui/toast/index.js';
39
40
  export * from './components/ui/toast/toaster.js';
40
41
  export * from './hooks/use-toast.js';
41
42
  export * from './components/ui/time-picker/index.js';
43
+ export * from './hooks/use-time.js';
42
44
  export * from './components/ui/tooltip/index.js';
43
45
  export * from './components/ui/form.js';
44
46
  export { Breadcrumb as ApplicationBreadcrumb } from './components/breadcrumb/index.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAGA,cAAc,uBAAuB,CAAA;AACrC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,mCAAmC,CAAA;AACjD,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,wBAAwB,CAAA;AACtC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,0BAA0B,CAAA;AACxC,cAAc,sBAAsB,CAAA;AACpC,cAAc,0BAA0B,CAAA;AACxC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,yBAAyB,CAAA;AACvC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,wBAAwB,CAAA;AACtC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,uBAAuB,CAAA;AACrC,cAAc,2BAA2B,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,uBAAuB,CAAA;AACrC,cAAc,mCAAmC,CAAA;AACjD,cAAc,yBAAyB,CAAA;AACvC,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,wBAAwB,CAAA;AACtC,cAAc,2BAA2B,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,cAAc,yBAAyB,CAAA;AACvC,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,qBAAqB,CAAA;AACnC,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA;AACpC,cAAc,0BAA0B,CAAA;AACxC,cAAc,uBAAuB,CAAA;AACrC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,mBAAmB,CAAA;AACjC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,yBAAyB,CAAA;AACvC,cAAc,sBAAsB,CAAA;AAGpC,OAAO,EAAE,UAAU,IAAI,qBAAqB,EAAE,MAAM,yBAAyB,CAAA;AAC7E,cAAc,8CAA8C,CAAA;AAC5D,cAAc,mBAAmB,CAAA;AACjC,cAAc,qBAAqB,CAAA;AACnC,cAAc,yBAAyB,CAAA;AACvC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,oBAAoB,CAAA;AAGlC,cAAc,cAAc,CAAA;AAC5B,cAAc,SAAS,CAAA;AACvB,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AAGxB,cAAc,2BAA2B,CAAA;AACzC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,8BAA8B,CAAA;AAG5C,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA;AAChC,cAAc,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAGA,cAAc,uBAAuB,CAAA;AACrC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,wBAAwB,CAAA;AACtC,cAAc,mCAAmC,CAAA;AACjD,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,wBAAwB,CAAA;AACtC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,0BAA0B,CAAA;AACxC,cAAc,sBAAsB,CAAA;AACpC,cAAc,0BAA0B,CAAA;AACxC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,yBAAyB,CAAA;AACvC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,wBAAwB,CAAA;AACtC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,uBAAuB,CAAA;AACrC,cAAc,2BAA2B,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,uBAAuB,CAAA;AACrC,cAAc,mCAAmC,CAAA;AACjD,cAAc,yBAAyB,CAAA;AACvC,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,wBAAwB,CAAA;AACtC,cAAc,2BAA2B,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,cAAc,yBAAyB,CAAA;AACvC,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,qBAAqB,CAAA;AACnC,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA;AACpC,cAAc,0BAA0B,CAAA;AACxC,cAAc,uBAAuB,CAAA;AACrC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,mBAAmB,CAAA;AACjC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,kBAAkB,CAAA;AAChC,cAAc,yBAAyB,CAAA;AACvC,cAAc,sBAAsB,CAAA;AAGpC,OAAO,EAAE,UAAU,IAAI,qBAAqB,EAAE,MAAM,yBAAyB,CAAA;AAC7E,cAAc,8CAA8C,CAAA;AAC5D,cAAc,mBAAmB,CAAA;AACjC,cAAc,qBAAqB,CAAA;AACnC,cAAc,yBAAyB,CAAA;AACvC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,oBAAoB,CAAA;AAGlC,cAAc,cAAc,CAAA;AAC5B,cAAc,SAAS,CAAA;AACvB,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AAGxB,cAAc,2BAA2B,CAAA;AACzC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,8BAA8B,CAAA;AAG5C,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA;AAChC,cAAc,kBAAkB,CAAA"}
package/dist/esm/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
  // Primitives
3
3
  export * from './components/ui/alert/index.js';
4
4
  export * from './components/ui/autocomplete/index.js';
5
+ export * from './hooks/use-click-away.js';
5
6
  export * from './components/ui/autosize-textarea/index.js';
6
7
  export * from './components/ui/avatar/index.js';
7
8
  export * from './components/ui/badge/index.js';
@@ -41,6 +42,7 @@ export * from './components/ui/toast/index.js';
41
42
  export * from './components/ui/toast/toaster.js';
42
43
  export * from './hooks/use-toast.js';
43
44
  export * from './components/ui/time-picker/index.js';
45
+ export * from './hooks/use-time.js';
44
46
  export * from './components/ui/tooltip/index.js';
45
47
  export * from './components/ui/form.js';
46
48
  // Components
@@ -1,3 +1,5 @@
1
1
  import { type ClassValue } from 'clsx';
2
2
  export declare function cn(...inputs: ClassValue[]): string;
3
+ /** Wraps a Radix `onInteractOutside` so a press on a toast never dismisses the layer under it. */
4
+ export declare function keepOpenOnToast<E extends Event>(onInteractOutside?: (event: E) => void): (event: E) => void;
3
5
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/lib/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAQ,MAAM,MAAM,CAAA;AA8B5C,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,UAEzC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/lib/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAQ,MAAM,MAAM,CAAA;AA8B5C,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,UAEzC;AAED,kGAAkG;AAClG,wBAAgB,eAAe,CAAC,CAAC,SAAS,KAAK,EAC7C,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,IAE9B,OAAO,CAAC,UASjB"}
@@ -29,3 +29,13 @@ const twMerge = extendTailwindMerge({
29
29
  export function cn(...inputs) {
30
30
  return twMerge(clsx(inputs));
31
31
  }
32
+ /** Wraps a Radix `onInteractOutside` so a press on a toast never dismisses the layer under it. */
33
+ export function keepOpenOnToast(onInteractOutside) {
34
+ return (event) => {
35
+ if (event.target?.closest('[data-sonner-toaster]')) {
36
+ event.preventDefault();
37
+ return;
38
+ }
39
+ onInteractOutside?.(event);
40
+ };
41
+ }
@@ -1,6 +1,12 @@
1
1
  import type { ToastActionElement } from '../components/ui/toast/index.js';
2
2
  /** Extra toast props for the severity helpers (the variant is fixed per helper). */
3
3
  export interface ToastOptions {
4
+ /**
5
+ * Caller-controlled toast identity. A repeat under the same id updates the
6
+ * toast in place instead of stacking a second one; omit it and a destructive
7
+ * toast derives its own from the title and description.
8
+ */
9
+ id?: string | number;
4
10
  /** Optional action element rendered inside the toast. */
5
11
  action?: ToastActionElement;
6
12
  /**
@@ -9,6 +15,13 @@ export interface ToastOptions {
9
15
  * it, so it is not rendered. Put it in `description` if it must be visible.
10
16
  */
11
17
  errorCode?: string;
18
+ /**
19
+ * Auto-dismiss delay in ms, overriding the variant's own lifetime for this
20
+ * one call. Must be greater than 0 -- sonner reads `0` as unset and falls
21
+ * back to the `<Toaster />` default. Omit it and `errorToast` stays until
22
+ * dismissed while `successToast` and `warningToast` close after 10s.
23
+ */
24
+ duration?: number;
12
25
  }
13
26
  export declare function successToast(title: string, description?: string, opts?: Partial<ToastOptions>): void;
14
27
  export declare function errorToast(title: string, description?: string, opts?: Partial<ToastOptions>): void;
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/toast/helpers.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAE/D,oFAAoF;AACpF,MAAM,WAAW,YAAY;IAC3B,yDAAyD;IACzD,MAAM,CAAC,EAAE,kBAAkB,CAAA;IAC3B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAWD,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,IAAI,CAEN;AAED,wBAAgB,UAAU,CACxB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,IAAI,CAEN;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,IAAI,CAEN"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/toast/helpers.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAE/D,oFAAoF;AACpF,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACpB,yDAAyD;IACzD,MAAM,CAAC,EAAE,kBAAkB,CAAA;IAC3B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAkBD,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,IAAI,CAEN;AAED,wBAAgB,UAAU,CACxB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,IAAI,CAEN;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,IAAI,CAEN"}
@@ -16,7 +16,14 @@
16
16
  */
17
17
  import { toast } from '../hooks/use-toast.js';
18
18
  function raise(variant, title, description, opts) {
19
- toast({ action: opts?.action, variant, title, description });
19
+ toast({
20
+ action: opts?.action,
21
+ variant,
22
+ title,
23
+ description,
24
+ duration: opts?.duration,
25
+ id: opts?.id
26
+ });
20
27
  }
21
28
  export function successToast(title, description, opts) {
22
29
  raise('success', title, description, opts);
package/dist/globals.css CHANGED
@@ -214,6 +214,28 @@
214
214
  :root {
215
215
  color-scheme: light; /* native widgets (form controls, scrollbars) follow the theme */
216
216
 
217
+ /*
218
+ Sidebar geometry. These were literals inside SidebarRoot's cva
219
+ (`w-[244px]` / `w-[72px]`), which a consumer could only override by
220
+ winning a specificity argument with `cn`. As custom properties the
221
+ default still ships with this sheet.
222
+
223
+ TWO places to re-point them, and only these two:
224
+ - on the rail, via `className="[--sidebar-width:280px]"`. SidebarRoot
225
+ copies exactly these two arbitrary-property classes onto the mobile
226
+ drawer's own element, so one class moves the rail AND the drawer.
227
+ - on `:root` or `html`, which every layout inherits from.
228
+
229
+ NOT on a React-tree wrapper above the rail: that reaches the rail, but
230
+ the mobile drawer is portalled into document.body, and custom properties
231
+ inherit down the DOM tree. A wrapper is not an ancestor of the portal;
232
+ `:root` is.
233
+
234
+ They are theme-independent on purpose: a rail is not wider in the dark.
235
+ */
236
+ --sidebar-width: 244px;
237
+ --sidebar-width-collapsed: 72px;
238
+
217
239
  /* Application tokens (from Figma ring-tokens) */
218
240
  --body-surface: 240 5% 96%; /* base/100 = #F4F4F5 */
219
241
  /*
@@ -294,6 +316,9 @@
294
316
  here claimed 4.4:1 was acceptable "on the shadcn-100 field", which named
295
317
  a fill the component never paints. */
296
318
  --input-placeholder: 240 4% 45%; /* one notch off base/500: #6E6E77, AA on body-surface */
319
+ /* Field boundary, held to the 3:1 non-text floor (SC 1.4.11) on every ground a
320
+ field sits on. base/400 read 2.56:1 on white and 2.34:1 on --body-surface. */
321
+ --input-border: 240 4% 46%; /* base/500 = #71717A, 4.86:1 on white, 4.43:1 on body-surface */
297
322
  /*
298
323
  Focus ring. base/400 read 2.55:1 on white and 2.33:1 on --body-surface,
299
324
  under the 3:1 floor a focus indicator answers to (SC 1.4.11), and this is
@@ -444,6 +469,7 @@
444
469
  dark field that is already only 5.8:1, and going lighter here means
445
470
  darker, which would push the hint under the AA floor. */
446
471
  --input-placeholder: 240 5% 80%; /* between base/400 and base/300: #C9C9CF, AA on card (6.3:1); base/400 read 4.07:1 there */
472
+ --input-border: 240 5% 65%; /* base/400 = #A1A1AA, 4.09:1 on card; light's base/500 reads 2.15:1 there */
447
473
  /* Held at base/400, which light had to leave: on this ground the two
448
474
  directions disagree. base/400 reads 5.81:1 on --background and 4.08:1 on
449
475
  --card here, while light's base/500 would read 2.16:1 on --card. */
@@ -541,7 +567,7 @@
541
567
  }
542
568
  }
543
569
 
544
- /* Sonner toast overrides — solid bold backgrounds (Radix parity) */
570
+ /* Sonner toast overrides — tinted surfaces from the system token families */
545
571
  [data-sonner-toaster] {
546
572
  --width: 420px;
547
573
  pointer-events: auto !important;
@@ -559,41 +585,41 @@
559
585
  }
560
586
 
561
587
  /*
562
- Type fills come from the system token families, so a toast themes with the
563
- rest of the app. All three coloured types take ONE ink, --accent-foreground:
564
- a solid system fill is bright enough to need near-black ink in BOTH themes,
565
- and that token is the only one in this sheet that is near-black in both.
566
-
567
- It replaced the per-family reasoning that stood here, which routed success
568
- and error through --primary-foreground because that token inverts (white in
569
- light, base/800 in dark). Inverting was the bug: white ink on the LIGHT
570
- fills measured 3.35:1 on --system-success and 3.78:1 on --system-error,
571
- both under AA, and no token value can fix that from the white side — the
572
- light green/600 and red/500 fills sit mid-luminance, so white caps at ~3.8
573
- while near-black reaches 5.9 and 5.3. Ratios now, ink over fill:
574
- light 5.93 / 5.25 / 11.17 and dark 11.39 / 7.23 / 13.00
575
- (success / error / warning). The dark pairs were already passing at
576
- 8.51 / 5.41 / 13.00 and only gained. `toast ink` in
577
- src/__tests__/tokens-contract.test.ts recomputes all six from these
578
- declarations, so the next token edit that drops a pair under 4.5 fails
579
- instead of shipping.
588
+ Each coloured type paints the `surface` + `text` + `border` trio of its own
589
+ family — the pairing every other tinted component in the kit already uses
590
+ (`components/ui/badge/index.tsx`, `enterprise/alert-banner/index.tsx`).
591
+ `surface` is the only slot in a system family built to sit BEHIND content: it
592
+ darkens on the dark canvas, while `base` and `h1a` are fill and ink slots
593
+ that INVERT between themes (`--system-success-h1a` is #166534 in light and
594
+ #BBF7D0 in dark). Grounding toast text on either of those forces a different
595
+ ink per theme, and the toast stops tracking the family it names.
596
+
597
+ Ink over ground, light / dark: success 6.81 / 10.62, error 7.60 / 8.51,
598
+ warning 6.62 / 11.70 — every half clear of the 4.5 floor by more than two
599
+ points. `system text tokens` in `src/__tests__/tokens-contract.test.ts`
600
+ already measures this pair for all five families, so the toast is covered by
601
+ the gate that guards the pills rather than by a rule written for it alone;
602
+ `sonner toast ink` there reads whichever pair these rules declare.
603
+
604
+ `info` stays neutral on `--card`: an informational toast is the unstyled
605
+ case, not a fourth colour.
580
606
  */
581
607
  [data-sonner-toast][data-type='success'] {
582
- --normal-bg: hsl(var(--system-success));
583
- --normal-text: hsl(var(--accent-foreground));
584
- --normal-border: transparent;
608
+ --normal-bg: hsl(var(--system-success-surface));
609
+ --normal-text: hsl(var(--system-success-text));
610
+ --normal-border: hsl(var(--system-success-border));
585
611
  }
586
612
 
587
613
  [data-sonner-toast][data-type='error'] {
588
- --normal-bg: hsl(var(--system-error));
589
- --normal-text: hsl(var(--accent-foreground));
590
- --normal-border: transparent;
614
+ --normal-bg: hsl(var(--system-error-surface));
615
+ --normal-text: hsl(var(--system-error-text));
616
+ --normal-border: hsl(var(--system-error-border));
591
617
  }
592
618
 
593
619
  [data-sonner-toast][data-type='warning'] {
594
- --normal-bg: hsl(var(--system-alert));
595
- --normal-text: hsl(var(--accent-foreground));
596
- --normal-border: transparent;
620
+ --normal-bg: hsl(var(--system-alert-surface));
621
+ --normal-text: hsl(var(--system-alert-text));
622
+ --normal-border: hsl(var(--system-alert-border));
597
623
  }
598
624
 
599
625
  [data-sonner-toast][data-type='info'] {
@@ -602,8 +628,32 @@
602
628
  --normal-border: hsl(var(--border));
603
629
  }
604
630
 
605
- [data-sonner-toast] [data-title] {
606
- font-weight: 600;
631
+ /*
632
+ The title outranks the description, and both rules have to WIN the cascade
633
+ for that to mean anything. Sonner ships
634
+ `[data-sonner-toast][data-styled='true'] [data-title]` at font-weight 500 and
635
+ its description twin at 400 — both (0,3,0), both injected at runtime.
636
+ The title rule here was a plain `[data-sonner-toast] [data-title]` (0,2,0):
637
+ it declared 600 and rendered at 500, losing outright, while the description
638
+ carried `!important` and rendered at 600. The hierarchy came out inverted on
639
+ every toast in the kit, the long line heavier than the label naming it.
640
+
641
+ Both now take the compound selector plus !important — the shape the
642
+ close-button rules below already use against this same stylesheet, and for
643
+ the same reason: source order cannot settle a tie with a sheet that is
644
+ injected at runtime.
645
+
646
+ The description returns to 400. It is the running text of a toast, and 14px
647
+ semibold across a full sentence reads as emphasis with nothing left to
648
+ emphasise; the family ink already carries the severity. Its `color` override
649
+ keeps !important on its own merits — sonner hardcodes #3f3f3f there, plus a
650
+ dark-theme rule of its own on top.
651
+
652
+ `toast text weights` in src/__tests__/tokens-contract.test.ts holds the order
653
+ and the two properties that let it apply.
654
+ */
655
+ [data-sonner-toast][data-styled='true'] [data-title] {
656
+ font-weight: 600 !important;
607
657
  font-size: 0.875rem;
608
658
  line-height: 1.25rem;
609
659
  }
@@ -611,7 +661,7 @@
611
661
  [data-sonner-toast] [data-description],
612
662
  [data-sonner-toast][data-styled='true'] [data-description] {
613
663
  font-size: 0.875rem;
614
- font-weight: 600 !important;
664
+ font-weight: 400 !important;
615
665
  line-height: 1.25rem;
616
666
  color: var(--normal-text) !important;
617
667
  }
@@ -1,4 +1,10 @@
1
1
  import type { ToastActionElement } from '../components/ui/toast';
2
+ /**
3
+ * Lifetime of every non-destructive toast, and the `<Toaster />` fallback for
4
+ * anything raised without one. The two must not drift apart, so the Toaster
5
+ * imports this rather than repeating the literal.
6
+ */
7
+ export declare const DEFAULT_DURATION = 10000;
2
8
  type ToastVariant = 'default' | 'success' | 'warning' | 'destructive';
3
9
  type ToasterToast = {
4
10
  id: string | number;
@@ -6,9 +12,19 @@ type ToasterToast = {
6
12
  description?: React.ReactNode;
7
13
  variant?: ToastVariant;
8
14
  action?: ToastActionElement;
15
+ /**
16
+ * Auto-dismiss delay in ms, which must be greater than 0: sonner resolves it
17
+ * as `toast.duration || toasterDuration || default`, so `0` reads as unset
18
+ * and the toast silently takes the `<Toaster />` default instead of closing
19
+ * at once. Omit it to take the variant's own lifetime: `destructive` stays
20
+ * until dismissed, every other variant closes after 10s.
21
+ */
22
+ duration?: number;
23
+ };
24
+ type Toast = Omit<ToasterToast, 'id'> & {
25
+ id?: ToasterToast['id'];
9
26
  };
10
- type Toast = Omit<ToasterToast, 'id'>;
11
- declare function toast({ title, description, variant, ...rest }: Toast): {
27
+ declare function toast({ title, description, variant, duration, id, ...rest }: Toast): {
12
28
  id: string | number;
13
29
  dismiss: () => string | number;
14
30
  update: (props: Partial<ToasterToast>) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"use-toast.d.ts","sourceRoot":"","sources":["../../src/hooks/use-toast.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAI/D,KAAK,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAA;AAErE,KAAK,YAAY,GAAG;IAClB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB,MAAM,CAAC,EAAE,kBAAkB,CAAA;CAC5B,CAAA;AAED,KAAK,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;AAErC,iBAAS,KAAK,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,EAAE,KAAK;;;oBA+B1C,OAAO,CAAC,YAAY,CAAC;EAQxC;AAED;;;;;;;GAOG;AACH,iBAAS,QAAQ;;wBAGO,MAAM,GAAG,MAAM;YAOrB,YAAY,EAAE;EAE/B;AAED,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;AAC1B,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,CAAA"}
1
+ {"version":3,"file":"use-toast.d.ts","sourceRoot":"","sources":["../../src/hooks/use-toast.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAE/D;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,QAAQ,CAAA;AAerC,KAAK,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAA;AAErE,KAAK,YAAY,GAAG;IAClB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB,MAAM,CAAC,EAAE,kBAAkB,CAAA;IAC3B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,KAAK,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,GAAG;IAAE,EAAE,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAA;CAAE,CAAA;AAiCnE,iBAAS,KAAK,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,EAAE,KAAK;;;oBAsCxD,OAAO,CAAC,YAAY,CAAC;EASxC;AAED;;;;;;;GAOG;AACH,iBAAS,QAAQ;;wBAGO,MAAM,GAAG,MAAM;YAOrB,YAAY,EAAE;EAE/B;AAED,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;AAC1B,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,CAAA"}
@@ -1,43 +1,88 @@
1
1
  'use client';
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.DEFAULT_DURATION = void 0;
4
5
  exports.useToast = useToast;
5
6
  exports.toast = toast;
6
7
  const sonner_1 = require("sonner");
7
- const DEFAULT_DURATION = 10000;
8
- function toast({ title, description, variant, ...rest }) {
8
+ /**
9
+ * Lifetime of every non-destructive toast, and the `<Toaster />` fallback for
10
+ * anything raised without one. The two must not drift apart, so the Toaster
11
+ * imports this rather than repeating the literal.
12
+ */
13
+ exports.DEFAULT_DURATION = 10000;
14
+ /**
15
+ * A destructive toast reports something the operator has to read -- a refused
16
+ * money operation, a failed copy of a show-once secret, a language switch that
17
+ * did not take. It stays up until dismissed instead of auto-closing.
18
+ *
19
+ * `Infinity` is how sonner disables the auto-close timer (it short-circuits the
20
+ * timer effect rather than calling `setTimeout(fn, Infinity)`, which would fire
21
+ * immediately). `<Toaster />` already passes `closeButton`, and sonner gates the
22
+ * close button on that flag alone, never on the duration -- so a persistent
23
+ * toast still renders its dismiss affordance.
24
+ */
25
+ const PERSIST_UNTIL_DISMISSED = Infinity;
26
+ const isPlainText = (value) => value === undefined || typeof value === 'string';
27
+ /**
28
+ * Two identical errors share one toast instead of stacking: same variant, same
29
+ * text -- same id, and sonner updates the one already on screen.
30
+ *
31
+ * Unbounded stacking is worse for a persistent toast than for a transient one.
32
+ * `<Toaster />` shows three at a time and renders the rest `opacity: 0;
33
+ * pointer-events: none`, so a fourth error nobody can read is also a fourth
34
+ * error nobody can close -- and without an auto-dismiss, nothing ahead of it
35
+ * clears on its own.
36
+ *
37
+ * Only plain-text toasts collapse. A `ReactNode` has no stable key and
38
+ * `String(node)` would fold unrelated errors onto one id.
39
+ *
40
+ * ponytail: the ceiling is still three. Distinct persistent errors past the
41
+ * third queue behind the front three until one is dismissed; lifting that means
42
+ * raising `visibleToasts`, not more work here.
43
+ */
44
+ function collapseKey(title, description) {
45
+ if (!isPlainText(title) || !isPlainText(description)) {
46
+ return undefined;
47
+ }
48
+ return `destructive:${JSON.stringify([title ?? null, description ?? null])}`;
49
+ }
50
+ function toast({ title, description, variant, duration, id, ...rest }) {
9
51
  const message = title ?? '';
52
+ const toastId = variant === 'destructive' && id === undefined
53
+ ? collapseKey(title, description)
54
+ : id;
10
55
  const options = {
11
56
  description,
12
- ...rest
57
+ ...rest,
58
+ ...(toastId !== undefined && { id: toastId }),
59
+ duration: duration ??
60
+ (variant === 'destructive' ? PERSIST_UNTIL_DISMISSED : exports.DEFAULT_DURATION)
13
61
  };
14
- let id;
62
+ let raisedId;
15
63
  switch (variant) {
16
64
  case 'success':
17
- options.duration = DEFAULT_DURATION;
18
- id = sonner_1.toast.success(message, options);
65
+ raisedId = sonner_1.toast.success(message, options);
19
66
  break;
20
67
  case 'warning':
21
- options.duration = DEFAULT_DURATION;
22
- id = sonner_1.toast.warning(message, options);
68
+ raisedId = sonner_1.toast.warning(message, options);
23
69
  break;
24
70
  case 'destructive':
25
- options.duration = DEFAULT_DURATION;
26
- id = sonner_1.toast.error(message, options);
71
+ raisedId = sonner_1.toast.error(message, options);
27
72
  break;
28
73
  default:
29
- options.duration = DEFAULT_DURATION;
30
- id = (0, sonner_1.toast)(message, options);
74
+ raisedId = (0, sonner_1.toast)(message, options);
31
75
  break;
32
76
  }
33
77
  return {
34
- id,
35
- dismiss: () => sonner_1.toast.dismiss(id),
78
+ id: raisedId,
79
+ dismiss: () => sonner_1.toast.dismiss(raisedId),
36
80
  update: (props) => {
37
81
  (0, sonner_1.toast)(props.title ?? message, {
38
- id,
82
+ ...rest,
83
+ id: raisedId,
39
84
  description: props.description ?? description,
40
- ...rest
85
+ duration: props.duration ?? options.duration
41
86
  });
42
87
  }
43
88
  };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from './components/ui/alert';
2
2
  export * from './components/ui/autocomplete';
3
+ export * from './hooks/use-click-away';
3
4
  export * from './components/ui/autosize-textarea';
4
5
  export * from './components/ui/avatar';
5
6
  export * from './components/ui/badge';
@@ -39,6 +40,7 @@ export * from './components/ui/toast';
39
40
  export * from './components/ui/toast/toaster';
40
41
  export * from './hooks/use-toast';
41
42
  export * from './components/ui/time-picker';
43
+ export * from './hooks/use-time';
42
44
  export * from './components/ui/tooltip';
43
45
  export * from './components/ui/form';
44
46
  export { Breadcrumb as ApplicationBreadcrumb } from './components/breadcrumb';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAGA,cAAc,uBAAuB,CAAA;AACrC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,mCAAmC,CAAA;AACjD,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,wBAAwB,CAAA;AACtC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,0BAA0B,CAAA;AACxC,cAAc,sBAAsB,CAAA;AACpC,cAAc,0BAA0B,CAAA;AACxC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,yBAAyB,CAAA;AACvC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,wBAAwB,CAAA;AACtC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,uBAAuB,CAAA;AACrC,cAAc,2BAA2B,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,uBAAuB,CAAA;AACrC,cAAc,mCAAmC,CAAA;AACjD,cAAc,yBAAyB,CAAA;AACvC,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,wBAAwB,CAAA;AACtC,cAAc,2BAA2B,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,cAAc,yBAAyB,CAAA;AACvC,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,qBAAqB,CAAA;AACnC,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA;AACpC,cAAc,0BAA0B,CAAA;AACxC,cAAc,uBAAuB,CAAA;AACrC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,mBAAmB,CAAA;AACjC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,yBAAyB,CAAA;AACvC,cAAc,sBAAsB,CAAA;AAGpC,OAAO,EAAE,UAAU,IAAI,qBAAqB,EAAE,MAAM,yBAAyB,CAAA;AAC7E,cAAc,8CAA8C,CAAA;AAC5D,cAAc,mBAAmB,CAAA;AACjC,cAAc,qBAAqB,CAAA;AACnC,cAAc,yBAAyB,CAAA;AACvC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,oBAAoB,CAAA;AAGlC,cAAc,cAAc,CAAA;AAC5B,cAAc,SAAS,CAAA;AACvB,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AAGxB,cAAc,2BAA2B,CAAA;AACzC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,8BAA8B,CAAA;AAG5C,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA;AAChC,cAAc,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAGA,cAAc,uBAAuB,CAAA;AACrC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,wBAAwB,CAAA;AACtC,cAAc,mCAAmC,CAAA;AACjD,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,wBAAwB,CAAA;AACtC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,0BAA0B,CAAA;AACxC,cAAc,sBAAsB,CAAA;AACpC,cAAc,0BAA0B,CAAA;AACxC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,yBAAyB,CAAA;AACvC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,wBAAwB,CAAA;AACtC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,uBAAuB,CAAA;AACrC,cAAc,2BAA2B,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,uBAAuB,CAAA;AACrC,cAAc,mCAAmC,CAAA;AACjD,cAAc,yBAAyB,CAAA;AACvC,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,wBAAwB,CAAA;AACtC,cAAc,2BAA2B,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,cAAc,yBAAyB,CAAA;AACvC,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,qBAAqB,CAAA;AACnC,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA;AACpC,cAAc,0BAA0B,CAAA;AACxC,cAAc,uBAAuB,CAAA;AACrC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,mBAAmB,CAAA;AACjC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,kBAAkB,CAAA;AAChC,cAAc,yBAAyB,CAAA;AACvC,cAAc,sBAAsB,CAAA;AAGpC,OAAO,EAAE,UAAU,IAAI,qBAAqB,EAAE,MAAM,yBAAyB,CAAA;AAC7E,cAAc,8CAA8C,CAAA;AAC5D,cAAc,mBAAmB,CAAA;AACjC,cAAc,qBAAqB,CAAA;AACnC,cAAc,yBAAyB,CAAA;AACvC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,oBAAoB,CAAA;AAGlC,cAAc,cAAc,CAAA;AAC5B,cAAc,SAAS,CAAA;AACvB,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AAGxB,cAAc,2BAA2B,CAAA;AACzC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,8BAA8B,CAAA;AAG5C,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA;AAChC,cAAc,kBAAkB,CAAA"}
package/dist/index.js CHANGED
@@ -19,6 +19,7 @@ exports.cn = exports.ApplicationBreadcrumb = void 0;
19
19
  // Primitives
20
20
  __exportStar(require("./components/ui/alert"), exports);
21
21
  __exportStar(require("./components/ui/autocomplete"), exports);
22
+ __exportStar(require("./hooks/use-click-away"), exports);
22
23
  __exportStar(require("./components/ui/autosize-textarea"), exports);
23
24
  __exportStar(require("./components/ui/avatar"), exports);
24
25
  __exportStar(require("./components/ui/badge"), exports);
@@ -58,6 +59,7 @@ __exportStar(require("./components/ui/toast"), exports);
58
59
  __exportStar(require("./components/ui/toast/toaster"), exports);
59
60
  __exportStar(require("./hooks/use-toast"), exports);
60
61
  __exportStar(require("./components/ui/time-picker"), exports);
62
+ __exportStar(require("./hooks/use-time"), exports);
61
63
  __exportStar(require("./components/ui/tooltip"), exports);
62
64
  __exportStar(require("./components/ui/form"), exports);
63
65
  // Components