cortena-ui 1.3.0 → 1.4.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 (280) hide show
  1. package/README.md +74 -3
  2. package/dist/a2ui/catalogue-doc.d.ts +44 -0
  3. package/dist/a2ui/catalogue-doc.js +169 -0
  4. package/dist/a2ui/catalogue-doc.js.map +1 -0
  5. package/dist/a2ui/catalogue.d.ts +44 -0
  6. package/dist/a2ui/catalogue.js +942 -0
  7. package/dist/a2ui/catalogue.js.map +1 -0
  8. package/dist/a2ui/index.d.ts +7 -0
  9. package/dist/a2ui/message.d.ts +232 -0
  10. package/dist/a2ui/message.js +365 -0
  11. package/dist/a2ui/message.js.map +1 -0
  12. package/dist/a2ui/renderer.d.ts +46 -0
  13. package/dist/a2ui/renderer.js +252 -0
  14. package/dist/a2ui/renderer.js.map +1 -0
  15. package/dist/a2ui/views.d.ts +80 -0
  16. package/dist/a2ui/views.js +596 -0
  17. package/dist/a2ui/views.js.map +1 -0
  18. package/dist/a2ui.d.ts +8 -0
  19. package/dist/a2ui.js +7 -0
  20. package/dist/chart.d.ts +9 -0
  21. package/dist/chart.js +9 -0
  22. package/dist/components/accordion.d.ts +22 -0
  23. package/dist/components/accordion.js +63 -0
  24. package/dist/components/accordion.js.map +1 -0
  25. package/dist/components/alert.d.ts +15 -0
  26. package/dist/components/alert.js +64 -0
  27. package/dist/components/alert.js.map +1 -0
  28. package/dist/components/avatar.d.ts +18 -0
  29. package/dist/components/avatar.js +40 -0
  30. package/dist/components/avatar.js.map +1 -0
  31. package/dist/components/badge.d.ts +12 -0
  32. package/dist/components/badge.js +47 -0
  33. package/dist/components/badge.js.map +1 -0
  34. package/dist/components/breadcrumb.d.ts +71 -0
  35. package/dist/components/breadcrumb.js +123 -0
  36. package/dist/components/breadcrumb.js.map +1 -0
  37. package/dist/components/button-link.d.ts +28 -0
  38. package/dist/components/button-link.js +24 -0
  39. package/dist/components/button-link.js.map +1 -0
  40. package/dist/components/button.d.ts +24 -0
  41. package/dist/components/button.js +65 -0
  42. package/dist/components/button.js.map +1 -0
  43. package/dist/components/calendar.d.ts +28 -0
  44. package/dist/components/calendar.js +123 -0
  45. package/dist/components/calendar.js.map +1 -0
  46. package/dist/components/card.d.ts +32 -0
  47. package/dist/components/card.js +57 -0
  48. package/dist/components/card.js.map +1 -0
  49. package/dist/components/chart/chart.d.ts +71 -0
  50. package/dist/components/chart/chart.js +167 -0
  51. package/dist/components/chart/chart.js.map +1 -0
  52. package/dist/components/chart/container.d.ts +88 -0
  53. package/dist/components/chart/container.js +189 -0
  54. package/dist/components/chart/container.js.map +1 -0
  55. package/dist/components/chart/data.js +128 -0
  56. package/dist/components/chart/data.js.map +1 -0
  57. package/dist/components/chart/index.d.ts +9 -0
  58. package/dist/components/chart/index.js +10 -0
  59. package/dist/components/chart/nivo-charts.js +225 -0
  60. package/dist/components/chart/nivo-charts.js.map +1 -0
  61. package/dist/components/chart/nivo-lazy.js +50 -0
  62. package/dist/components/chart/nivo-lazy.js.map +1 -0
  63. package/dist/components/chart/nivo-theme.d.ts +156 -0
  64. package/dist/components/chart/nivo-theme.js +161 -0
  65. package/dist/components/chart/nivo-theme.js.map +1 -0
  66. package/dist/components/chart/recharts-charts.js +276 -0
  67. package/dist/components/chart/recharts-charts.js.map +1 -0
  68. package/dist/components/chart/recharts-lazy.js +58 -0
  69. package/dist/components/chart/recharts-lazy.js.map +1 -0
  70. package/dist/components/chart/recharts-parts.d.ts +10 -0
  71. package/dist/components/chart/recharts-parts.js +25 -0
  72. package/dist/components/chart/recharts-parts.js.map +1 -0
  73. package/dist/components/chart/tokens.d.ts +62 -0
  74. package/dist/components/chart/tokens.js +192 -0
  75. package/dist/components/chart/tokens.js.map +1 -0
  76. package/dist/components/chart/types.d.ts +114 -0
  77. package/dist/components/chart/types.js +27 -0
  78. package/dist/components/chart/types.js.map +1 -0
  79. package/dist/components/checkbox.d.ts +20 -0
  80. package/dist/components/checkbox.js +24 -0
  81. package/dist/components/checkbox.js.map +1 -0
  82. package/dist/components/chip.d.ts +17 -0
  83. package/dist/components/chip.js +47 -0
  84. package/dist/components/chip.js.map +1 -0
  85. package/dist/components/combobox.d.ts +76 -0
  86. package/dist/components/combobox.js +201 -0
  87. package/dist/components/combobox.js.map +1 -0
  88. package/dist/components/command.d.ts +50 -0
  89. package/dist/components/command.js +117 -0
  90. package/dist/components/command.js.map +1 -0
  91. package/dist/components/data-table/data-table.d.ts +65 -0
  92. package/dist/components/data-table/data-table.js +588 -0
  93. package/dist/components/data-table/data-table.js.map +1 -0
  94. package/dist/components/data-table/export.d.ts +23 -0
  95. package/dist/components/data-table/export.js +95 -0
  96. package/dist/components/data-table/export.js.map +1 -0
  97. package/dist/components/data-table/features.d.ts +66 -0
  98. package/dist/components/data-table/features.js +103 -0
  99. package/dist/components/data-table/features.js.map +1 -0
  100. package/dist/components/data-table/index.d.ts +8 -0
  101. package/dist/components/data-table/parts.d.ts +79 -0
  102. package/dist/components/data-table/parts.js +400 -0
  103. package/dist/components/data-table/parts.js.map +1 -0
  104. package/dist/components/data-table/system-columns.js +84 -0
  105. package/dist/components/data-table/system-columns.js.map +1 -0
  106. package/dist/components/data-table/types.d.ts +172 -0
  107. package/dist/components/data-table/use-data-table.d.ts +19 -0
  108. package/dist/components/data-table/use-data-table.js +171 -0
  109. package/dist/components/data-table/use-data-table.js.map +1 -0
  110. package/dist/components/data-table/use-server-source.js +200 -0
  111. package/dist/components/data-table/use-server-source.js.map +1 -0
  112. package/dist/components/date-field.d.ts +54 -0
  113. package/dist/components/date-field.js +235 -0
  114. package/dist/components/date-field.js.map +1 -0
  115. package/dist/components/date-picker.d.ts +42 -0
  116. package/dist/components/date-picker.js +125 -0
  117. package/dist/components/date-picker.js.map +1 -0
  118. package/dist/components/dialog.d.ts +36 -0
  119. package/dist/components/dialog.js +97 -0
  120. package/dist/components/dialog.js.map +1 -0
  121. package/dist/components/dropdown-menu.d.ts +54 -0
  122. package/dist/components/dropdown-menu.js +191 -0
  123. package/dist/components/dropdown-menu.js.map +1 -0
  124. package/dist/components/dropzone.d.ts +48 -0
  125. package/dist/components/dropzone.js +185 -0
  126. package/dist/components/dropzone.js.map +1 -0
  127. package/dist/components/empty-state.d.ts +22 -0
  128. package/dist/components/empty-state.js +46 -0
  129. package/dist/components/empty-state.js.map +1 -0
  130. package/dist/components/error-banner.d.ts +17 -0
  131. package/dist/components/error-banner.js +52 -0
  132. package/dist/components/error-banner.js.map +1 -0
  133. package/dist/components/field.d.ts +64 -0
  134. package/dist/components/field.js +133 -0
  135. package/dist/components/field.js.map +1 -0
  136. package/dist/components/form.d.ts +37 -0
  137. package/dist/components/form.js +103 -0
  138. package/dist/components/form.js.map +1 -0
  139. package/dist/components/input.d.ts +17 -0
  140. package/dist/components/input.js +26 -0
  141. package/dist/components/input.js.map +1 -0
  142. package/dist/components/kbd.d.ts +11 -0
  143. package/dist/components/kbd.js +20 -0
  144. package/dist/components/kbd.js.map +1 -0
  145. package/dist/components/label.d.ts +14 -0
  146. package/dist/components/label.js +28 -0
  147. package/dist/components/label.js.map +1 -0
  148. package/dist/components/loading-skeleton.d.ts +22 -0
  149. package/dist/components/loading-skeleton.js +123 -0
  150. package/dist/components/loading-skeleton.js.map +1 -0
  151. package/dist/components/markdown.d.ts +44 -0
  152. package/dist/components/markdown.js +231 -0
  153. package/dist/components/markdown.js.map +1 -0
  154. package/dist/components/page-header.d.ts +26 -0
  155. package/dist/components/page-header.js +53 -0
  156. package/dist/components/page-header.js.map +1 -0
  157. package/dist/components/popover.d.ts +29 -0
  158. package/dist/components/popover.js +74 -0
  159. package/dist/components/popover.js.map +1 -0
  160. package/dist/components/progress.d.ts +22 -0
  161. package/dist/components/progress.js +49 -0
  162. package/dist/components/progress.js.map +1 -0
  163. package/dist/components/radio-group.d.ts +20 -0
  164. package/dist/components/radio-group.js +29 -0
  165. package/dist/components/radio-group.js.map +1 -0
  166. package/dist/components/scroll-area.d.ts +25 -0
  167. package/dist/components/scroll-area.js +39 -0
  168. package/dist/components/scroll-area.js.map +1 -0
  169. package/dist/components/section-card.d.ts +29 -0
  170. package/dist/components/section-card.js +55 -0
  171. package/dist/components/section-card.js.map +1 -0
  172. package/dist/components/segmented.d.ts +27 -0
  173. package/dist/components/segmented.js +32 -0
  174. package/dist/components/segmented.js.map +1 -0
  175. package/dist/components/select.d.ts +62 -0
  176. package/dist/components/select.js +97 -0
  177. package/dist/components/select.js.map +1 -0
  178. package/dist/components/separator.d.ts +19 -0
  179. package/dist/components/separator.js +23 -0
  180. package/dist/components/separator.js.map +1 -0
  181. package/dist/components/sheet.d.ts +35 -0
  182. package/dist/components/sheet.js +131 -0
  183. package/dist/components/sheet.js.map +1 -0
  184. package/dist/components/skeleton.d.ts +12 -0
  185. package/dist/components/skeleton.js +22 -0
  186. package/dist/components/skeleton.js.map +1 -0
  187. package/dist/components/sortable-list.d.ts +67 -0
  188. package/dist/components/sortable-list.js +206 -0
  189. package/dist/components/sortable-list.js.map +1 -0
  190. package/dist/components/spinner.d.ts +29 -0
  191. package/dist/components/spinner.js +34 -0
  192. package/dist/components/spinner.js.map +1 -0
  193. package/dist/components/status-dot.d.ts +26 -0
  194. package/dist/components/status-dot.js +47 -0
  195. package/dist/components/status-dot.js.map +1 -0
  196. package/dist/components/switch.d.ts +21 -0
  197. package/dist/components/switch.js +21 -0
  198. package/dist/components/switch.js.map +1 -0
  199. package/dist/components/tabs.d.ts +24 -0
  200. package/dist/components/tabs.js +60 -0
  201. package/dist/components/tabs.js.map +1 -0
  202. package/dist/components/textarea.d.ts +19 -0
  203. package/dist/components/textarea.js +47 -0
  204. package/dist/components/textarea.js.map +1 -0
  205. package/dist/components/toast.d.ts +47 -0
  206. package/dist/components/toast.js +106 -0
  207. package/dist/components/toast.js.map +1 -0
  208. package/dist/components/toolbar.d.ts +19 -0
  209. package/dist/components/toolbar.js +45 -0
  210. package/dist/components/toolbar.js.map +1 -0
  211. package/dist/components/tooltip.d.ts +28 -0
  212. package/dist/components/tooltip.js +59 -0
  213. package/dist/components/tooltip.js.map +1 -0
  214. package/dist/core.d.ts +44 -0
  215. package/dist/core.js +44 -0
  216. package/dist/data-table.d.ts +9 -0
  217. package/dist/data-table.js +7 -0
  218. package/dist/form.d.ts +7 -0
  219. package/dist/form.js +7 -0
  220. package/dist/hooks/use-cortena-theme.d.ts +98 -0
  221. package/dist/hooks/use-cortena-theme.js +145 -0
  222. package/dist/hooks/use-cortena-theme.js.map +1 -0
  223. package/dist/index.d.ts +75 -2678
  224. package/dist/index.js +66 -8598
  225. package/dist/lib/cn.d.ts +10 -0
  226. package/dist/lib/cn.js +15 -0
  227. package/dist/lib/cn.js.map +1 -0
  228. package/dist/lib/render.d.ts +23 -0
  229. package/dist/lib/render.js +20 -0
  230. package/dist/lib/render.js.map +1 -0
  231. package/dist/lib/shakeable.js +39 -0
  232. package/dist/lib/shakeable.js.map +1 -0
  233. package/dist/markdown.d.ts +3 -0
  234. package/dist/markdown.js +3 -0
  235. package/dist/sortable-list.d.ts +3 -0
  236. package/dist/sortable-list.js +3 -0
  237. package/package.json +37 -14
  238. package/src/a2ui/catalogue.ts +140 -103
  239. package/src/a2ui/views.tsx +5 -2
  240. package/src/components/alert.tsx +1 -1
  241. package/src/components/badge.tsx +1 -1
  242. package/src/components/button.tsx +1 -1
  243. package/src/components/chart/chart.tsx +72 -25
  244. package/src/components/chart/container.tsx +24 -39
  245. package/src/components/chart/index.tsx +4 -2
  246. package/src/components/chart/nivo-charts.tsx +41 -13
  247. package/src/components/chart/nivo-lazy.tsx +52 -0
  248. package/src/components/chart/recharts-charts.tsx +98 -3
  249. package/src/components/chart/recharts-lazy.tsx +72 -0
  250. package/src/components/chart/recharts-parts.tsx +34 -0
  251. package/src/components/chart/tokens.ts +1 -1
  252. package/src/components/chart/types.ts +14 -0
  253. package/src/components/chip.tsx +1 -1
  254. package/src/components/combobox.tsx +2 -2
  255. package/src/components/data-table/export.ts +18 -2
  256. package/src/components/data-table/features.ts +77 -45
  257. package/src/components/data-table/parts.tsx +15 -0
  258. package/src/components/data-table/use-data-table.ts +7 -2
  259. package/src/components/data-table/use-server-source.ts +17 -4
  260. package/src/components/date-field.tsx +1 -1
  261. package/src/components/error-banner.tsx +1 -1
  262. package/src/components/field.tsx +2 -2
  263. package/src/components/form.tsx +2 -2
  264. package/src/components/input.tsx +1 -1
  265. package/src/components/label.tsx +1 -1
  266. package/src/components/markdown.tsx +5 -4
  267. package/src/components/sheet.tsx +2 -2
  268. package/src/components/sortable-list.tsx +2 -2
  269. package/src/components/textarea.tsx +1 -1
  270. package/src/components/toast.tsx +1 -1
  271. package/src/entries/a2ui.ts +11 -0
  272. package/src/entries/chart.ts +10 -0
  273. package/src/entries/core.ts +91 -0
  274. package/src/entries/data-table.ts +9 -0
  275. package/src/entries/form.ts +24 -0
  276. package/src/entries/markdown.ts +9 -0
  277. package/src/entries/sortable-list.ts +13 -0
  278. package/src/index.ts +32 -98
  279. package/src/lib/shakeable.ts +33 -0
  280. package/dist/index.js.map +0 -1
@@ -0,0 +1,235 @@
1
+ "use client";
2
+ "use client";
3
+ import { cn } from "../lib/cn.js";
4
+ import { Button } from "./button.js";
5
+ import { Input } from "./input.js";
6
+ import { Popover, PopoverContent, PopoverTrigger } from "./popover.js";
7
+ import { Calendar } from "./calendar.js";
8
+ import { CalendarIcon } from "lucide-react";
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
+ import * as React from "react";
11
+ //#region src/components/date-field.tsx
12
+ /**
13
+ * DateField.
14
+ *
15
+ * A form-friendly date input: our `<Input>` showing the formatted date, with
16
+ * the DatePicker's calendar behind a trailing icon button. Typing a date the
17
+ * parser accepts commits it (the default parser reads ISO `yyyy-mm-dd`, and
18
+ * the English `15 Jan 2026` / `15 January 2026` shapes the formatters below
19
+ * produce); picking a day from the calendar writes it back through
20
+ * `formatDate`. Non-empty text the parser rejects, or a date outside
21
+ * `min`/`max`, clears the value and marks the input invalid so a Field can
22
+ * show the error.
23
+ *
24
+ * The date helpers are hand-written for `en-GB` (day month year, no library);
25
+ * any other `locale` goes through the browser's `Intl`.
26
+ */
27
+ const MONTHS_LONG = [
28
+ "January",
29
+ "February",
30
+ "March",
31
+ "April",
32
+ "May",
33
+ "June",
34
+ "July",
35
+ "August",
36
+ "September",
37
+ "October",
38
+ "November",
39
+ "December"
40
+ ];
41
+ const MONTHS_SHORT = /* @__PURE__ */ MONTHS_LONG.map((m) => m.slice(0, 3));
42
+ const pad = (n) => String(n).padStart(2, "0");
43
+ const isEn = (locale) => /^en(-GB)?$/i.test(locale);
44
+ /** `2026-01-05`. */
45
+ function formatDateISO(date) {
46
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
47
+ }
48
+ /** `5 Jan 2026` for en-GB; other locales via `Intl.DateTimeFormat`. */
49
+ function formatDateShort(date, locale = "en-GB") {
50
+ if (isEn(locale)) return `${date.getDate()} ${MONTHS_SHORT[date.getMonth()]} ${date.getFullYear()}`;
51
+ return new Intl.DateTimeFormat(locale, {
52
+ day: "numeric",
53
+ month: "short",
54
+ year: "numeric"
55
+ }).format(date);
56
+ }
57
+ /** `5 January 2026` for en-GB; other locales via `Intl.DateTimeFormat`. */
58
+ function formatDateLong(date, locale = "en-GB") {
59
+ if (isEn(locale)) return `${date.getDate()} ${MONTHS_LONG[date.getMonth()]} ${date.getFullYear()}`;
60
+ return new Intl.DateTimeFormat(locale, {
61
+ day: "numeric",
62
+ month: "long",
63
+ year: "numeric"
64
+ }).format(date);
65
+ }
66
+ const DAY_MS = 864e5;
67
+ function startOfDay(date) {
68
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();
69
+ }
70
+ /**
71
+ * Calendar-day distance in words: `today`, `yesterday`, `tomorrow`, `3 days
72
+ * ago`, `in 2 weeks`, `4 months ago`, `in 2 years`. Compares local calendar
73
+ * days, so 23:59 to 00:01 is `tomorrow`. Other locales use
74
+ * `Intl.RelativeTimeFormat`.
75
+ */
76
+ function formatRelative(date, options = {}) {
77
+ const { now = /* @__PURE__ */ new Date(), locale = "en-GB" } = options;
78
+ const days = Math.round((startOfDay(date) - startOfDay(now)) / DAY_MS);
79
+ const abs = Math.abs(days);
80
+ let unit;
81
+ let count;
82
+ if (abs < 7) {
83
+ unit = "day";
84
+ count = days;
85
+ } else if (abs < 30) {
86
+ unit = "week";
87
+ count = Math.round(days / 7);
88
+ } else if (abs < 365) {
89
+ unit = "month";
90
+ count = Math.round(days / 30);
91
+ } else {
92
+ unit = "year";
93
+ count = Math.round(days / 365);
94
+ }
95
+ if (!isEn(locale)) return new Intl.RelativeTimeFormat(locale, { numeric: "auto" }).format(count, unit);
96
+ if (days === 0) return "today";
97
+ if (days === -1) return "yesterday";
98
+ if (days === 1) return "tomorrow";
99
+ const n = Math.abs(count);
100
+ const label = `${n} ${unit}${n === 1 ? "" : "s"}`;
101
+ return count < 0 ? `${label} ago` : `in ${label}`;
102
+ }
103
+ function makeDate(year, month, day) {
104
+ const date = new Date(year, month - 1, day);
105
+ if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) return;
106
+ return date;
107
+ }
108
+ /** Strict `yyyy-mm-dd`; rejects impossible days such as `2026-02-30`. */
109
+ function parseDateISO(text) {
110
+ const m = /^(\d{4})-(\d{1,2})-(\d{1,2})$/.exec(text.trim());
111
+ if (!m) return void 0;
112
+ return makeDate(Number(m[1]), Number(m[2]), Number(m[3]));
113
+ }
114
+ /** ISO first, then the English `5 Jan 2026` / `5 January 2026` shapes. */
115
+ function parseDateDefault(text) {
116
+ const iso = parseDateISO(text);
117
+ if (iso) return iso;
118
+ const m = /^(\d{1,2})\s+([a-z]+)\s+(\d{4})$/i.exec(text.trim());
119
+ if (!m) return void 0;
120
+ const name = (m[2] ?? "").toLowerCase();
121
+ const month = MONTHS_LONG.findIndex((full) => full.toLowerCase() === name || full.slice(0, 3).toLowerCase() === name);
122
+ if (month < 0) return void 0;
123
+ return makeDate(Number(m[3]), month + 1, Number(m[1]));
124
+ }
125
+ function sameDay(a, b) {
126
+ if (!a || !b) return a === b;
127
+ return startOfDay(a) === startOfDay(b);
128
+ }
129
+ function inRange(date, min, max) {
130
+ const t = startOfDay(date);
131
+ if (min && t < startOfDay(min)) return false;
132
+ if (max && t > startOfDay(max)) return false;
133
+ return true;
134
+ }
135
+ function DateField(props) {
136
+ const { value, defaultValue, onValueChange, placeholder = "yyyy-mm-dd", formatDate = formatDateISO, parseDate = parseDateDefault, min, max, disabled, invalid, calendarProps, wrapperClassName, className, onBlur, ...inputProps } = props;
137
+ const controlled = "value" in props;
138
+ const [inner, setInner] = React.useState(defaultValue);
139
+ const date = controlled ? value : inner;
140
+ const [text, setText] = React.useState(() => date ? formatDate(date) : "");
141
+ const [textInvalid, setTextInvalid] = React.useState(false);
142
+ const [open, setOpen] = React.useState(false);
143
+ const committed = React.useRef(date);
144
+ const commit = React.useCallback((next) => {
145
+ committed.current = next;
146
+ if (!controlled) setInner(next);
147
+ onValueChange?.(next);
148
+ }, [controlled, onValueChange]);
149
+ React.useEffect(() => {
150
+ if (sameDay(date, committed.current)) return;
151
+ committed.current = date;
152
+ setText(date ? formatDate(date) : "");
153
+ setTextInvalid(false);
154
+ }, [date, formatDate]);
155
+ const onChange = (event) => {
156
+ const next = event.target.value;
157
+ setText(next);
158
+ if (next.trim() === "") {
159
+ setTextInvalid(false);
160
+ if (date !== void 0) commit(void 0);
161
+ return;
162
+ }
163
+ const parsed = parseDate(next);
164
+ const ok = parsed !== void 0 && inRange(parsed, min, max);
165
+ setTextInvalid(!ok);
166
+ if (ok) {
167
+ if (!sameDay(parsed, date)) commit(parsed);
168
+ } else if (date !== void 0) commit(void 0);
169
+ };
170
+ const pick = (next) => {
171
+ setOpen(false);
172
+ setTextInvalid(false);
173
+ setText(next ? formatDate(next) : "");
174
+ if (!sameDay(next, date)) commit(next);
175
+ };
176
+ const matchers = [];
177
+ if (min) matchers.push({ before: min });
178
+ if (max) matchers.push({ after: max });
179
+ const isInvalid = invalid || textInvalid;
180
+ return /* @__PURE__ */ jsxs("div", {
181
+ "data-slot": "date-field",
182
+ "data-invalid": isInvalid || void 0,
183
+ "data-disabled": disabled || void 0,
184
+ className: cn("relative w-60", wrapperClassName),
185
+ children: [/* @__PURE__ */ jsx(Input, {
186
+ type: "text",
187
+ inputMode: "numeric",
188
+ autoComplete: "off",
189
+ "data-slot": "date-field-input",
190
+ value: text,
191
+ placeholder,
192
+ disabled,
193
+ "aria-invalid": isInvalid || void 0,
194
+ onChange,
195
+ onBlur: (event) => {
196
+ if (date && !textInvalid) setText(formatDate(date));
197
+ onBlur?.(event);
198
+ },
199
+ className: cn("pr-10", className),
200
+ ...inputProps
201
+ }), /* @__PURE__ */ jsxs(Popover, {
202
+ open,
203
+ onOpenChange: setOpen,
204
+ children: [/* @__PURE__ */ jsx(PopoverTrigger, {
205
+ "data-slot": "date-field-trigger",
206
+ render: /* @__PURE__ */ jsx(Button, {
207
+ variant: "ghost",
208
+ size: "icon-sm"
209
+ }),
210
+ "aria-label": "Open calendar",
211
+ disabled,
212
+ className: cn("absolute top-1/2 right-1 -translate-y-1/2", "text-[color:var(--ds-muted-foreground)] hover:text-[color:var(--ds-foreground)]"),
213
+ children: /* @__PURE__ */ jsx(CalendarIcon, {})
214
+ }), /* @__PURE__ */ jsx(PopoverContent, {
215
+ "data-slot": "date-field-content",
216
+ align: "end",
217
+ className: "w-auto p-0",
218
+ children: /* @__PURE__ */ jsx(Calendar, {
219
+ ...calendarProps,
220
+ mode: "single",
221
+ defaultMonth: calendarProps?.defaultMonth ?? date,
222
+ selected: date,
223
+ onSelect: pick,
224
+ disabled: matchers.length > 0 ? matchers : void 0,
225
+ startMonth: calendarProps?.startMonth ?? min,
226
+ endMonth: calendarProps?.endMonth ?? max
227
+ })
228
+ })]
229
+ })]
230
+ });
231
+ }
232
+ //#endregion
233
+ export { DateField, formatDateISO, formatDateLong, formatDateShort, formatRelative, parseDateDefault, parseDateISO };
234
+
235
+ //# sourceMappingURL=date-field.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-field.js","names":[],"sources":["../../src/components/date-field.tsx"],"sourcesContent":["\"use client\";\n\nimport { CalendarIcon } from \"lucide-react\";\nimport * as React from \"react\";\nimport type { Matcher } from \"react-day-picker\";\nimport { Button } from \"@/components/button\";\nimport { Calendar, type CalendarProps } from \"@/components/calendar\";\nimport { Input } from \"@/components/input\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@/components/popover\";\nimport { cn } from \"@/lib/cn\";\n\n/**\n * DateField.\n *\n * A form-friendly date input: our `<Input>` showing the formatted date, with\n * the DatePicker's calendar behind a trailing icon button. Typing a date the\n * parser accepts commits it (the default parser reads ISO `yyyy-mm-dd`, and\n * the English `15 Jan 2026` / `15 January 2026` shapes the formatters below\n * produce); picking a day from the calendar writes it back through\n * `formatDate`. Non-empty text the parser rejects, or a date outside\n * `min`/`max`, clears the value and marks the input invalid so a Field can\n * show the error.\n *\n * The date helpers are hand-written for `en-GB` (day month year, no library);\n * any other `locale` goes through the browser's `Intl`.\n */\n\nconst MONTHS_LONG = [\n \"January\",\n \"February\",\n \"March\",\n \"April\",\n \"May\",\n \"June\",\n \"July\",\n \"August\",\n \"September\",\n \"October\",\n \"November\",\n \"December\",\n];\nconst MONTHS_SHORT = /* @__PURE__ */ MONTHS_LONG.map((m) => m.slice(0, 3));\n\nconst pad = (n: number) => String(n).padStart(2, \"0\");\n\nconst isEn = (locale: string) => /^en(-GB)?$/i.test(locale);\n\n/** `2026-01-05`. */\nfunction formatDateISO(date: Date): string {\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;\n}\n\n/** `5 Jan 2026` for en-GB; other locales via `Intl.DateTimeFormat`. */\nfunction formatDateShort(date: Date, locale = \"en-GB\"): string {\n if (isEn(locale)) {\n return `${date.getDate()} ${MONTHS_SHORT[date.getMonth()]} ${date.getFullYear()}`;\n }\n return new Intl.DateTimeFormat(locale, { day: \"numeric\", month: \"short\", year: \"numeric\" }).format(\n date,\n );\n}\n\n/** `5 January 2026` for en-GB; other locales via `Intl.DateTimeFormat`. */\nfunction formatDateLong(date: Date, locale = \"en-GB\"): string {\n if (isEn(locale)) {\n return `${date.getDate()} ${MONTHS_LONG[date.getMonth()]} ${date.getFullYear()}`;\n }\n return new Intl.DateTimeFormat(locale, { day: \"numeric\", month: \"long\", year: \"numeric\" }).format(\n date,\n );\n}\n\nconst DAY_MS = 86_400_000;\n\nfunction startOfDay(date: Date): number {\n return new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();\n}\n\n/**\n * Calendar-day distance in words: `today`, `yesterday`, `tomorrow`, `3 days\n * ago`, `in 2 weeks`, `4 months ago`, `in 2 years`. Compares local calendar\n * days, so 23:59 to 00:01 is `tomorrow`. Other locales use\n * `Intl.RelativeTimeFormat`.\n */\nfunction formatRelative(date: Date, options: { now?: Date; locale?: string } = {}): string {\n const { now = new Date(), locale = \"en-GB\" } = options;\n const days = Math.round((startOfDay(date) - startOfDay(now)) / DAY_MS);\n const abs = Math.abs(days);\n let unit: \"day\" | \"week\" | \"month\" | \"year\";\n let count: number;\n if (abs < 7) {\n unit = \"day\";\n count = days;\n } else if (abs < 30) {\n unit = \"week\";\n count = Math.round(days / 7);\n } else if (abs < 365) {\n unit = \"month\";\n count = Math.round(days / 30);\n } else {\n unit = \"year\";\n count = Math.round(days / 365);\n }\n if (!isEn(locale)) {\n return new Intl.RelativeTimeFormat(locale, { numeric: \"auto\" }).format(count, unit);\n }\n if (days === 0) return \"today\";\n if (days === -1) return \"yesterday\";\n if (days === 1) return \"tomorrow\";\n const n = Math.abs(count);\n const label = `${n} ${unit}${n === 1 ? \"\" : \"s\"}`;\n return count < 0 ? `${label} ago` : `in ${label}`;\n}\n\nfunction makeDate(year: number, month: number, day: number): Date | undefined {\n const date = new Date(year, month - 1, day);\n if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) {\n return undefined;\n }\n return date;\n}\n\n/** Strict `yyyy-mm-dd`; rejects impossible days such as `2026-02-30`. */\nfunction parseDateISO(text: string): Date | undefined {\n const m = /^(\\d{4})-(\\d{1,2})-(\\d{1,2})$/.exec(text.trim());\n if (!m) return undefined;\n return makeDate(Number(m[1]), Number(m[2]), Number(m[3]));\n}\n\n/** ISO first, then the English `5 Jan 2026` / `5 January 2026` shapes. */\nfunction parseDateDefault(text: string): Date | undefined {\n const iso = parseDateISO(text);\n if (iso) return iso;\n const m = /^(\\d{1,2})\\s+([a-z]+)\\s+(\\d{4})$/i.exec(text.trim());\n if (!m) return undefined;\n const name = (m[2] ?? \"\").toLowerCase();\n const month = MONTHS_LONG.findIndex(\n (full) => full.toLowerCase() === name || full.slice(0, 3).toLowerCase() === name,\n );\n if (month < 0) return undefined;\n return makeDate(Number(m[3]), month + 1, Number(m[1]));\n}\n\nfunction sameDay(a: Date | undefined, b: Date | undefined): boolean {\n if (!a || !b) return a === b;\n return startOfDay(a) === startOfDay(b);\n}\n\nfunction inRange(date: Date, min: Date | undefined, max: Date | undefined): boolean {\n const t = startOfDay(date);\n if (min && t < startOfDay(min)) return false;\n if (max && t > startOfDay(max)) return false;\n return true;\n}\n\ntype CalendarPassthrough = Omit<\n CalendarProps,\n \"mode\" | \"selected\" | \"onSelect\" | \"required\" | \"disabled\"\n>;\n\nexport interface DateFieldProps extends Omit<\n React.ComponentProps<\"input\">,\n \"value\" | \"defaultValue\" | \"onChange\" | \"min\" | \"max\" | \"type\"\n> {\n /** The date (controlled). */\n value?: Date | undefined;\n /** The initial date (uncontrolled). */\n defaultValue?: Date | undefined;\n /** Called with the parsed or picked date, or `undefined` when the text is cleared or invalid. */\n onValueChange?: (date: Date | undefined) => void;\n /** Input placeholder; defaults to the ISO shape. */\n placeholder?: string;\n /** Formats the date into the input; defaults to ISO `yyyy-mm-dd`. */\n formatDate?: (date: Date) => string;\n /** Parses typed text; defaults to ISO plus the English day-month-year shapes. */\n parseDate?: (text: string) => Date | undefined;\n /** Earliest selectable day. */\n min?: Date;\n /** Latest selectable day. */\n max?: Date;\n disabled?: boolean;\n /** Force the invalid look (e.g. from a form validator). */\n invalid?: boolean;\n /** Extra props for the Calendar (e.g. `captionLayout`, `today`). */\n calendarProps?: CalendarPassthrough;\n /** Class name for the wrapper; use `className` for the input itself. */\n wrapperClassName?: string;\n}\n\nfunction DateField(props: DateFieldProps) {\n const {\n value,\n defaultValue,\n onValueChange,\n placeholder = \"yyyy-mm-dd\",\n formatDate = formatDateISO,\n parseDate = parseDateDefault,\n min,\n max,\n disabled,\n invalid,\n calendarProps,\n wrapperClassName,\n className,\n onBlur,\n ...inputProps\n } = props;\n const controlled = \"value\" in props;\n const [inner, setInner] = React.useState<Date | undefined>(defaultValue);\n const date = controlled ? value : inner;\n\n const [text, setText] = React.useState(() => (date ? formatDate(date) : \"\"));\n const [textInvalid, setTextInvalid] = React.useState(false);\n const [open, setOpen] = React.useState(false);\n const committed = React.useRef<Date | undefined>(date);\n\n const commit = React.useCallback(\n (next: Date | undefined) => {\n committed.current = next;\n if (!controlled) setInner(next);\n onValueChange?.(next);\n },\n [controlled, onValueChange],\n );\n\n // An external value change (form reset, server data) rewrites the text; a\n // change this field committed itself leaves the user's text alone.\n React.useEffect(() => {\n if (sameDay(date, committed.current)) return;\n committed.current = date;\n setText(date ? formatDate(date) : \"\");\n setTextInvalid(false);\n }, [date, formatDate]);\n\n const onChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n const next = event.target.value;\n setText(next);\n if (next.trim() === \"\") {\n setTextInvalid(false);\n if (date !== undefined) commit(undefined);\n return;\n }\n const parsed = parseDate(next);\n const ok = parsed !== undefined && inRange(parsed, min, max);\n setTextInvalid(!ok);\n if (ok) {\n if (!sameDay(parsed, date)) commit(parsed);\n } else if (date !== undefined) {\n commit(undefined);\n }\n };\n\n const pick = (next: Date | undefined) => {\n setOpen(false);\n setTextInvalid(false);\n setText(next ? formatDate(next) : \"\");\n if (!sameDay(next, date)) commit(next);\n };\n\n const matchers: Matcher[] = [];\n if (min) matchers.push({ before: min });\n if (max) matchers.push({ after: max });\n const isInvalid = invalid || textInvalid;\n\n return (\n <div\n data-slot=\"date-field\"\n data-invalid={isInvalid || undefined}\n data-disabled={disabled || undefined}\n className={cn(\"relative w-60\", wrapperClassName)}\n >\n <Input\n type=\"text\"\n inputMode=\"numeric\"\n autoComplete=\"off\"\n data-slot=\"date-field-input\"\n value={text}\n placeholder={placeholder}\n disabled={disabled}\n aria-invalid={isInvalid || undefined}\n onChange={onChange}\n onBlur={(event) => {\n if (date && !textInvalid) setText(formatDate(date));\n onBlur?.(event);\n }}\n className={cn(\"pr-10\", className)}\n {...inputProps}\n />\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger\n data-slot=\"date-field-trigger\"\n render={<Button variant=\"ghost\" size=\"icon-sm\" />}\n aria-label=\"Open calendar\"\n disabled={disabled}\n className={cn(\n \"absolute top-1/2 right-1 -translate-y-1/2\",\n \"text-[color:var(--ds-muted-foreground)] hover:text-[color:var(--ds-foreground)]\",\n )}\n >\n <CalendarIcon />\n </PopoverTrigger>\n <PopoverContent data-slot=\"date-field-content\" align=\"end\" className=\"w-auto p-0\">\n <Calendar\n {...calendarProps}\n mode=\"single\"\n defaultMonth={calendarProps?.defaultMonth ?? date}\n selected={date}\n onSelect={pick}\n disabled={matchers.length > 0 ? matchers : undefined}\n startMonth={calendarProps?.startMonth ?? min}\n endMonth={calendarProps?.endMonth ?? max}\n />\n </PopoverContent>\n </Popover>\n </div>\n );\n}\n\nexport {\n DateField,\n formatDateISO,\n formatDateShort,\n formatDateLong,\n formatRelative,\n parseDateISO,\n parseDateDefault,\n};\n"],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ "use client";
2
+ import { CalendarProps } from "./calendar.js";
3
+ import * as React from "react";
4
+ import { DateRange } from "react-day-picker";
5
+ //#region src/components/date-picker.d.ts
6
+ /** en-GB order, no library: `15 January 2026`. */
7
+ declare function formatDateDefault(date: Date): string;
8
+ type CalendarPassthrough = Omit<CalendarProps, "mode" | "selected" | "onSelect" | "required" | "disabled">;
9
+ export interface DatePickerProps {
10
+ /** The selected date (controlled). */
11
+ value?: Date | undefined;
12
+ /** The initial date (uncontrolled). */
13
+ defaultValue?: Date | undefined;
14
+ /** Called with the picked date, or `undefined` when the selected day is clicked again. */
15
+ onValueChange?: (date: Date | undefined) => void;
16
+ /** Trigger text while nothing is selected. */
17
+ placeholder?: string;
18
+ /** Formats the trigger text; defaults to `15 January 2026`. */
19
+ formatDate?: (date: Date) => string;
20
+ /** Disables the trigger. */
21
+ disabled?: boolean;
22
+ /** Class name for the trigger button. */
23
+ className?: string;
24
+ /** Extra props for the Calendar (e.g. `startMonth`, `captionLayout`, `disabled` matchers via `calendarProps.hidden`). */
25
+ calendarProps?: CalendarPassthrough & {
26
+ disabled?: CalendarProps["disabled"];
27
+ };
28
+ /** Accessible name for the trigger. */
29
+ "aria-label"?: string;
30
+ }
31
+ declare function DatePicker(props: DatePickerProps): React.JSX.Element;
32
+ export interface DateRangePickerProps extends Omit<DatePickerProps, "value" | "defaultValue" | "onValueChange"> {
33
+ value?: DateRange | undefined;
34
+ defaultValue?: DateRange | undefined;
35
+ onValueChange?: (range: DateRange | undefined) => void;
36
+ /** Separator between the two ends; defaults to an en dash. */
37
+ separator?: string;
38
+ }
39
+ declare function DateRangePicker(props: DateRangePickerProps): React.JSX.Element;
40
+ //#endregion
41
+ export { DatePicker, DateRangePicker, formatDateDefault };
42
+ //# sourceMappingURL=date-picker.d.ts.map
@@ -0,0 +1,125 @@
1
+ "use client";
2
+ "use client";
3
+ import { cn } from "../lib/cn.js";
4
+ import { Button } from "./button.js";
5
+ import { Popover, PopoverContent, PopoverTrigger } from "./popover.js";
6
+ import { Calendar } from "./calendar.js";
7
+ import { CalendarIcon } from "lucide-react";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ import * as React from "react";
10
+ //#region src/components/date-picker.tsx
11
+ /**
12
+ * DatePicker.
13
+ *
14
+ * Our outline Button as the trigger, showing the formatted value or a muted
15
+ * placeholder, opening a Popover that holds a single-select Calendar. Picking
16
+ * a day commits the value and closes the popup. Controlled through `value` /
17
+ * `onValueChange`, uncontrolled through `defaultValue`.
18
+ *
19
+ * `DateRangePicker` is the same shape over `mode="range"`. Its popup stays
20
+ * open while both ends are chosen (react-day-picker's first click sets
21
+ * `from === to`, the second widens it), so the user dismisses it.
22
+ */
23
+ const MONTHS = [
24
+ "January",
25
+ "February",
26
+ "March",
27
+ "April",
28
+ "May",
29
+ "June",
30
+ "July",
31
+ "August",
32
+ "September",
33
+ "October",
34
+ "November",
35
+ "December"
36
+ ];
37
+ /** en-GB order, no library: `15 January 2026`. */
38
+ function formatDateDefault(date) {
39
+ return `${date.getDate()} ${MONTHS[date.getMonth()]} ${date.getFullYear()}`;
40
+ }
41
+ function useControllable(controlled, value, defaultValue, onChange) {
42
+ const [inner, setInner] = React.useState(defaultValue);
43
+ return [controlled ? value : inner, React.useCallback((next) => {
44
+ if (!controlled) setInner(next);
45
+ onChange?.(next);
46
+ }, [controlled, onChange])];
47
+ }
48
+ function PickerTrigger({ slot, placeholder, label, className, ...props }) {
49
+ return /* @__PURE__ */ jsxs(PopoverTrigger, {
50
+ "data-slot": slot,
51
+ "data-empty": label ? void 0 : true,
52
+ render: /* @__PURE__ */ jsx(Button, { variant: "outline" }),
53
+ className: cn("w-60 justify-start font-normal", "data-[empty]:text-[color:var(--ds-muted-foreground)]", "[&_svg]:text-[color:var(--ds-muted-foreground)]", className),
54
+ ...props,
55
+ children: [/* @__PURE__ */ jsx(CalendarIcon, {}), /* @__PURE__ */ jsx("span", {
56
+ "data-slot": `${slot}-value`,
57
+ className: "truncate",
58
+ children: label ?? placeholder
59
+ })]
60
+ });
61
+ }
62
+ function DatePicker(props) {
63
+ const { value, defaultValue, onValueChange, placeholder = "Pick a date", formatDate = formatDateDefault, disabled, className, calendarProps, ...rest } = props;
64
+ const [date, setDate] = useControllable("value" in props, value, defaultValue, onValueChange);
65
+ const [open, setOpen] = React.useState(false);
66
+ return /* @__PURE__ */ jsxs(Popover, {
67
+ open,
68
+ onOpenChange: setOpen,
69
+ children: [/* @__PURE__ */ jsx(PickerTrigger, {
70
+ slot: "date-picker-trigger",
71
+ placeholder,
72
+ label: date ? formatDate(date) : void 0,
73
+ disabled,
74
+ className,
75
+ ...rest
76
+ }), /* @__PURE__ */ jsx(PopoverContent, {
77
+ "data-slot": "date-picker-content",
78
+ align: "start",
79
+ className: "w-auto p-0",
80
+ children: /* @__PURE__ */ jsx(Calendar, {
81
+ ...calendarProps,
82
+ mode: "single",
83
+ defaultMonth: calendarProps?.defaultMonth ?? date,
84
+ selected: date,
85
+ onSelect: (next) => {
86
+ setDate(next);
87
+ setOpen(false);
88
+ }
89
+ })
90
+ })]
91
+ });
92
+ }
93
+ function formatRange(range, formatDate, separator) {
94
+ if (!range?.from) return void 0;
95
+ if (!range.to || range.to.getTime() === range.from.getTime()) return formatDate(range.from);
96
+ return `${formatDate(range.from)}${separator}${formatDate(range.to)}`;
97
+ }
98
+ function DateRangePicker(props) {
99
+ const { value, defaultValue, onValueChange, placeholder = "Pick a date range", formatDate = formatDateDefault, separator = " – ", disabled, className, calendarProps, ...rest } = props;
100
+ const [range, setRange] = useControllable("value" in props, value, defaultValue, onValueChange);
101
+ return /* @__PURE__ */ jsxs(Popover, { children: [/* @__PURE__ */ jsx(PickerTrigger, {
102
+ slot: "date-range-picker-trigger",
103
+ placeholder,
104
+ label: formatRange(range, formatDate, separator),
105
+ disabled,
106
+ className: cn("w-72", className),
107
+ ...rest
108
+ }), /* @__PURE__ */ jsx(PopoverContent, {
109
+ "data-slot": "date-range-picker-content",
110
+ align: "start",
111
+ className: "w-auto p-0",
112
+ children: /* @__PURE__ */ jsx(Calendar, {
113
+ numberOfMonths: 2,
114
+ ...calendarProps,
115
+ mode: "range",
116
+ defaultMonth: calendarProps?.defaultMonth ?? range?.from,
117
+ selected: range,
118
+ onSelect: setRange
119
+ })
120
+ })] });
121
+ }
122
+ //#endregion
123
+ export { DatePicker, DateRangePicker, formatDateDefault };
124
+
125
+ //# sourceMappingURL=date-picker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-picker.js","names":[],"sources":["../../src/components/date-picker.tsx"],"sourcesContent":["\"use client\";\n\nimport { CalendarIcon } from \"lucide-react\";\nimport * as React from \"react\";\nimport type { DateRange } from \"react-day-picker\";\nimport { Button } from \"@/components/button\";\nimport { Calendar, type CalendarProps } from \"@/components/calendar\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@/components/popover\";\nimport { cn } from \"@/lib/cn\";\n\n/**\n * DatePicker.\n *\n * Our outline Button as the trigger, showing the formatted value or a muted\n * placeholder, opening a Popover that holds a single-select Calendar. Picking\n * a day commits the value and closes the popup. Controlled through `value` /\n * `onValueChange`, uncontrolled through `defaultValue`.\n *\n * `DateRangePicker` is the same shape over `mode=\"range\"`. Its popup stays\n * open while both ends are chosen (react-day-picker's first click sets\n * `from === to`, the second widens it), so the user dismisses it.\n */\n\nconst MONTHS = [\n \"January\",\n \"February\",\n \"March\",\n \"April\",\n \"May\",\n \"June\",\n \"July\",\n \"August\",\n \"September\",\n \"October\",\n \"November\",\n \"December\",\n];\n\n/** en-GB order, no library: `15 January 2026`. */\nfunction formatDateDefault(date: Date): string {\n return `${date.getDate()} ${MONTHS[date.getMonth()]} ${date.getFullYear()}`;\n}\n\nfunction useControllable<T>(\n controlled: boolean,\n value: T | undefined,\n defaultValue: T | undefined,\n onChange: ((next: T) => void) | undefined,\n): [T | undefined, (next: T) => void] {\n const [inner, setInner] = React.useState<T | undefined>(defaultValue);\n const current = controlled ? value : inner;\n const set = React.useCallback(\n (next: T) => {\n if (!controlled) setInner(next);\n onChange?.(next);\n },\n [controlled, onChange],\n );\n return [current, set];\n}\n\ntype CalendarPassthrough = Omit<\n CalendarProps,\n \"mode\" | \"selected\" | \"onSelect\" | \"required\" | \"disabled\"\n>;\n\ninterface PickerTriggerProps {\n slot: string;\n placeholder: string;\n label: string | undefined;\n disabled?: boolean | undefined;\n className?: string | undefined;\n \"aria-label\"?: string | undefined;\n}\n\nfunction PickerTrigger({ slot, placeholder, label, className, ...props }: PickerTriggerProps) {\n return (\n <PopoverTrigger\n data-slot={slot}\n data-empty={label ? undefined : true}\n render={<Button variant=\"outline\" />}\n className={cn(\n \"w-60 justify-start font-normal\",\n \"data-[empty]:text-[color:var(--ds-muted-foreground)]\",\n \"[&_svg]:text-[color:var(--ds-muted-foreground)]\",\n className,\n )}\n {...props}\n >\n <CalendarIcon />\n <span data-slot={`${slot}-value`} className=\"truncate\">\n {label ?? placeholder}\n </span>\n </PopoverTrigger>\n );\n}\n\nexport interface DatePickerProps {\n /** The selected date (controlled). */\n value?: Date | undefined;\n /** The initial date (uncontrolled). */\n defaultValue?: Date | undefined;\n /** Called with the picked date, or `undefined` when the selected day is clicked again. */\n onValueChange?: (date: Date | undefined) => void;\n /** Trigger text while nothing is selected. */\n placeholder?: string;\n /** Formats the trigger text; defaults to `15 January 2026`. */\n formatDate?: (date: Date) => string;\n /** Disables the trigger. */\n disabled?: boolean;\n /** Class name for the trigger button. */\n className?: string;\n /** Extra props for the Calendar (e.g. `startMonth`, `captionLayout`, `disabled` matchers via `calendarProps.hidden`). */\n calendarProps?: CalendarPassthrough & { disabled?: CalendarProps[\"disabled\"] };\n /** Accessible name for the trigger. */\n \"aria-label\"?: string;\n}\n\nfunction DatePicker(props: DatePickerProps) {\n const {\n value,\n defaultValue,\n onValueChange,\n placeholder = \"Pick a date\",\n formatDate = formatDateDefault,\n disabled,\n className,\n calendarProps,\n ...rest\n } = props;\n const [date, setDate] = useControllable<Date | undefined>(\n \"value\" in props,\n value,\n defaultValue,\n onValueChange,\n );\n const [open, setOpen] = React.useState(false);\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PickerTrigger\n slot=\"date-picker-trigger\"\n placeholder={placeholder}\n label={date ? formatDate(date) : undefined}\n disabled={disabled}\n className={className}\n {...rest}\n />\n <PopoverContent data-slot=\"date-picker-content\" align=\"start\" className=\"w-auto p-0\">\n <Calendar\n {...calendarProps}\n mode=\"single\"\n defaultMonth={calendarProps?.defaultMonth ?? date}\n selected={date}\n onSelect={(next) => {\n setDate(next);\n setOpen(false);\n }}\n />\n </PopoverContent>\n </Popover>\n );\n}\n\nexport interface DateRangePickerProps extends Omit<\n DatePickerProps,\n \"value\" | \"defaultValue\" | \"onValueChange\"\n> {\n value?: DateRange | undefined;\n defaultValue?: DateRange | undefined;\n onValueChange?: (range: DateRange | undefined) => void;\n /** Separator between the two ends; defaults to an en dash. */\n separator?: string;\n}\n\nfunction formatRange(\n range: DateRange | undefined,\n formatDate: (d: Date) => string,\n separator: string,\n): string | undefined {\n if (!range?.from) return undefined;\n if (!range.to || range.to.getTime() === range.from.getTime()) return formatDate(range.from);\n return `${formatDate(range.from)}${separator}${formatDate(range.to)}`;\n}\n\nfunction DateRangePicker(props: DateRangePickerProps) {\n const {\n value,\n defaultValue,\n onValueChange,\n placeholder = \"Pick a date range\",\n formatDate = formatDateDefault,\n separator = \" \\u2013 \",\n disabled,\n className,\n calendarProps,\n ...rest\n } = props;\n const [range, setRange] = useControllable<DateRange | undefined>(\n \"value\" in props,\n value,\n defaultValue,\n onValueChange,\n );\n\n return (\n <Popover>\n <PickerTrigger\n slot=\"date-range-picker-trigger\"\n placeholder={placeholder}\n label={formatRange(range, formatDate, separator)}\n disabled={disabled}\n className={cn(\"w-72\", className)}\n {...rest}\n />\n <PopoverContent data-slot=\"date-range-picker-content\" align=\"start\" className=\"w-auto p-0\">\n <Calendar\n numberOfMonths={2}\n {...calendarProps}\n mode=\"range\"\n defaultMonth={calendarProps?.defaultMonth ?? range?.from}\n selected={range}\n onSelect={setRange}\n />\n </PopoverContent>\n </Popover>\n );\n}\n\nexport { DatePicker, DateRangePicker, formatDateDefault };\n"],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ "use client";
2
+ import * as React from "react";
3
+ import { Dialog } from "@base-ui/react/dialog";
4
+ //#region src/components/dialog.d.ts
5
+ /**
6
+ * Dialog.
7
+ *
8
+ * `DialogContent` composes Base UI's Portal + Backdrop + Popup so consumers
9
+ * keep writing `<DialogContent>…</DialogContent>`. The Radix `Overlay` part is
10
+ * exported as `DialogOverlay` (a styled Backdrop) for anyone composing by hand.
11
+ *
12
+ * Radix users: `asChild` becomes `render={...}`; `onOpenChange` receives
13
+ * `(open, eventDetails)` rather than just `open`; the popup is only
14
+ * dismissable via pointer when `modal` is true (the default), and
15
+ * `disablePointerDismissal` replaces `onPointerDownOutside` preventDefault.
16
+ */
17
+ declare function Dialog$1(props: Dialog.Root.Props): React.JSX.Element;
18
+ declare function DialogTrigger(props: Dialog.Trigger.Props): React.JSX.Element;
19
+ declare function DialogPortal(props: Dialog.Portal.Props): React.JSX.Element;
20
+ declare function DialogClose(props: Dialog.Close.Props): React.JSX.Element;
21
+ declare function DialogOverlay({ className, ...props }: Dialog.Backdrop.Props): React.JSX.Element;
22
+ export interface DialogContentProps extends Dialog.Popup.Props {
23
+ /** Keep the dialog mounted in the DOM while hidden. */
24
+ keepMounted?: boolean;
25
+ /** Where to portal the dialog; defaults to `<body>`. */
26
+ container?: Dialog.Portal.Props["container"];
27
+ }
28
+ declare function DialogContent({ className, children, keepMounted, container, ...props }: DialogContentProps): React.JSX.Element;
29
+ declare function DialogHeader({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
30
+ declare function DialogBody({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
31
+ declare function DialogFooter({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
32
+ declare function DialogTitle({ className, ...props }: Dialog.Title.Props): React.JSX.Element;
33
+ declare function DialogDescription({ className, ...props }: Dialog.Description.Props): React.JSX.Element;
34
+ //#endregion
35
+ export { Dialog$1 as Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger };
36
+ //# sourceMappingURL=dialog.d.ts.map
@@ -0,0 +1,97 @@
1
+ "use client";
2
+ "use client";
3
+ import { cn } from "../lib/cn.js";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { Dialog } from "@base-ui/react/dialog";
6
+ //#region src/components/dialog.tsx
7
+ /**
8
+ * Dialog.
9
+ *
10
+ * `DialogContent` composes Base UI's Portal + Backdrop + Popup so consumers
11
+ * keep writing `<DialogContent>…</DialogContent>`. The Radix `Overlay` part is
12
+ * exported as `DialogOverlay` (a styled Backdrop) for anyone composing by hand.
13
+ *
14
+ * Radix users: `asChild` becomes `render={...}`; `onOpenChange` receives
15
+ * `(open, eventDetails)` rather than just `open`; the popup is only
16
+ * dismissable via pointer when `modal` is true (the default), and
17
+ * `disablePointerDismissal` replaces `onPointerDownOutside` preventDefault.
18
+ */
19
+ function Dialog$1(props) {
20
+ return /* @__PURE__ */ jsx(Dialog.Root, { ...props });
21
+ }
22
+ function DialogTrigger(props) {
23
+ return /* @__PURE__ */ jsx(Dialog.Trigger, {
24
+ "data-slot": "dialog-trigger",
25
+ ...props
26
+ });
27
+ }
28
+ function DialogPortal(props) {
29
+ return /* @__PURE__ */ jsx(Dialog.Portal, {
30
+ "data-slot": "dialog-portal",
31
+ ...props
32
+ });
33
+ }
34
+ function DialogClose(props) {
35
+ return /* @__PURE__ */ jsx(Dialog.Close, {
36
+ "data-slot": "dialog-close",
37
+ ...props
38
+ });
39
+ }
40
+ function DialogOverlay({ className, ...props }) {
41
+ return /* @__PURE__ */ jsx(Dialog.Backdrop, {
42
+ "data-slot": "dialog-overlay",
43
+ className: cn("fixed inset-0 z-50 backdrop-blur-[2px]", "bg-[color-mix(in_oklab,var(--ds-ink-950)_70%,transparent)]", "open:animate-in open:fade-in-0 closed:animate-out closed:fade-out-0", "duration-[var(--ds-duration-base)] ease-[var(--ds-ease-out)]", className),
44
+ ...props
45
+ });
46
+ }
47
+ function DialogContent({ className, children, keepMounted, container, ...props }) {
48
+ return /* @__PURE__ */ jsxs(DialogPortal, {
49
+ keepMounted,
50
+ container,
51
+ children: [/* @__PURE__ */ jsx(DialogOverlay, {}), /* @__PURE__ */ jsx(Dialog.Popup, {
52
+ "data-slot": "dialog-content",
53
+ className: cn("fixed left-1/2 top-1/2 z-50 grid w-full max-w-[440px] -translate-x-1/2 -translate-y-1/2 overflow-hidden outline-none", "rounded-[var(--ds-radius-xl)] border border-[var(--ds-border)]", "bg-[var(--ds-popover)] text-[color:var(--ds-popover-foreground)] shadow-[var(--ds-shadow-lg)]", "open:animate-in open:fade-in-0 open:zoom-in-95", "closed:animate-out closed:fade-out-0 closed:zoom-out-95", "duration-[var(--ds-duration-base)] ease-[var(--ds-ease-out)]", className),
54
+ ...props,
55
+ children
56
+ })]
57
+ });
58
+ }
59
+ function DialogHeader({ className, ...props }) {
60
+ return /* @__PURE__ */ jsx("div", {
61
+ "data-slot": "dialog-header",
62
+ className: cn("flex flex-col gap-1.5 px-5 pb-1 pt-5 text-left", className),
63
+ ...props
64
+ });
65
+ }
66
+ function DialogBody({ className, ...props }) {
67
+ return /* @__PURE__ */ jsx("div", {
68
+ "data-slot": "dialog-body",
69
+ className: cn("px-5 pb-5 pt-1", className),
70
+ ...props
71
+ });
72
+ }
73
+ function DialogFooter({ className, ...props }) {
74
+ return /* @__PURE__ */ jsx("div", {
75
+ "data-slot": "dialog-footer",
76
+ className: cn("flex flex-col-reverse gap-2 border-t border-[var(--ds-border-subtle)] bg-[var(--ds-card)] px-5 py-3.5 sm:flex-row sm:justify-end", className),
77
+ ...props
78
+ });
79
+ }
80
+ function DialogTitle({ className, ...props }) {
81
+ return /* @__PURE__ */ jsx(Dialog.Title, {
82
+ "data-slot": "dialog-title",
83
+ className: cn("text-[length:var(--ds-text-body-md)] font-semibold leading-none tracking-[-0.01em] text-[color:var(--ds-foreground)]", className),
84
+ ...props
85
+ });
86
+ }
87
+ function DialogDescription({ className, ...props }) {
88
+ return /* @__PURE__ */ jsx(Dialog.Description, {
89
+ "data-slot": "dialog-description",
90
+ className: cn("text-[length:var(--ds-text-caption-lg)] text-[color:var(--ds-muted-foreground)]", className),
91
+ ...props
92
+ });
93
+ }
94
+ //#endregion
95
+ export { Dialog$1 as Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger };
96
+
97
+ //# sourceMappingURL=dialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialog.js","names":["Dialog","DialogPrimitive"],"sources":["../../src/components/dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { Dialog as DialogPrimitive } from \"@base-ui/react/dialog\";\nimport type * as React from \"react\";\nimport { cn } from \"@/lib/cn\";\n\n/**\n * Dialog.\n *\n * `DialogContent` composes Base UI's Portal + Backdrop + Popup so consumers\n * keep writing `<DialogContent>…</DialogContent>`. The Radix `Overlay` part is\n * exported as `DialogOverlay` (a styled Backdrop) for anyone composing by hand.\n *\n * Radix users: `asChild` becomes `render={...}`; `onOpenChange` receives\n * `(open, eventDetails)` rather than just `open`; the popup is only\n * dismissable via pointer when `modal` is true (the default), and\n * `disablePointerDismissal` replaces `onPointerDownOutside` preventDefault.\n */\nfunction Dialog(props: DialogPrimitive.Root.Props) {\n return <DialogPrimitive.Root {...props} />;\n}\n\nfunction DialogTrigger(props: DialogPrimitive.Trigger.Props) {\n return <DialogPrimitive.Trigger data-slot=\"dialog-trigger\" {...props} />;\n}\n\nfunction DialogPortal(props: DialogPrimitive.Portal.Props) {\n return <DialogPrimitive.Portal data-slot=\"dialog-portal\" {...props} />;\n}\n\nfunction DialogClose(props: DialogPrimitive.Close.Props) {\n return <DialogPrimitive.Close data-slot=\"dialog-close\" {...props} />;\n}\n\nfunction DialogOverlay({ className, ...props }: DialogPrimitive.Backdrop.Props) {\n return (\n <DialogPrimitive.Backdrop\n data-slot=\"dialog-overlay\"\n className={cn(\n \"fixed inset-0 z-50 backdrop-blur-[2px]\",\n \"bg-[color-mix(in_oklab,var(--ds-ink-950)_70%,transparent)]\",\n \"open:animate-in open:fade-in-0 closed:animate-out closed:fade-out-0\",\n \"duration-[var(--ds-duration-base)] ease-[var(--ds-ease-out)]\",\n className,\n )}\n {...props}\n />\n );\n}\n\nexport interface DialogContentProps extends DialogPrimitive.Popup.Props {\n /** Keep the dialog mounted in the DOM while hidden. */\n keepMounted?: boolean;\n /** Where to portal the dialog; defaults to `<body>`. */\n container?: DialogPrimitive.Portal.Props[\"container\"];\n}\n\nfunction DialogContent({ className, children, keepMounted, container, ...props }: DialogContentProps) {\n return (\n <DialogPortal keepMounted={keepMounted} container={container}>\n <DialogOverlay />\n <DialogPrimitive.Popup\n data-slot=\"dialog-content\"\n className={cn(\n \"fixed left-1/2 top-1/2 z-50 grid w-full max-w-[440px] -translate-x-1/2 -translate-y-1/2 overflow-hidden outline-none\",\n \"rounded-[var(--ds-radius-xl)] border border-[var(--ds-border)]\",\n \"bg-[var(--ds-popover)] text-[color:var(--ds-popover-foreground)] shadow-[var(--ds-shadow-lg)]\",\n \"open:animate-in open:fade-in-0 open:zoom-in-95\",\n \"closed:animate-out closed:fade-out-0 closed:zoom-out-95\",\n \"duration-[var(--ds-duration-base)] ease-[var(--ds-ease-out)]\",\n className,\n )}\n {...props}\n >\n {children}\n </DialogPrimitive.Popup>\n </DialogPortal>\n );\n}\n\nfunction DialogHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"dialog-header\"\n className={cn(\"flex flex-col gap-1.5 px-5 pb-1 pt-5 text-left\", className)}\n {...props}\n />\n );\n}\n\nfunction DialogBody({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div data-slot=\"dialog-body\" className={cn(\"px-5 pb-5 pt-1\", className)} {...props} />;\n}\n\nfunction DialogFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"dialog-footer\"\n className={cn(\n \"flex flex-col-reverse gap-2 border-t border-[var(--ds-border-subtle)] bg-[var(--ds-card)] px-5 py-3.5 sm:flex-row sm:justify-end\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) {\n return (\n <DialogPrimitive.Title\n data-slot=\"dialog-title\"\n className={cn(\n \"text-[length:var(--ds-text-body-md)] font-semibold leading-none tracking-[-0.01em] text-[color:var(--ds-foreground)]\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DialogDescription({ className, ...props }: DialogPrimitive.Description.Props) {\n return (\n <DialogPrimitive.Description\n data-slot=\"dialog-description\"\n className={cn(\n \"text-[length:var(--ds-text-caption-lg)] text-[color:var(--ds-muted-foreground)]\",\n className,\n )}\n {...props}\n />\n );\n}\n\nexport {\n Dialog,\n DialogPortal,\n DialogOverlay,\n DialogClose,\n DialogTrigger,\n DialogContent,\n DialogHeader,\n DialogBody,\n DialogFooter,\n DialogTitle,\n DialogDescription,\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAkBA,SAASA,SAAO,OAAmC;CACjD,OAAO,oBAACC,OAAgB,MAAjB,EAAsB,GAAI,MAAQ,CAAA;AAC3C;AAEA,SAAS,cAAc,OAAsC;CAC3D,OAAO,oBAACA,OAAgB,SAAjB;EAAyB,aAAU;EAAiB,GAAI;CAAQ,CAAA;AACzE;AAEA,SAAS,aAAa,OAAqC;CACzD,OAAO,oBAACA,OAAgB,QAAjB;EAAwB,aAAU;EAAgB,GAAI;CAAQ,CAAA;AACvE;AAEA,SAAS,YAAY,OAAoC;CACvD,OAAO,oBAACA,OAAgB,OAAjB;EAAuB,aAAU;EAAe,GAAI;CAAQ,CAAA;AACrE;AAEA,SAAS,cAAc,EAAE,WAAW,GAAG,SAAyC;CAC9E,OACE,oBAACA,OAAgB,UAAjB;EACE,aAAU;EACV,WAAW,GACT,0CACA,8DACA,uEACA,gEACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AASA,SAAS,cAAc,EAAE,WAAW,UAAU,aAAa,WAAW,GAAG,SAA6B;CACpG,OACE,qBAAC,cAAD;EAA2B;EAAwB;EAAnD,UAAA,CACE,oBAAC,eAAD,CAAgB,CAAA,GAChB,oBAACA,OAAgB,OAAjB;GACE,aAAU;GACV,WAAW,GACT,wHACA,kEACA,iGACA,kDACA,2DACA,gEACA,SACF;GACA,GAAI;GAEH;EACoB,CAAA,CACX;;AAElB;AAEA,SAAS,aAAa,EAAE,WAAW,GAAG,SAAsC;CAC1E,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,kDAAkD,SAAS;EACzE,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,WAAW,EAAE,WAAW,GAAG,SAAsC;CACxE,OAAO,oBAAC,OAAD;EAAK,aAAU;EAAc,WAAW,GAAG,kBAAkB,SAAS;EAAG,GAAI;CAAQ,CAAA;AAC9F;AAEA,SAAS,aAAa,EAAE,WAAW,GAAG,SAAsC;CAC1E,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,oIACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,YAAY,EAAE,WAAW,GAAG,SAAsC;CACzE,OACE,oBAACA,OAAgB,OAAjB;EACE,aAAU;EACV,WAAW,GACT,wHACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,kBAAkB,EAAE,WAAW,GAAG,SAA4C;CACrF,OACE,oBAACA,OAAgB,aAAjB;EACE,aAAU;EACV,WAAW,GACT,mFACA,SACF;EACA,GAAI;CACL,CAAA;AAEL"}