@datum-cloud/datum-ui 0.2.0-alpha.3 → 0.2.0-alpha.4

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 (132) hide show
  1. package/README.md +46 -21
  2. package/dist/alert/index.mjs +3 -0
  3. package/dist/alert-BC2Mccfo.mjs +95 -0
  4. package/dist/autocomplete/index.mjs +7 -0
  5. package/dist/autocomplete-DZtI97HP.mjs +295 -0
  6. package/dist/avatar-stack/index.mjs +5 -0
  7. package/dist/avatar-stack-JCfBlPB9.mjs +80 -0
  8. package/dist/badge/index.mjs +3 -0
  9. package/dist/badge-bFgeYceE.mjs +185 -0
  10. package/dist/breadcrumb/index.mjs +4 -0
  11. package/dist/breadcrumb-BGYJgom_.mjs +71 -0
  12. package/dist/button/index.mjs +4 -0
  13. package/dist/button-AzpnV-WB.mjs +49 -0
  14. package/dist/button-C1wRfGtT.mjs +230 -0
  15. package/dist/button-group/index.mjs +5 -0
  16. package/dist/button-group-C1IB2K5s.mjs +40 -0
  17. package/dist/calendar/index.mjs +5 -0
  18. package/dist/calendar-DlIHeWb0.mjs +113 -0
  19. package/dist/card/index.mjs +4 -0
  20. package/dist/card-3Kd0VdNf.mjs +63 -0
  21. package/dist/chart/index.mjs +4 -0
  22. package/dist/chart-BZqUKpkh.mjs +143 -0
  23. package/dist/checkbox/index.mjs +4 -0
  24. package/dist/checkbox-LG1OKTpG.mjs +34 -0
  25. package/dist/col-lrLMZaTJ.mjs +184 -0
  26. package/dist/collapsible/index.mjs +3 -0
  27. package/dist/collapsible-Bt9UYfv3.mjs +9 -0
  28. package/dist/command/index.mjs +5 -0
  29. package/dist/command-s0Yv3abE.mjs +86 -0
  30. package/dist/components/features/date-picker/index.d.ts +3 -0
  31. package/dist/components/features/date-picker/index.d.ts.map +1 -0
  32. package/dist/components/features/dropzone/index.d.ts +1 -0
  33. package/dist/components/features/dropzone/index.d.ts.map +1 -1
  34. package/dist/date-picker/index.mjs +9 -0
  35. package/dist/{datum.provider-D6VMjSV0.mjs → datum.provider-B77goJgl.mjs} +1 -1
  36. package/dist/dialog/index.mjs +5 -0
  37. package/dist/dialog-DXBaT9gA.mjs +86 -0
  38. package/dist/dialog-bnMMf9GD.mjs +73 -0
  39. package/dist/dropdown/index.mjs +3 -0
  40. package/dist/dropdown-DtSa_lqc.mjs +112 -0
  41. package/dist/dropzone/index.mjs +5 -0
  42. package/dist/dropzone-BkOnwrS4.mjs +221 -0
  43. package/dist/empty-content/index.mjs +3 -0
  44. package/dist/empty-content-BM9rzI13.mjs +196 -0
  45. package/dist/exports/map.d.ts +3 -0
  46. package/dist/exports/map.d.ts.map +1 -0
  47. package/dist/form/index.mjs +146 -0
  48. package/dist/grid/index.mjs +3 -0
  49. package/dist/hooks/index.mjs +2 -3
  50. package/dist/hover-card/index.mjs +4 -0
  51. package/dist/hover-card-CUPfFUqE.mjs +33 -0
  52. package/dist/icon-wrapper-9ticVbRL.mjs +14 -0
  53. package/dist/icons/index.mjs +3 -3
  54. package/dist/index.mjs +66 -8
  55. package/dist/input/index.mjs +5 -0
  56. package/dist/input-DuyjEKEW.mjs +17 -0
  57. package/dist/input-fzXBheCN.mjs +17 -0
  58. package/dist/input-group/index.mjs +7 -0
  59. package/dist/input-group-CPaFSTEV.mjs +80 -0
  60. package/dist/input-number/index.mjs +6 -0
  61. package/dist/input-number-9o62JHRl.mjs +106 -0
  62. package/dist/input-with-addons/index.mjs +3 -0
  63. package/dist/input-with-addons-BQn7KCTU.mjs +30 -0
  64. package/dist/label/index.mjs +4 -0
  65. package/dist/label-_ste_Re3.mjs +44 -0
  66. package/dist/link-button-TIF2Zdrk.mjs +36 -0
  67. package/dist/loader-overlay/index.mjs +3 -0
  68. package/dist/loader-overlay-DUaQSZQP.mjs +17 -0
  69. package/dist/map/index.mjs +13 -0
  70. package/dist/map-Df8QMcX0.mjs +1094 -0
  71. package/dist/more-actions/index.mjs +5 -0
  72. package/dist/more-actions-Ch1f6Mh3.mjs +54 -0
  73. package/dist/nprogress/index.mjs +32 -0
  74. package/dist/page-title/index.mjs +3 -0
  75. package/dist/page-title-BJuo81rT.mjs +26 -0
  76. package/dist/popover/index.mjs +4 -0
  77. package/dist/popover-SQlKSz6L.mjs +36 -0
  78. package/dist/provider/index.mjs +4 -0
  79. package/dist/radio-group/index.mjs +4 -0
  80. package/dist/radio-group-Oshv0b-U.mjs +49 -0
  81. package/dist/select/index.mjs +4 -0
  82. package/dist/select-DVlEzD2W.mjs +166 -0
  83. package/dist/separator/index.mjs +4 -0
  84. package/dist/separator-T2ppyD-8.mjs +18 -0
  85. package/dist/sheet/index.mjs +5 -0
  86. package/dist/sheet-BKiCwtNO.mjs +45 -0
  87. package/dist/sheet-CtnP6gTD.mjs +77 -0
  88. package/dist/sidebar/index.mjs +11 -0
  89. package/dist/sidebar-DfqezV8t.mjs +945 -0
  90. package/dist/skeleton/index.mjs +4 -0
  91. package/dist/skeleton-vzbxA-DQ.mjs +13 -0
  92. package/dist/spinner/index.mjs +4 -0
  93. package/dist/spinner-BE7k2bAD.mjs +16 -0
  94. package/dist/{icon-wrapper-BgPkifId.mjs → spinner.icon-Bg8zgGh0.mjs} +1 -12
  95. package/dist/stepper/index.mjs +5 -0
  96. package/dist/stepper-SWB-u_nM.mjs +323 -0
  97. package/dist/switch/index.mjs +4 -0
  98. package/dist/switch-Calk7Gyw.mjs +32 -0
  99. package/dist/table/index.mjs +4 -0
  100. package/dist/table-CsXBcQLI.mjs +68 -0
  101. package/dist/tabs/index.mjs +3 -0
  102. package/dist/tabs-D8n-dqnw.mjs +52 -0
  103. package/dist/tag-input/index.mjs +5 -0
  104. package/dist/tag-input-Di7SDNbK.mjs +284 -0
  105. package/dist/task-queue/index.mjs +7 -0
  106. package/dist/task-queue-dropdown-DW72ikDH.mjs +1356 -0
  107. package/dist/textarea/index.mjs +5 -0
  108. package/dist/textarea-CxE3YbC7.mjs +17 -0
  109. package/dist/textarea-QYRcDEpK.mjs +15 -0
  110. package/dist/theme/index.mjs +4 -0
  111. package/dist/theme-script-XBouzsNR.mjs +66 -0
  112. package/dist/to-api-format-C2xjQUcI.mjs +1506 -0
  113. package/dist/toast/index.mjs +3 -0
  114. package/dist/tooltip/index.mjs +4 -0
  115. package/dist/tooltip-Dd3ActSS.mjs +74 -0
  116. package/dist/typography/index.mjs +3 -0
  117. package/dist/typography-UA7ZZvgJ.mjs +200 -0
  118. package/dist/use-copy-to-clipboard-ki-WoTml.mjs +31 -0
  119. package/dist/use-stepper-BaToCYMs.mjs +2017 -0
  120. package/dist/{use-copy-to-clipboard-BfrpD6G8.mjs → use-toast-mdn_CqRY.mjs} +34 -27
  121. package/dist/utils/index.mjs +0 -1
  122. package/dist/utils-Bfgoe-Gm.mjs +20 -0
  123. package/dist/visually-hidden/index.mjs +3 -0
  124. package/dist/visuallyhidden-aaTUk4Yo.mjs +7 -0
  125. package/package.json +208 -8
  126. package/dist/components/index.mjs +0 -8
  127. package/dist/providers/index.mjs +0 -4
  128. package/dist/theme-script-DHyLk25i.mjs +0 -11128
  129. /package/dist/{close.icon-chkXPAUC.mjs → close.icon-CMNMoXM_.mjs} +0 -0
  130. /package/dist/{map-leaflet-imports-OKaoesjZ.mjs → map-leaflet-imports-CdzvEnzY.mjs} +0 -0
  131. /package/dist/{theme.provider-DpFLwtHe.mjs → theme.provider-DgGshapa.mjs} +0 -0
  132. /package/dist/{use-debounce-BYB-jPeX.mjs → use-debounce-DQ1tmxOL.mjs} +0 -0
@@ -0,0 +1,1506 @@
1
+ import { t as cn } from "./cn-DWCc1QRE.mjs";
2
+ import { t as Button } from "./button-C1wRfGtT.mjs";
3
+ import { t as Separator } from "./separator-T2ppyD-8.mjs";
4
+ import { t as Button$1 } from "./button-AzpnV-WB.mjs";
5
+ import { t as Icon } from "./icon-wrapper-9ticVbRL.mjs";
6
+ import { t as Calendar$1 } from "./calendar-DlIHeWb0.mjs";
7
+ import { t as Input } from "./input-fzXBheCN.mjs";
8
+ import { i as PopoverTrigger, r as PopoverContent, t as Popover } from "./popover-SQlKSz6L.mjs";
9
+ import { i as SelectItem, l as SelectTrigger, n as SelectContent, t as Select, u as SelectValue } from "./select-DVlEzD2W.mjs";
10
+ import { cva } from "class-variance-authority";
11
+ import { Calendar, CalendarIcon, Globe, X } from "lucide-react";
12
+ import * as React$1 from "react";
13
+ import { useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
14
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
15
+ import { endOfDay, endOfMonth, endOfWeek, endOfYear, format, isSameDay, isSameYear, parse, startOfDay, startOfMonth, startOfWeek, startOfYear, subDays, subHours, subMinutes } from "date-fns";
16
+ import { formatInTimeZone, fromZonedTime, toDate, toZonedTime } from "date-fns-tz";
17
+
18
+ //#region src/components/features/calendar-date-picker/calendar-date-picker.tsx
19
+ const months = [
20
+ "January",
21
+ "February",
22
+ "March",
23
+ "April",
24
+ "May",
25
+ "June",
26
+ "July",
27
+ "August",
28
+ "September",
29
+ "October",
30
+ "November",
31
+ "December"
32
+ ];
33
+ const multiSelectVariants = cva("flex font-normal shadow-none items-center justify-center whitespace-nowrap rounded-md text-sm text-foreground ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", {
34
+ variants: { variant: {
35
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
36
+ destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
37
+ outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
38
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
39
+ ghost: "hover:bg-accent hover:text-accent-foreground text-background",
40
+ link: "text-primary underline-offset-4 hover:underline text-background"
41
+ } },
42
+ defaultVariants: { variant: "default" }
43
+ });
44
+ function CalendarDatePicker({ ref, id = "calendar-date-picker", className, triggerClassName, date, closeOnSelect = false, numberOfMonths = 2, yearsRange = 10, onDateSelect, variant, placeholder, excludePresets, customPresets, minDate, maxDate, disableFuture = false, disablePast = false, maxRange, ...props }) {
45
+ const [isPopoverOpen, setIsPopoverOpen] = React$1.useState(false);
46
+ const [selectedRange, setSelectedRange] = React$1.useState(numberOfMonths === 2 ? "This Year" : "Today");
47
+ const [monthFrom, setMonthFrom] = React$1.useState(date?.from);
48
+ const [yearFrom, setYearFrom] = React$1.useState(date?.from?.getFullYear());
49
+ const [monthTo, setMonthTo] = React$1.useState(numberOfMonths === 2 ? date?.to : date?.from);
50
+ const [yearTo, setYearTo] = React$1.useState(numberOfMonths === 2 ? date?.to?.getFullYear() : date?.from?.getFullYear());
51
+ const [highlightedPart, setHighlightedPart] = React$1.useState(null);
52
+ const [pendingDate, setPendingDate] = React$1.useState(date);
53
+ const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
54
+ const today = /* @__PURE__ */ new Date();
55
+ const effectiveMinDate = React$1.useMemo(() => {
56
+ let min = minDate;
57
+ if (disablePast) {
58
+ const todayStart = startOfDay(today);
59
+ min = min ? min > todayStart ? min : todayStart : todayStart;
60
+ }
61
+ return min;
62
+ }, [
63
+ minDate,
64
+ disablePast,
65
+ today
66
+ ]);
67
+ const effectiveMaxDate = React$1.useMemo(() => {
68
+ let max = maxDate;
69
+ if (disableFuture) {
70
+ const todayEnd = endOfDay(today);
71
+ max = max ? max < todayEnd ? max : todayEnd : todayEnd;
72
+ }
73
+ return max;
74
+ }, [
75
+ maxDate,
76
+ disableFuture,
77
+ today
78
+ ]);
79
+ const isDateDisabled = React$1.useCallback((date) => {
80
+ if (effectiveMinDate && date < effectiveMinDate) return true;
81
+ if (effectiveMaxDate && date > effectiveMaxDate) return true;
82
+ return false;
83
+ }, [effectiveMinDate, effectiveMaxDate]);
84
+ const getDaysDifference = React$1.useCallback((from, to) => {
85
+ const timeDiff = Math.abs(to.getTime() - from.getTime());
86
+ return Math.ceil(timeDiff / (1e3 * 60 * 60 * 24));
87
+ }, []);
88
+ const isRangeValid = React$1.useCallback((from, to) => {
89
+ if (!maxRange) return true;
90
+ if (numberOfMonths === 1) return true;
91
+ return getDaysDifference(from, to) <= maxRange;
92
+ }, [
93
+ maxRange,
94
+ numberOfMonths,
95
+ getDaysDifference
96
+ ]);
97
+ const adjustRangeToMaxRange = React$1.useCallback((from, to) => {
98
+ if (!maxRange || numberOfMonths === 1) return {
99
+ from,
100
+ to
101
+ };
102
+ if (getDaysDifference(from, to) <= maxRange) return {
103
+ from,
104
+ to
105
+ };
106
+ const adjustedTo = new Date(from.getTime() + maxRange * 24 * 60 * 60 * 1e3);
107
+ if (effectiveMaxDate && adjustedTo > effectiveMaxDate) {
108
+ const adjustedFrom = /* @__PURE__ */ new Date(to.getTime() - maxRange * 24 * 60 * 60 * 1e3);
109
+ if (effectiveMinDate && adjustedFrom < effectiveMinDate) return {
110
+ from,
111
+ to
112
+ };
113
+ return {
114
+ from: adjustedFrom,
115
+ to
116
+ };
117
+ }
118
+ return {
119
+ from,
120
+ to: adjustedTo
121
+ };
122
+ }, [
123
+ maxRange,
124
+ numberOfMonths,
125
+ getDaysDifference,
126
+ effectiveMinDate,
127
+ effectiveMaxDate
128
+ ]);
129
+ React$1.useEffect(() => {
130
+ setPendingDate(date);
131
+ }, [date]);
132
+ const handleClose = () => setIsPopoverOpen(false);
133
+ const handleTogglePopover = () => setIsPopoverOpen((prev) => !prev);
134
+ const handleClear = (e) => {
135
+ e.stopPropagation();
136
+ onDateSelect(void 0);
137
+ setPendingDate({
138
+ from: void 0,
139
+ to: void 0
140
+ });
141
+ setSelectedRange(null);
142
+ };
143
+ const handleApply = () => {
144
+ if (pendingDate?.from) onDateSelect({
145
+ from: pendingDate.from,
146
+ to: pendingDate.to || pendingDate.from
147
+ });
148
+ setIsPopoverOpen(false);
149
+ };
150
+ const handleReset = () => {
151
+ setPendingDate(date);
152
+ setMonthFrom(date?.from);
153
+ setYearFrom(date?.from?.getFullYear());
154
+ setMonthTo(numberOfMonths === 2 ? date?.to : date?.from);
155
+ setYearTo(numberOfMonths === 2 ? date?.to?.getFullYear() : date?.from?.getFullYear());
156
+ setSelectedRange(null);
157
+ };
158
+ const selectDateRange = (from, to, range) => {
159
+ const startDate = startOfDay(toDate(from, { timeZone }));
160
+ const endDate = numberOfMonths === 2 ? endOfDay(toDate(to, { timeZone })) : startDate;
161
+ if (isDateDisabled(startDate) || isDateDisabled(endDate)) return;
162
+ let finalDates = {
163
+ from: startDate,
164
+ to: endDate
165
+ };
166
+ if (numberOfMonths === 2 && !isRangeValid(startDate, endDate)) {
167
+ finalDates = adjustRangeToMaxRange(startDate, endDate);
168
+ if (!isRangeValid(finalDates.from, finalDates.to)) return;
169
+ }
170
+ setPendingDate({
171
+ from: finalDates.from,
172
+ to: finalDates.to
173
+ });
174
+ setSelectedRange(range);
175
+ setMonthFrom(finalDates.from);
176
+ setYearFrom(finalDates.from.getFullYear());
177
+ setMonthTo(finalDates.to);
178
+ setYearTo(finalDates.to.getFullYear());
179
+ if (closeOnSelect) {
180
+ onDateSelect({
181
+ from: finalDates.from,
182
+ to: finalDates.to
183
+ });
184
+ setIsPopoverOpen(false);
185
+ }
186
+ };
187
+ const handleDateSelect = (range) => {
188
+ if (range) {
189
+ let from = startOfDay(toDate(range.from, { timeZone }));
190
+ let to = range.to ? endOfDay(toDate(range.to, { timeZone })) : from;
191
+ if (numberOfMonths === 1) if (range.from !== pendingDate?.from) to = from;
192
+ else from = startOfDay(toDate(range.to, { timeZone }));
193
+ if (isDateDisabled(from) || isDateDisabled(to)) return;
194
+ let finalDates = {
195
+ from,
196
+ to
197
+ };
198
+ if (numberOfMonths === 2 && !isRangeValid(from, to)) {
199
+ finalDates = adjustRangeToMaxRange(from, to);
200
+ if (!isRangeValid(finalDates.from, finalDates.to)) return;
201
+ }
202
+ setPendingDate({
203
+ from: finalDates.from,
204
+ to: finalDates.to
205
+ });
206
+ setMonthFrom(finalDates.from);
207
+ setYearFrom(finalDates.from.getFullYear());
208
+ setMonthTo(finalDates.to);
209
+ setYearTo(finalDates.to.getFullYear());
210
+ if (closeOnSelect) {
211
+ onDateSelect({
212
+ from: finalDates.from,
213
+ to: finalDates.to
214
+ });
215
+ setIsPopoverOpen(false);
216
+ }
217
+ }
218
+ setSelectedRange(null);
219
+ };
220
+ const handleMonthChange = (newMonthIndex, part) => {
221
+ setSelectedRange(null);
222
+ if (part === "from") {
223
+ if (yearFrom !== void 0) {
224
+ if (newMonthIndex < 0 || newMonthIndex > yearsRange + 1) return;
225
+ const newMonth = new Date(yearFrom, newMonthIndex, 1);
226
+ const from = numberOfMonths === 2 ? startOfMonth(toDate(newMonth, { timeZone })) : pendingDate?.from ? new Date(pendingDate.from.getFullYear(), newMonth.getMonth(), pendingDate.from.getDate()) : newMonth;
227
+ const to = numberOfMonths === 2 ? pendingDate?.to ? endOfDay(toDate(pendingDate.to, { timeZone })) : endOfMonth(toDate(newMonth, { timeZone })) : from;
228
+ if (from <= to) {
229
+ setPendingDate({
230
+ from,
231
+ to
232
+ });
233
+ setMonthFrom(newMonth);
234
+ setMonthTo(pendingDate?.to);
235
+ }
236
+ }
237
+ } else if (yearTo !== void 0) {
238
+ if (newMonthIndex < 0 || newMonthIndex > yearsRange + 1) return;
239
+ const newMonth = new Date(yearTo, newMonthIndex, 1);
240
+ const from = pendingDate?.from ? startOfDay(toDate(pendingDate.from, { timeZone })) : startOfMonth(toDate(newMonth, { timeZone }));
241
+ const to = numberOfMonths === 2 ? endOfMonth(toDate(newMonth, { timeZone })) : from;
242
+ if (from <= to) {
243
+ setPendingDate({
244
+ from,
245
+ to
246
+ });
247
+ setMonthTo(newMonth);
248
+ setMonthFrom(pendingDate?.from);
249
+ }
250
+ }
251
+ };
252
+ const years = Array.from({ length: yearsRange + 1 }, (_, i) => today.getFullYear() - yearsRange / 2 + i);
253
+ const handleYearChange = (newYear, part) => {
254
+ setSelectedRange(null);
255
+ if (part === "from") {
256
+ if (years.includes(newYear)) {
257
+ const newMonth = monthFrom ? new Date(newYear, monthFrom ? monthFrom.getMonth() : 0, 1) : new Date(newYear, 0, 1);
258
+ const from = numberOfMonths === 2 ? startOfMonth(toDate(newMonth, { timeZone })) : pendingDate?.from ? new Date(newYear, newMonth.getMonth(), pendingDate.from.getDate()) : newMonth;
259
+ const to = numberOfMonths === 2 ? pendingDate?.to ? endOfDay(toDate(pendingDate.to, { timeZone })) : endOfMonth(toDate(newMonth, { timeZone })) : from;
260
+ if (from <= to) {
261
+ setPendingDate({
262
+ from,
263
+ to
264
+ });
265
+ setYearFrom(newYear);
266
+ setMonthFrom(newMonth);
267
+ setYearTo(pendingDate?.to?.getFullYear());
268
+ setMonthTo(pendingDate?.to);
269
+ }
270
+ }
271
+ } else if (years.includes(newYear)) {
272
+ const newMonth = monthTo ? new Date(newYear, monthTo.getMonth(), 1) : new Date(newYear, 0, 1);
273
+ const from = pendingDate?.from ? startOfDay(toDate(pendingDate.from, { timeZone })) : startOfMonth(toDate(newMonth, { timeZone }));
274
+ const to = numberOfMonths === 2 ? endOfMonth(toDate(newMonth, { timeZone })) : from;
275
+ if (from <= to) {
276
+ setPendingDate({
277
+ from,
278
+ to
279
+ });
280
+ setYearTo(newYear);
281
+ setMonthTo(newMonth);
282
+ setYearFrom(pendingDate?.from?.getFullYear());
283
+ setMonthFrom(pendingDate?.from);
284
+ }
285
+ }
286
+ };
287
+ const defaultDateRangePresets = [
288
+ {
289
+ key: "today",
290
+ label: "Today",
291
+ start: today,
292
+ end: today
293
+ },
294
+ {
295
+ key: "yesterday",
296
+ label: "Yesterday",
297
+ start: subDays(today, 1),
298
+ end: subDays(today, 1)
299
+ },
300
+ {
301
+ key: "thisWeek",
302
+ label: "This Week",
303
+ start: startOfWeek(today, { weekStartsOn: 1 }),
304
+ end: endOfWeek(today, { weekStartsOn: 1 })
305
+ },
306
+ {
307
+ key: "lastWeek",
308
+ label: "Last Week",
309
+ start: subDays(startOfWeek(today, { weekStartsOn: 1 }), 7),
310
+ end: subDays(endOfWeek(today, { weekStartsOn: 1 }), 7)
311
+ },
312
+ {
313
+ key: "last7Days",
314
+ label: "Last 7 Days",
315
+ start: subDays(today, 6),
316
+ end: today
317
+ },
318
+ {
319
+ key: "thisMonth",
320
+ label: "This Month",
321
+ start: startOfMonth(today),
322
+ end: endOfMonth(today)
323
+ },
324
+ {
325
+ key: "lastMonth",
326
+ label: "Last Month",
327
+ start: startOfMonth(subDays(today, today.getDate())),
328
+ end: endOfMonth(subDays(today, today.getDate()))
329
+ },
330
+ {
331
+ key: "thisYear",
332
+ label: "This Year",
333
+ start: startOfYear(today),
334
+ end: endOfYear(today)
335
+ },
336
+ {
337
+ key: "lastYear",
338
+ label: "Last Year",
339
+ start: startOfYear(subDays(today, 365)),
340
+ end: endOfYear(subDays(today, 365))
341
+ }
342
+ ];
343
+ const allDateRangePresets = customPresets || defaultDateRangePresets;
344
+ const dateRanges = React$1.useMemo(() => {
345
+ return allDateRangePresets.filter((preset) => {
346
+ if (excludePresets?.includes(preset.key)) return false;
347
+ const startValid = !isDateDisabled(preset.start);
348
+ const endValid = !isDateDisabled(preset.end);
349
+ const rangeValid = numberOfMonths === 1 || isRangeValid(preset.start, preset.end);
350
+ return startValid && endValid && rangeValid;
351
+ });
352
+ }, [
353
+ isDateDisabled,
354
+ excludePresets,
355
+ numberOfMonths,
356
+ isRangeValid
357
+ ]);
358
+ const handleMouseOver = (part) => {
359
+ setHighlightedPart(part);
360
+ };
361
+ const handleMouseLeave = () => {
362
+ setHighlightedPart(null);
363
+ };
364
+ const handleWheel = (event) => {
365
+ event.preventDefault();
366
+ setSelectedRange(null);
367
+ if (highlightedPart === "firstDay") {
368
+ const newDate = new Date(pendingDate?.from);
369
+ const increment = event.deltaY > 0 ? -1 : 1;
370
+ newDate.setDate(newDate.getDate() + increment);
371
+ if (newDate <= pendingDate?.to) {
372
+ numberOfMonths === 2 ? setPendingDate({
373
+ from: newDate,
374
+ to: new Date(pendingDate?.to)
375
+ }) : setPendingDate({
376
+ from: newDate,
377
+ to: newDate
378
+ });
379
+ setMonthFrom(newDate);
380
+ } else if (newDate > pendingDate?.to && numberOfMonths === 1) {
381
+ setPendingDate({
382
+ from: newDate,
383
+ to: newDate
384
+ });
385
+ setMonthFrom(newDate);
386
+ }
387
+ } else if (highlightedPart === "firstMonth") handleMonthChange((monthFrom ? monthFrom.getMonth() : 0) + (event.deltaY > 0 ? -1 : 1), "from");
388
+ else if (highlightedPart === "firstYear" && yearFrom !== void 0) handleYearChange(yearFrom + (event.deltaY > 0 ? -1 : 1), "from");
389
+ else if (highlightedPart === "secondDay") {
390
+ const newDate = new Date(pendingDate?.to);
391
+ const increment = event.deltaY > 0 ? -1 : 1;
392
+ newDate.setDate(newDate.getDate() + increment);
393
+ if (newDate >= pendingDate?.from) {
394
+ setPendingDate({
395
+ from: new Date(pendingDate?.from),
396
+ to: newDate
397
+ });
398
+ setMonthTo(newDate);
399
+ }
400
+ } else if (highlightedPart === "secondMonth") handleMonthChange((monthTo ? monthTo.getMonth() : 0) + (event.deltaY > 0 ? -1 : 1), "to");
401
+ else if (highlightedPart === "secondYear" && yearTo !== void 0) handleYearChange(yearTo + (event.deltaY > 0 ? -1 : 1), "to");
402
+ };
403
+ React$1.useEffect(() => {
404
+ const elements = [
405
+ document.getElementById(`firstDay-${id}`),
406
+ document.getElementById(`firstMonth-${id}`),
407
+ document.getElementById(`firstYear-${id}`),
408
+ document.getElementById(`secondDay-${id}`),
409
+ document.getElementById(`secondMonth-${id}`),
410
+ document.getElementById(`secondYear-${id}`)
411
+ ];
412
+ const addPassiveEventListener = (element) => {
413
+ if (element) element.addEventListener("wheel", handleWheel, { passive: false });
414
+ };
415
+ elements.forEach(addPassiveEventListener);
416
+ return () => {
417
+ elements.forEach((element) => {
418
+ if (element) element.removeEventListener("wheel", handleWheel);
419
+ });
420
+ };
421
+ }, [highlightedPart, pendingDate]);
422
+ const formatWithTz = (date, fmt) => formatInTimeZone(date, timeZone, fmt);
423
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("style", { children: `
424
+ .date-part {
425
+ touch-action: none;
426
+ }
427
+ ` }), /* @__PURE__ */ jsxs(Popover, {
428
+ open: isPopoverOpen,
429
+ onOpenChange: setIsPopoverOpen,
430
+ children: [/* @__PURE__ */ jsx(PopoverTrigger, {
431
+ asChild: true,
432
+ children: /* @__PURE__ */ jsx(Button$1, {
433
+ id: "date",
434
+ ref,
435
+ ...props,
436
+ className: cn("w-full", triggerClassName, multiSelectVariants({
437
+ variant,
438
+ className
439
+ })),
440
+ onClick: handleTogglePopover,
441
+ suppressHydrationWarning: true,
442
+ children: /* @__PURE__ */ jsxs("div", {
443
+ className: "flex w-full items-center justify-between gap-2",
444
+ children: [/* @__PURE__ */ jsxs("div", {
445
+ className: "flex items-center gap-2",
446
+ children: [/* @__PURE__ */ jsx(CalendarIcon, { className: "text-muted-foreground h-4 w-4" }), /* @__PURE__ */ jsx("span", { children: date?.from ? date.to ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
447
+ /* @__PURE__ */ jsx("span", {
448
+ id: `firstDay-${id}`,
449
+ className: cn("date-part", highlightedPart === "firstDay" && "font-bold underline"),
450
+ onMouseOver: () => handleMouseOver("firstDay"),
451
+ onMouseLeave: handleMouseLeave,
452
+ children: formatWithTz(date.from, "dd")
453
+ }),
454
+ " ",
455
+ /* @__PURE__ */ jsx("span", {
456
+ id: `firstMonth-${id}`,
457
+ className: cn("date-part", highlightedPart === "firstMonth" && "font-bold underline"),
458
+ onMouseOver: () => handleMouseOver("firstMonth"),
459
+ onMouseLeave: handleMouseLeave,
460
+ children: formatWithTz(date.from, "LLL")
461
+ }),
462
+ ",",
463
+ " ",
464
+ /* @__PURE__ */ jsx("span", {
465
+ id: `firstYear-${id}`,
466
+ className: cn("date-part", highlightedPart === "firstYear" && "font-bold underline"),
467
+ onMouseOver: () => handleMouseOver("firstYear"),
468
+ onMouseLeave: handleMouseLeave,
469
+ children: formatWithTz(date.from, "y")
470
+ }),
471
+ numberOfMonths === 2 && /* @__PURE__ */ jsxs(Fragment$1, { children: [
472
+ " - ",
473
+ /* @__PURE__ */ jsx("span", {
474
+ id: `secondDay-${id}`,
475
+ className: cn("date-part", highlightedPart === "secondDay" && "font-bold underline"),
476
+ onMouseOver: () => handleMouseOver("secondDay"),
477
+ onMouseLeave: handleMouseLeave,
478
+ children: formatWithTz(date.to, "dd")
479
+ }),
480
+ " ",
481
+ /* @__PURE__ */ jsx("span", {
482
+ id: `secondMonth-${id}`,
483
+ className: cn("date-part", highlightedPart === "secondMonth" && "font-bold underline"),
484
+ onMouseOver: () => handleMouseOver("secondMonth"),
485
+ onMouseLeave: handleMouseLeave,
486
+ children: formatWithTz(date.to, "LLL")
487
+ }),
488
+ ",",
489
+ " ",
490
+ /* @__PURE__ */ jsx("span", {
491
+ id: `secondYear-${id}`,
492
+ className: cn("date-part", highlightedPart === "secondYear" && "font-bold underline"),
493
+ onMouseOver: () => handleMouseOver("secondYear"),
494
+ onMouseLeave: handleMouseLeave,
495
+ children: formatWithTz(date.to, "y")
496
+ })
497
+ ] })
498
+ ] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
499
+ /* @__PURE__ */ jsx("span", {
500
+ id: "day",
501
+ className: cn("date-part", highlightedPart === "day" && "font-bold underline"),
502
+ onMouseOver: () => handleMouseOver("day"),
503
+ onMouseLeave: handleMouseLeave,
504
+ children: formatWithTz(date.from, "dd")
505
+ }),
506
+ " ",
507
+ /* @__PURE__ */ jsx("span", {
508
+ id: "month",
509
+ className: cn("date-part", highlightedPart === "month" && "font-bold underline"),
510
+ onMouseOver: () => handleMouseOver("month"),
511
+ onMouseLeave: handleMouseLeave,
512
+ children: formatWithTz(date.from, "LLL")
513
+ }),
514
+ ",",
515
+ " ",
516
+ /* @__PURE__ */ jsx("span", {
517
+ id: "year",
518
+ className: cn("date-part", highlightedPart === "year" && "font-bold underline"),
519
+ onMouseOver: () => handleMouseOver("year"),
520
+ onMouseLeave: handleMouseLeave,
521
+ children: formatWithTz(date.from, "y")
522
+ })
523
+ ] }) : /* @__PURE__ */ jsx("span", {
524
+ className: "text-muted-foreground",
525
+ children: placeholder || "Pick a date"
526
+ }) })]
527
+ }), date?.from && /* @__PURE__ */ jsxs("div", {
528
+ onClick: handleClear,
529
+ className: "text-muted-foreground hover:text-primary size-4 p-0 hover:bg-transparent",
530
+ children: [/* @__PURE__ */ jsx(X, { size: 14 }), /* @__PURE__ */ jsx("span", {
531
+ className: "sr-only",
532
+ children: "Clear date"
533
+ })]
534
+ })]
535
+ })
536
+ })
537
+ }), isPopoverOpen && /* @__PURE__ */ jsx(PopoverContent, {
538
+ className: "w-auto",
539
+ align: "center",
540
+ avoidCollisions: false,
541
+ onInteractOutside: handleClose,
542
+ onEscapeKeyDown: handleClose,
543
+ style: {
544
+ maxHeight: "var(--radix-popover-content-available-height)",
545
+ overflowY: "auto"
546
+ },
547
+ children: /* @__PURE__ */ jsxs("div", {
548
+ className: "flex",
549
+ children: [numberOfMonths === 2 && /* @__PURE__ */ jsx("div", {
550
+ className: "border-foreground/10 hidden flex-col gap-1 border-r pr-4 text-left md:flex",
551
+ children: dateRanges.map(({ key, label, start, end }) => /* @__PURE__ */ jsx(Button$1, {
552
+ variant: "ghost",
553
+ size: "sm",
554
+ className: cn("hover:bg-primary/90 hover:text-background justify-start", selectedRange === label && "bg-primary text-background hover:bg-primary/90 hover:text-background"),
555
+ onClick: () => {
556
+ selectDateRange(start, end, label);
557
+ setMonthFrom(start);
558
+ setYearFrom(start.getFullYear());
559
+ setMonthTo(end);
560
+ setYearTo(end.getFullYear());
561
+ },
562
+ children: label
563
+ }, key))
564
+ }), /* @__PURE__ */ jsxs("div", {
565
+ className: "flex flex-col",
566
+ children: [
567
+ /* @__PURE__ */ jsxs("div", {
568
+ className: "flex items-center gap-4",
569
+ children: [/* @__PURE__ */ jsxs("div", {
570
+ className: "ml-3 flex gap-2",
571
+ children: [/* @__PURE__ */ jsxs(Select, {
572
+ onValueChange: (value) => {
573
+ handleMonthChange(months.indexOf(value), "from");
574
+ setSelectedRange(null);
575
+ },
576
+ value: monthFrom ? months[monthFrom.getMonth()] : void 0,
577
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
578
+ className: "hover:bg-accent hover:text-accent-foreground hidden w-[122px] font-medium focus:ring-0 focus:ring-offset-0 sm:flex",
579
+ children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Month" })
580
+ }), /* @__PURE__ */ jsx(SelectContent, { children: months.map((month, idx) => /* @__PURE__ */ jsx(SelectItem, {
581
+ value: month,
582
+ children: month
583
+ }, idx)) })]
584
+ }), /* @__PURE__ */ jsxs(Select, {
585
+ onValueChange: (value) => {
586
+ handleYearChange(Number(value), "from");
587
+ setSelectedRange(null);
588
+ },
589
+ value: yearFrom ? yearFrom.toString() : void 0,
590
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
591
+ className: "hover:bg-accent hover:text-accent-foreground hidden w-[122px] font-medium focus:ring-0 focus:ring-offset-0 sm:flex",
592
+ children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Year" })
593
+ }), /* @__PURE__ */ jsx(SelectContent, { children: years.map((year, idx) => /* @__PURE__ */ jsx(SelectItem, {
594
+ value: year.toString(),
595
+ children: year
596
+ }, idx)) })]
597
+ })]
598
+ }), numberOfMonths === 2 && /* @__PURE__ */ jsxs("div", {
599
+ className: "flex gap-2",
600
+ children: [/* @__PURE__ */ jsxs(Select, {
601
+ onValueChange: (value) => {
602
+ handleMonthChange(months.indexOf(value), "to");
603
+ setSelectedRange(null);
604
+ },
605
+ value: monthTo ? months[monthTo.getMonth()] : void 0,
606
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
607
+ className: "hover:bg-accent hover:text-accent-foreground hidden w-[122px] font-medium focus:ring-0 focus:ring-offset-0 sm:flex",
608
+ children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Month" })
609
+ }), /* @__PURE__ */ jsx(SelectContent, { children: months.map((month, idx) => /* @__PURE__ */ jsx(SelectItem, {
610
+ value: month,
611
+ children: month
612
+ }, idx)) })]
613
+ }), /* @__PURE__ */ jsxs(Select, {
614
+ onValueChange: (value) => {
615
+ handleYearChange(Number(value), "to");
616
+ setSelectedRange(null);
617
+ },
618
+ value: yearTo ? yearTo.toString() : void 0,
619
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
620
+ className: "hover:bg-accent hover:text-accent-foreground hidden w-[122px] font-medium focus:ring-0 focus:ring-offset-0 sm:flex",
621
+ children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Year" })
622
+ }), /* @__PURE__ */ jsx(SelectContent, { children: years.map((year, idx) => /* @__PURE__ */ jsx(SelectItem, {
623
+ value: year.toString(),
624
+ children: year
625
+ }, idx)) })]
626
+ })]
627
+ })]
628
+ }),
629
+ /* @__PURE__ */ jsx("div", {
630
+ className: "flex",
631
+ children: /* @__PURE__ */ jsx(Calendar$1, {
632
+ mode: "range",
633
+ defaultMonth: monthFrom,
634
+ month: monthFrom,
635
+ onMonthChange: setMonthFrom,
636
+ selected: pendingDate,
637
+ onSelect: handleDateSelect,
638
+ numberOfMonths,
639
+ showOutsideDays: false,
640
+ disabled: isDateDisabled,
641
+ fromDate: effectiveMinDate,
642
+ toDate: effectiveMaxDate,
643
+ className
644
+ })
645
+ }),
646
+ !closeOnSelect && /* @__PURE__ */ jsxs("div", {
647
+ className: "flex justify-end gap-2 border-t p-3",
648
+ children: [/* @__PURE__ */ jsx(Button$1, {
649
+ variant: "outline",
650
+ size: "sm",
651
+ onClick: handleReset,
652
+ type: "button",
653
+ children: "Reset"
654
+ }), /* @__PURE__ */ jsx(Button$1, {
655
+ size: "sm",
656
+ onClick: handleApply,
657
+ type: "button",
658
+ children: "Apply"
659
+ })]
660
+ })
661
+ ]
662
+ })]
663
+ })
664
+ })]
665
+ })] });
666
+ }
667
+ CalendarDatePicker.displayName = "CalendarDatePicker";
668
+
669
+ //#endregion
670
+ //#region src/components/features/time-range-picker/utils/timezone.ts
671
+ /**
672
+ * Get the UTC offset string for a timezone
673
+ * @example getTimezoneOffset('Asia/Jakarta') => '+07:00'
674
+ */
675
+ function getTimezoneOffset(timezone) {
676
+ try {
677
+ const now = /* @__PURE__ */ new Date();
678
+ const offsetPart = new Intl.DateTimeFormat("en-US", {
679
+ timeZone: timezone,
680
+ timeZoneName: "shortOffset"
681
+ }).formatToParts(now).find((p) => p.type === "timeZoneName");
682
+ if (offsetPart) {
683
+ const match = offsetPart.value.match(/GMT([+-])(\d+)(?::(\d+))?/);
684
+ if (match) return `${match[1]}${match[2].padStart(2, "0")}:${match[3]?.padStart(2, "0") ?? "00"}`;
685
+ if (offsetPart.value === "GMT") return "+00:00";
686
+ }
687
+ } catch {}
688
+ return "+00:00";
689
+ }
690
+ /**
691
+ * Format a timezone for display
692
+ * @example formatTimezoneLabel('Asia/Jakarta') => 'Asia/Jakarta (UTC+07:00)'
693
+ */
694
+ function formatTimezoneLabel(timezone) {
695
+ const offset = getTimezoneOffset(timezone);
696
+ return `${timezone.replace(/_/g, " ")} (UTC${offset})`;
697
+ }
698
+ /**
699
+ * Create a TimezoneOption from a timezone string
700
+ */
701
+ function createTimezoneOption(timezone) {
702
+ return {
703
+ value: timezone,
704
+ label: formatTimezoneLabel(timezone),
705
+ offset: getTimezoneOffset(timezone)
706
+ };
707
+ }
708
+ /**
709
+ * Get default timezone options (user's timezone + UTC)
710
+ */
711
+ function getDefaultTimezoneOptions(userTimezone) {
712
+ const options = [];
713
+ if (userTimezone && userTimezone !== "UTC") options.push(createTimezoneOption(userTimezone));
714
+ options.push({
715
+ value: "UTC",
716
+ label: "UTC (+00:00)",
717
+ offset: "+00:00"
718
+ });
719
+ return options;
720
+ }
721
+ /**
722
+ * Get short offset display (e.g., "UTC+7")
723
+ */
724
+ function getShortTimezoneDisplay(timezone) {
725
+ const offset = getTimezoneOffset(timezone);
726
+ const match = offset.match(/([+-])(\d+):(\d+)/);
727
+ if (match) {
728
+ const sign = match[1];
729
+ const hours = Number.parseInt(match[2], 10);
730
+ const minutes = match[3];
731
+ if (minutes === "00") return `UTC${sign}${hours}`;
732
+ return `UTC${sign}${hours}:${minutes}`;
733
+ }
734
+ return `UTC${offset}`;
735
+ }
736
+ /**
737
+ * Get the browser's timezone
738
+ */
739
+ function getBrowserTimezone() {
740
+ try {
741
+ return Intl.DateTimeFormat().resolvedOptions().timeZone;
742
+ } catch {
743
+ return "UTC";
744
+ }
745
+ }
746
+ /**
747
+ * Convert a UTC Date to a local datetime-local input string in the given timezone
748
+ * @example utcToLocalInputString(new Date('2026-01-16T04:00:00Z'), 'Asia/Jakarta') => '2026-01-16T11:00'
749
+ */
750
+ function utcToLocalInputString(utcDate, timezone) {
751
+ return format(toZonedTime(utcDate, timezone), "yyyy-MM-dd'T'HH:mm");
752
+ }
753
+ /**
754
+ * Convert a local datetime-local input string to a UTC Date
755
+ * @example localInputStringToUtc('2026-01-16T11:00', 'Asia/Jakarta') => Date('2026-01-16T04:00:00Z')
756
+ */
757
+ function localInputStringToUtc(localString, timezone) {
758
+ return fromZonedTime(parse(localString, "yyyy-MM-dd'T'HH:mm", /* @__PURE__ */ new Date()), timezone);
759
+ }
760
+ /**
761
+ * Convert a UTC ISO string to a Date for display in user's timezone
762
+ */
763
+ function utcStringToZonedDate(utcString, timezone) {
764
+ return toZonedTime(new Date(utcString), timezone);
765
+ }
766
+ /**
767
+ * Convert a zoned Date to UTC ISO string
768
+ */
769
+ function zonedDateToUtcString(zonedDate, timezone) {
770
+ return fromZonedTime(zonedDate, timezone).toISOString();
771
+ }
772
+ /**
773
+ * Format a UTC ISO string for display in user's timezone
774
+ * @example formatUtcForDisplay('2026-01-16T04:00:00Z', 'Asia/Jakarta') => 'Jan 16, 2026 11:00'
775
+ */
776
+ function formatUtcForDisplay(utcString, timezone, formatString = "MMM d, yyyy HH:mm") {
777
+ return format(utcStringToZonedDate(utcString, timezone), formatString);
778
+ }
779
+
780
+ //#endregion
781
+ //#region src/components/features/time-range-picker/components/absolute-range-panel.tsx
782
+ /**
783
+ * Parse a zoned date into separate date and time parts
784
+ */
785
+ function parseDateTimeParts(zonedDate) {
786
+ return {
787
+ date: zonedDate,
788
+ time: `${zonedDate.getHours().toString().padStart(2, "0")}:${zonedDate.getMinutes().toString().padStart(2, "0")}`
789
+ };
790
+ }
791
+ /**
792
+ * Combine a date and time string into a single Date
793
+ */
794
+ function combineDateAndTime(date, time) {
795
+ const [hours, minutes] = time.split(":").map(Number);
796
+ const combined = new Date(date);
797
+ combined.setHours(hours || 0, minutes || 0, 0, 0);
798
+ return combined;
799
+ }
800
+ /**
801
+ * Validate time string format (HH:mm)
802
+ */
803
+ function isValidTime(time) {
804
+ const match = time.match(/^(\d{2}):(\d{2})$/);
805
+ if (!match) return false;
806
+ const hours = Number.parseInt(match[1], 10);
807
+ const minutes = Number.parseInt(match[2], 10);
808
+ return hours >= 0 && hours <= 23 && minutes >= 0 && minutes <= 59;
809
+ }
810
+ function CustomRangePanel({ fromUtc, toUtc, timezone, onRangeChange, disableFuture = false, debounceMs = 600, className }) {
811
+ const startDateId = useId();
812
+ const startTimeId = useId();
813
+ const endDateId = useId();
814
+ const endTimeId = useId();
815
+ const userHasEditedTimeRef = useRef(false);
816
+ const prevFromUtcRef = useRef(fromUtc);
817
+ const prevToUtcRef = useRef(toUtc);
818
+ const debounceTimerRef = useRef(null);
819
+ const [startDateOpen, setStartDateOpen] = useState(false);
820
+ const [endDateOpen, setEndDateOpen] = useState(false);
821
+ const initialFrom = parseDateTimeParts(utcStringToZonedDate(fromUtc, timezone));
822
+ const initialTo = parseDateTimeParts(utcStringToZonedDate(toUtc, timezone));
823
+ const [startDate, setStartDate] = useState(initialFrom.date);
824
+ const [startTime, setStartTime] = useState(initialFrom.time);
825
+ const [endDate, setEndDate] = useState(initialTo.date);
826
+ const [endTime, setEndTime] = useState(initialTo.time);
827
+ useEffect(() => {
828
+ return () => {
829
+ if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
830
+ };
831
+ }, []);
832
+ useEffect(() => {
833
+ const fromChanged = fromUtc !== prevFromUtcRef.current;
834
+ const toChanged = toUtc !== prevToUtcRef.current;
835
+ if (fromChanged) {
836
+ try {
837
+ const parsed = parseDateTimeParts(utcStringToZonedDate(fromUtc, timezone));
838
+ setStartDate(parsed.date);
839
+ setStartTime(parsed.time);
840
+ userHasEditedTimeRef.current = false;
841
+ } catch {}
842
+ prevFromUtcRef.current = fromUtc;
843
+ }
844
+ if (toChanged) {
845
+ try {
846
+ const parsed = parseDateTimeParts(utcStringToZonedDate(toUtc, timezone));
847
+ setEndDate(parsed.date);
848
+ setEndTime(parsed.time);
849
+ userHasEditedTimeRef.current = false;
850
+ } catch {}
851
+ prevToUtcRef.current = toUtc;
852
+ }
853
+ }, [
854
+ fromUtc,
855
+ toUtc,
856
+ timezone
857
+ ]);
858
+ const notifyChangeImmediate = useCallback((newStartDate, newStartTime, newEndDate, newEndTime) => {
859
+ if (!isValidTime(newStartTime) || !isValidTime(newEndTime)) return;
860
+ const startCombined = combineDateAndTime(newStartDate, newStartTime);
861
+ const endCombined = combineDateAndTime(newEndDate, newEndTime);
862
+ if (startCombined >= endCombined) return;
863
+ const newFromUtc = zonedDateToUtcString(startCombined, timezone);
864
+ const newToUtc = zonedDateToUtcString(endCombined, timezone);
865
+ if (newFromUtc !== fromUtc || newToUtc !== toUtc) onRangeChange(newFromUtc, newToUtc);
866
+ }, [
867
+ timezone,
868
+ fromUtc,
869
+ toUtc,
870
+ onRangeChange
871
+ ]);
872
+ const notifyChangeDebounced = useCallback((newStartDate, newStartTime, newEndDate, newEndTime) => {
873
+ if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
874
+ debounceTimerRef.current = setTimeout(() => {
875
+ notifyChangeImmediate(newStartDate, newStartTime, newEndDate, newEndTime);
876
+ }, debounceMs);
877
+ }, [notifyChangeImmediate, debounceMs]);
878
+ const handleStartDateSelect = useCallback((date) => {
879
+ if (!date) return;
880
+ setStartDate(date);
881
+ setStartDateOpen(false);
882
+ notifyChangeImmediate(date, startTime, endDate, endTime);
883
+ }, [
884
+ startTime,
885
+ endDate,
886
+ endTime,
887
+ notifyChangeImmediate
888
+ ]);
889
+ const handleStartTimeChange = useCallback((e) => {
890
+ const newTime = e.target.value;
891
+ userHasEditedTimeRef.current = true;
892
+ setStartTime(newTime);
893
+ if (isValidTime(newTime)) notifyChangeDebounced(startDate, newTime, endDate, endTime);
894
+ }, [
895
+ startDate,
896
+ endDate,
897
+ endTime,
898
+ notifyChangeDebounced
899
+ ]);
900
+ const handleEndDateSelect = useCallback((date) => {
901
+ if (!date) return;
902
+ setEndDate(date);
903
+ setEndDateOpen(false);
904
+ notifyChangeImmediate(startDate, startTime, date, endTime);
905
+ }, [
906
+ startDate,
907
+ startTime,
908
+ endTime,
909
+ notifyChangeImmediate
910
+ ]);
911
+ const handleEndTimeChange = useCallback((e) => {
912
+ const newTime = e.target.value;
913
+ userHasEditedTimeRef.current = true;
914
+ setEndTime(newTime);
915
+ if (isValidTime(newTime)) notifyChangeDebounced(startDate, startTime, endDate, newTime);
916
+ }, [
917
+ startDate,
918
+ startTime,
919
+ endDate,
920
+ notifyChangeDebounced
921
+ ]);
922
+ return /* @__PURE__ */ jsxs("div", {
923
+ className: cn("flex flex-col gap-2", className),
924
+ children: [/* @__PURE__ */ jsx("p", {
925
+ className: "text-muted-foreground text-xs font-medium",
926
+ children: "Custom Range"
927
+ }), /* @__PURE__ */ jsxs("div", {
928
+ className: "flex items-center gap-2",
929
+ children: [
930
+ /* @__PURE__ */ jsxs("div", {
931
+ className: "flex items-center gap-1.5",
932
+ children: [/* @__PURE__ */ jsxs(Popover, {
933
+ open: startDateOpen,
934
+ onOpenChange: setStartDateOpen,
935
+ children: [/* @__PURE__ */ jsx(PopoverTrigger, {
936
+ asChild: true,
937
+ children: /* @__PURE__ */ jsxs(Button, {
938
+ type: "quaternary",
939
+ theme: "outline",
940
+ id: startDateId,
941
+ className: "h-8 w-full justify-start gap-1.5 px-2 text-xs font-normal",
942
+ children: [/* @__PURE__ */ jsx(CalendarIcon, { className: "h-3.5 w-3.5 shrink-0 opacity-50" }), /* @__PURE__ */ jsx("span", {
943
+ className: "truncate",
944
+ children: format(startDate, "MMM d, yyyy")
945
+ })]
946
+ })
947
+ }), /* @__PURE__ */ jsx(PopoverContent, {
948
+ className: "w-auto p-0",
949
+ align: "start",
950
+ children: /* @__PURE__ */ jsx(Calendar$1, {
951
+ mode: "single",
952
+ selected: startDate,
953
+ onSelect: handleStartDateSelect,
954
+ disabled: disableFuture ? (date) => date > /* @__PURE__ */ new Date() : void 0,
955
+ initialFocus: true
956
+ })
957
+ })]
958
+ }), /* @__PURE__ */ jsx(Input, {
959
+ type: "time",
960
+ id: startTimeId,
961
+ value: startTime,
962
+ onChange: handleStartTimeChange,
963
+ className: cn("h-8 w-[80px] px-2 text-xs md:text-xs", "appearance-none bg-transparent", "[&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none")
964
+ })]
965
+ }),
966
+ /* @__PURE__ */ jsx("span", {
967
+ className: "text-muted-foreground text-sm",
968
+ children: "—"
969
+ }),
970
+ /* @__PURE__ */ jsxs("div", {
971
+ className: "flex items-center gap-1.5",
972
+ children: [/* @__PURE__ */ jsxs(Popover, {
973
+ open: endDateOpen,
974
+ onOpenChange: setEndDateOpen,
975
+ children: [/* @__PURE__ */ jsx(PopoverTrigger, {
976
+ asChild: true,
977
+ children: /* @__PURE__ */ jsxs(Button, {
978
+ type: "quaternary",
979
+ theme: "outline",
980
+ id: endDateId,
981
+ className: "h-8 w-full justify-start gap-1.5 px-2 text-xs font-normal",
982
+ children: [/* @__PURE__ */ jsx(CalendarIcon, { className: "h-3.5 w-3.5 shrink-0 opacity-50" }), /* @__PURE__ */ jsx("span", {
983
+ className: "truncate",
984
+ children: format(endDate, "MMM d, yyyy")
985
+ })]
986
+ })
987
+ }), /* @__PURE__ */ jsx(PopoverContent, {
988
+ className: "w-auto p-0",
989
+ align: "start",
990
+ children: /* @__PURE__ */ jsx(Calendar$1, {
991
+ mode: "single",
992
+ selected: endDate,
993
+ onSelect: handleEndDateSelect,
994
+ disabled: disableFuture ? (date) => date > /* @__PURE__ */ new Date() || date < startDate : (date) => date < startDate,
995
+ initialFocus: true
996
+ })
997
+ })]
998
+ }), /* @__PURE__ */ jsx(Input, {
999
+ type: "time",
1000
+ id: endTimeId,
1001
+ value: endTime,
1002
+ onChange: handleEndTimeChange,
1003
+ className: cn("h-8 w-[80px] px-2 text-xs md:text-xs", "appearance-none bg-transparent", "[&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none")
1004
+ })]
1005
+ })
1006
+ ]
1007
+ })]
1008
+ });
1009
+ }
1010
+
1011
+ //#endregion
1012
+ //#region src/components/features/time-range-picker/components/quick-ranges-panel.tsx
1013
+ function QuickRangesPanel({ presets, value, onPresetSelect, className }) {
1014
+ const selectedPreset = value?.type === "preset" ? value.preset : void 0;
1015
+ return /* @__PURE__ */ jsxs("div", {
1016
+ className: cn("flex flex-col gap-2", className),
1017
+ children: [/* @__PURE__ */ jsx("p", {
1018
+ className: "text-muted-foreground px-3 text-xs font-medium",
1019
+ children: "Presets"
1020
+ }), /* @__PURE__ */ jsx("div", {
1021
+ className: "grid gap-1",
1022
+ children: presets.map((preset) => {
1023
+ const isSelected = selectedPreset === preset.key;
1024
+ return /* @__PURE__ */ jsxs("button", {
1025
+ type: "button",
1026
+ onClick: () => onPresetSelect(preset),
1027
+ className: cn("flex items-center justify-between gap-2 rounded-lg px-3 py-1.5 text-xs transition-colors", "hover:bg-accent hover:text-accent-foreground", isSelected ? "bg-accent text-primary border-border border font-medium" : "border border-transparent"),
1028
+ children: [/* @__PURE__ */ jsx("span", { children: preset.label }), /* @__PURE__ */ jsx("kbd", {
1029
+ className: cn("bg-muted pointer-events-none hidden h-5 items-center gap-1 rounded border px-1.5 font-mono text-[10px] font-medium select-none sm:flex", isSelected ? "border-primary" : "bg-muted/50 border-transparent"),
1030
+ children: preset.shortcut
1031
+ })]
1032
+ }, preset.key);
1033
+ })
1034
+ })]
1035
+ });
1036
+ }
1037
+
1038
+ //#endregion
1039
+ //#region src/components/features/time-range-picker/components/timezone-selector.tsx
1040
+ function TimezoneSelector({ value, onChange, options, className }) {
1041
+ const selectedOption = options.find((opt) => opt.value === value);
1042
+ return /* @__PURE__ */ jsxs("div", {
1043
+ className: cn("flex items-center gap-2", className),
1044
+ children: [/* @__PURE__ */ jsx(Globe, { className: "text-muted-foreground h-4 w-4 shrink-0" }), /* @__PURE__ */ jsxs(Select, {
1045
+ value,
1046
+ onValueChange: onChange,
1047
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
1048
+ className: "hover:bg-accent h-8 min-w-[180px] border-0 bg-transparent px-2 text-xs shadow-none",
1049
+ children: /* @__PURE__ */ jsx(SelectValue, {
1050
+ placeholder: "Select timezone",
1051
+ children: selectedOption?.label ?? value
1052
+ })
1053
+ }), /* @__PURE__ */ jsx(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsx(SelectItem, {
1054
+ value: option.value,
1055
+ className: "text-xs",
1056
+ children: option.label
1057
+ }, option.value)) })]
1058
+ })]
1059
+ });
1060
+ }
1061
+
1062
+ //#endregion
1063
+ //#region src/components/features/time-range-picker/presets.ts
1064
+ /**
1065
+ * Get start of day in a specific timezone
1066
+ */
1067
+ function startOfDayInTimezone(date, timezone) {
1068
+ const zonedDate = toZonedTime(date, timezone);
1069
+ zonedDate.setHours(0, 0, 0, 0);
1070
+ return fromZonedTime(zonedDate, timezone);
1071
+ }
1072
+ /**
1073
+ * Get end of day in a specific timezone
1074
+ */
1075
+ function endOfDayInTimezone(date, timezone) {
1076
+ const zonedDate = toZonedTime(date, timezone);
1077
+ zonedDate.setHours(23, 59, 59, 999);
1078
+ return fromZonedTime(zonedDate, timezone);
1079
+ }
1080
+ /**
1081
+ * Default time range presets with timezone-aware range calculation
1082
+ * Note: All presets use "now" as end time to avoid future timestamps
1083
+ * (API rejects future times for historical audit logs)
1084
+ *
1085
+ * API constraint: Maximum time range is 720 hours (30 days)
1086
+ */
1087
+ const DEFAULT_PRESETS = [
1088
+ {
1089
+ key: "15m",
1090
+ label: "Last 15 minutes",
1091
+ shortcut: "1",
1092
+ getRange: (_timezone) => {
1093
+ const now = /* @__PURE__ */ new Date();
1094
+ return {
1095
+ from: subMinutes(now, 15),
1096
+ to: now
1097
+ };
1098
+ }
1099
+ },
1100
+ {
1101
+ key: "30m",
1102
+ label: "Last 30 minutes",
1103
+ shortcut: "3",
1104
+ getRange: (_timezone) => {
1105
+ const now = /* @__PURE__ */ new Date();
1106
+ return {
1107
+ from: subMinutes(now, 30),
1108
+ to: now
1109
+ };
1110
+ }
1111
+ },
1112
+ {
1113
+ key: "1h",
1114
+ label: "Last hour",
1115
+ shortcut: "H",
1116
+ getRange: (_timezone) => {
1117
+ const now = /* @__PURE__ */ new Date();
1118
+ return {
1119
+ from: subHours(now, 1),
1120
+ to: now
1121
+ };
1122
+ }
1123
+ },
1124
+ {
1125
+ key: "today",
1126
+ label: "Today",
1127
+ shortcut: "D",
1128
+ getRange: (timezone) => {
1129
+ const now = /* @__PURE__ */ new Date();
1130
+ return {
1131
+ from: startOfDayInTimezone(now, timezone),
1132
+ to: now
1133
+ };
1134
+ }
1135
+ },
1136
+ {
1137
+ key: "yesterday",
1138
+ label: "Yesterday",
1139
+ shortcut: "Y",
1140
+ getRange: (timezone) => {
1141
+ const yesterday = subDays(/* @__PURE__ */ new Date(), 1);
1142
+ return {
1143
+ from: startOfDayInTimezone(yesterday, timezone),
1144
+ to: endOfDayInTimezone(yesterday, timezone)
1145
+ };
1146
+ }
1147
+ },
1148
+ {
1149
+ key: "7d",
1150
+ label: "Last 7 days",
1151
+ shortcut: "W",
1152
+ getRange: (_timezone) => {
1153
+ const now = /* @__PURE__ */ new Date();
1154
+ return {
1155
+ from: subDays(now, 7),
1156
+ to: now
1157
+ };
1158
+ }
1159
+ },
1160
+ {
1161
+ key: "30d",
1162
+ label: "Last 30 days",
1163
+ shortcut: "M",
1164
+ getRange: (_timezone) => {
1165
+ const now = /* @__PURE__ */ new Date();
1166
+ return {
1167
+ from: subDays(now, 30),
1168
+ to: now
1169
+ };
1170
+ }
1171
+ }
1172
+ ];
1173
+ /**
1174
+ * Get a preset by key
1175
+ */
1176
+ function getPresetByKey(key, presets = DEFAULT_PRESETS) {
1177
+ return presets.find((p) => p.key === key);
1178
+ }
1179
+ /**
1180
+ * Get a preset by keyboard shortcut
1181
+ */
1182
+ function getPresetByShortcut(shortcut, presets = DEFAULT_PRESETS) {
1183
+ return presets.find((p) => p.shortcut.toLowerCase() === shortcut.toLowerCase());
1184
+ }
1185
+ /**
1186
+ * Get the default preset (last 7 days)
1187
+ */
1188
+ function getDefaultPreset(presets = DEFAULT_PRESETS) {
1189
+ return getPresetByKey("today", presets) ?? presets[0];
1190
+ }
1191
+ /**
1192
+ * Calculate preset range and return UTC ISO strings
1193
+ */
1194
+ function getPresetRange(preset, timezone) {
1195
+ const range = preset.getRange(timezone);
1196
+ return {
1197
+ from: range.from.toISOString(),
1198
+ to: range.to.toISOString()
1199
+ };
1200
+ }
1201
+
1202
+ //#endregion
1203
+ //#region src/components/features/time-range-picker/utils/format-display.ts
1204
+ /**
1205
+ * Format a TimeRangeValue for display in the trigger button
1206
+ * Always shows the actual date/time range, not preset labels
1207
+ * Converts UTC timestamps to user's timezone for display
1208
+ */
1209
+ function formatTimeRangeDisplay(value, timezone) {
1210
+ if (!value || !value.from || !value.to) return "Select time range";
1211
+ return formatDateRangeDisplay(value.from, value.to, timezone);
1212
+ }
1213
+ /**
1214
+ * Format a date range for display
1215
+ * Smart formatting based on whether dates are same day/year
1216
+ */
1217
+ function formatDateRangeDisplay(fromUtc, toUtc, timezone) {
1218
+ try {
1219
+ const fromDate = utcStringToZonedDate(fromUtc, timezone);
1220
+ const toDate = utcStringToZonedDate(toUtc, timezone);
1221
+ const now = /* @__PURE__ */ new Date();
1222
+ if (isSameDay(fromDate, toDate)) return `${isSameYear(fromDate, now) ? format(fromDate, "MMM d") : format(fromDate, "MMM d, yyyy")}, ${format(fromDate, "HH:mm")} - ${format(toDate, "HH:mm")}`;
1223
+ if (isSameYear(fromDate, now) && isSameYear(toDate, now)) return `${format(fromDate, "MMM d, HH:mm")} - ${format(toDate, "MMM d, HH:mm")}`;
1224
+ return `${format(fromDate, "MMM d, yyyy")} - ${format(toDate, "MMM d, yyyy")}`;
1225
+ } catch {
1226
+ return `${formatUtcForDisplay(fromUtc, timezone, "MMM d, HH:mm")} - ${formatUtcForDisplay(toUtc, timezone, "MMM d, HH:mm")}`;
1227
+ }
1228
+ }
1229
+ /**
1230
+ * Format a UTC ISO string for display in user's timezone
1231
+ */
1232
+ function formatSingleTimeDisplay(utcString, timezone) {
1233
+ try {
1234
+ return formatUtcForDisplay(utcString, timezone, "MMM d, yyyy HH:mm");
1235
+ } catch {
1236
+ return utcString;
1237
+ }
1238
+ }
1239
+ /**
1240
+ * Format a Date object for the datetime-local input field
1241
+ */
1242
+ function formatDateForInput(date) {
1243
+ return format(date, "yyyy-MM-dd'T'HH:mm");
1244
+ }
1245
+
1246
+ //#endregion
1247
+ //#region src/components/features/time-range-picker/time-range-picker.tsx
1248
+ function TimeRangePicker({ value, onChange, onClear, timezone: timezoneProp, presets = DEFAULT_PRESETS, disableFuture = false, maxDate, minDate, className, disabled = false, placeholder = "Select time range", align = "start", side = "bottom" }) {
1249
+ const [open, setOpen] = useState(false);
1250
+ const timezone = timezoneProp ?? getBrowserTimezone();
1251
+ const defaultPreset = getDefaultPreset(presets);
1252
+ const defaultRange = useMemo(() => getPresetRange(defaultPreset, timezone), [defaultPreset, timezone]);
1253
+ const currentFromUtc = value?.from ?? defaultRange.from;
1254
+ const currentToUtc = value?.to ?? defaultRange.to;
1255
+ const calendarRange = useMemo(() => {
1256
+ try {
1257
+ return {
1258
+ from: utcStringToZonedDate(currentFromUtc, timezone),
1259
+ to: utcStringToZonedDate(currentToUtc, timezone)
1260
+ };
1261
+ } catch {
1262
+ return;
1263
+ }
1264
+ }, [
1265
+ currentFromUtc,
1266
+ currentToUtc,
1267
+ timezone
1268
+ ]);
1269
+ const effectiveValue = useMemo(() => {
1270
+ if (value?.type === "preset" && value?.preset && (!value?.from || !value?.to)) {
1271
+ const preset = presets.find((p) => p.key === value.preset) ?? defaultPreset;
1272
+ const range = getPresetRange(preset, timezone);
1273
+ return {
1274
+ type: "preset",
1275
+ preset: preset.key,
1276
+ from: range.from,
1277
+ to: range.to
1278
+ };
1279
+ }
1280
+ if (value?.from && value?.to) return value;
1281
+ return {
1282
+ type: "preset",
1283
+ preset: defaultPreset.key,
1284
+ from: defaultRange.from,
1285
+ to: defaultRange.to
1286
+ };
1287
+ }, [
1288
+ value,
1289
+ defaultPreset,
1290
+ defaultRange.from,
1291
+ defaultRange.to,
1292
+ presets,
1293
+ timezone
1294
+ ]);
1295
+ const displayText = useMemo(() => formatTimeRangeDisplay(effectiveValue, timezone) || placeholder, [
1296
+ effectiveValue,
1297
+ timezone,
1298
+ placeholder
1299
+ ]);
1300
+ const handlePresetSelect = useCallback((preset) => {
1301
+ const range = getPresetRange(preset, timezone);
1302
+ onChange({
1303
+ type: "preset",
1304
+ preset: preset.key,
1305
+ from: range.from,
1306
+ to: range.to
1307
+ });
1308
+ setOpen(false);
1309
+ }, [onChange, timezone]);
1310
+ const userClickedCalendarRef = useRef(false);
1311
+ const handleDayClick = useCallback(() => {
1312
+ userClickedCalendarRef.current = true;
1313
+ }, []);
1314
+ const handleCalendarSelect = useCallback((range) => {
1315
+ if (!userClickedCalendarRef.current) return;
1316
+ userClickedCalendarRef.current = false;
1317
+ if (range?.from && range?.to) {
1318
+ const now = /* @__PURE__ */ new Date();
1319
+ const fromStart = new Date(range.from);
1320
+ fromStart.setHours(0, 0, 0, 0);
1321
+ const toEnd = new Date(range.to);
1322
+ toEnd.setHours(23, 59, 59, 999);
1323
+ const effectiveToEnd = toEnd > now ? now : toEnd;
1324
+ onChange({
1325
+ type: "custom",
1326
+ from: zonedDateToUtcString(fromStart, timezone),
1327
+ to: zonedDateToUtcString(effectiveToEnd, timezone)
1328
+ });
1329
+ } else if (range?.from) {
1330
+ const now = /* @__PURE__ */ new Date();
1331
+ const fromStart = new Date(range.from);
1332
+ fromStart.setHours(0, 0, 0, 0);
1333
+ const toEnd = new Date(range.from);
1334
+ toEnd.setHours(23, 59, 59, 999);
1335
+ const effectiveToEnd = toEnd > now ? now : toEnd;
1336
+ onChange({
1337
+ type: "custom",
1338
+ from: zonedDateToUtcString(fromStart, timezone),
1339
+ to: zonedDateToUtcString(effectiveToEnd, timezone)
1340
+ });
1341
+ }
1342
+ }, [onChange, timezone]);
1343
+ const handleCustomRangeChange = useCallback((fromUtc, toUtc) => {
1344
+ onChange({
1345
+ type: "custom",
1346
+ from: fromUtc,
1347
+ to: toUtc
1348
+ });
1349
+ }, [onChange]);
1350
+ useEffect(() => {
1351
+ if (!open) return;
1352
+ const handleKeyDown = (e) => {
1353
+ const preset = getPresetByShortcut(e.key, presets);
1354
+ if (preset) {
1355
+ e.preventDefault();
1356
+ handlePresetSelect(preset);
1357
+ }
1358
+ };
1359
+ document.addEventListener("keydown", handleKeyDown);
1360
+ return () => document.removeEventListener("keydown", handleKeyDown);
1361
+ }, [
1362
+ open,
1363
+ presets,
1364
+ handlePresetSelect
1365
+ ]);
1366
+ const effectiveMaxDate = disableFuture ? /* @__PURE__ */ new Date() : maxDate;
1367
+ const handleClear = useCallback((e) => {
1368
+ e.stopPropagation();
1369
+ onClear?.();
1370
+ }, [onClear]);
1371
+ const showClearButton = value && onClear;
1372
+ return /* @__PURE__ */ jsxs(Popover, {
1373
+ open,
1374
+ onOpenChange: setOpen,
1375
+ children: [/* @__PURE__ */ jsx("div", {
1376
+ className: "relative inline-flex",
1377
+ children: /* @__PURE__ */ jsx(PopoverTrigger, {
1378
+ asChild: true,
1379
+ children: /* @__PURE__ */ jsxs(Button, {
1380
+ type: "quaternary",
1381
+ theme: "outline",
1382
+ disabled,
1383
+ className: cn("text-foreground min-w-[200px] items-center justify-between gap-2 px-3 font-normal", className),
1384
+ children: [/* @__PURE__ */ jsxs("div", {
1385
+ className: "flex flex-1 items-center gap-2",
1386
+ children: [/* @__PURE__ */ jsx(Icon, {
1387
+ icon: Calendar,
1388
+ size: 16
1389
+ }), /* @__PURE__ */ jsx("span", {
1390
+ className: "truncate text-xs",
1391
+ children: displayText
1392
+ })]
1393
+ }), showClearButton && /* @__PURE__ */ jsx("div", {
1394
+ onClick: (e) => {
1395
+ e.stopPropagation();
1396
+ e.preventDefault();
1397
+ handleClear(e);
1398
+ },
1399
+ className: cn("size-[14px] shrink-0 p-0 hover:bg-transparent", "hover:text-destructive text-icon-quaternary hover:bg-transparent dark:text-white", "focus:ring-ring focus:ring-2 focus:ring-offset-1 focus:outline-none", "disabled:pointer-events-none disabled:opacity-50", "transition-colors"),
1400
+ "aria-label": "Clear time range",
1401
+ children: /* @__PURE__ */ jsx(Icon, {
1402
+ icon: X,
1403
+ size: 14
1404
+ })
1405
+ })]
1406
+ })
1407
+ })
1408
+ }), /* @__PURE__ */ jsxs(PopoverContent, {
1409
+ className: "w-auto rounded-xl p-0",
1410
+ align,
1411
+ side,
1412
+ sideOffset: 4,
1413
+ children: [
1414
+ /* @__PURE__ */ jsxs("div", {
1415
+ className: "divide-border flex flex-col divide-x sm:flex-row",
1416
+ children: [/* @__PURE__ */ jsx("div", {
1417
+ className: "flex-1 px-0",
1418
+ children: /* @__PURE__ */ jsx(Calendar$1, {
1419
+ className: "w-full",
1420
+ mode: "range",
1421
+ defaultMonth: calendarRange?.from,
1422
+ selected: calendarRange,
1423
+ onSelect: handleCalendarSelect,
1424
+ onDayClick: handleDayClick,
1425
+ numberOfMonths: 1,
1426
+ disabled: (date) => {
1427
+ if (effectiveMaxDate && date > effectiveMaxDate) return true;
1428
+ if (minDate && date < minDate) return true;
1429
+ return false;
1430
+ },
1431
+ initialFocus: true
1432
+ })
1433
+ }), /* @__PURE__ */ jsx("div", {
1434
+ className: "p-3",
1435
+ children: /* @__PURE__ */ jsx(QuickRangesPanel, {
1436
+ presets,
1437
+ value: effectiveValue,
1438
+ onPresetSelect: handlePresetSelect
1439
+ })
1440
+ })]
1441
+ }),
1442
+ /* @__PURE__ */ jsx(Separator, {}),
1443
+ /* @__PURE__ */ jsx("div", {
1444
+ className: "p-3",
1445
+ children: /* @__PURE__ */ jsx(CustomRangePanel, {
1446
+ fromUtc: currentFromUtc,
1447
+ toUtc: currentToUtc,
1448
+ timezone,
1449
+ onRangeChange: handleCustomRangeChange,
1450
+ disableFuture
1451
+ })
1452
+ }),
1453
+ /* @__PURE__ */ jsx(Separator, {}),
1454
+ /* @__PURE__ */ jsxs("div", {
1455
+ className: "text-muted-foreground bg-muted/30 flex items-center gap-2 px-3 py-2 text-xs",
1456
+ children: [/* @__PURE__ */ jsx(Globe, { className: "h-3.5 w-3.5" }), /* @__PURE__ */ jsxs("span", { children: ["Your timezone:", formatTimezoneLabel(timezone)] })]
1457
+ })
1458
+ ]
1459
+ })]
1460
+ });
1461
+ }
1462
+
1463
+ //#endregion
1464
+ //#region src/components/features/time-range-picker/utils/to-api-format.ts
1465
+ /**
1466
+ * Convert a TimeRangeValue to API format (startTime/endTime)
1467
+ *
1468
+ * Since TimeRangeValue now always stores UTC timestamps,
1469
+ * this is a simple passthrough.
1470
+ *
1471
+ * @param value - The time range value (stores UTC timestamps)
1472
+ * @param timezone - User's timezone (used only if value needs recalculation)
1473
+ * @param presets - Preset configurations
1474
+ */
1475
+ function toApiTimeRange(value, timezone, presets = DEFAULT_PRESETS) {
1476
+ const tz = timezone ?? getBrowserTimezone();
1477
+ if (!value) {
1478
+ const range = getPresetRange(getDefaultPreset(), tz);
1479
+ return {
1480
+ startTime: range.from,
1481
+ endTime: range.to
1482
+ };
1483
+ }
1484
+ if (value.from && value.to) return {
1485
+ startTime: value.from,
1486
+ endTime: value.to
1487
+ };
1488
+ if (value.type === "preset" && value.preset) {
1489
+ const preset = presets.find((p) => p.key === value.preset);
1490
+ if (preset) {
1491
+ const range = getPresetRange(preset, tz);
1492
+ return {
1493
+ startTime: range.from,
1494
+ endTime: range.to
1495
+ };
1496
+ }
1497
+ }
1498
+ const range = getPresetRange(getDefaultPreset(presets), tz);
1499
+ return {
1500
+ startTime: range.from,
1501
+ endTime: range.to
1502
+ };
1503
+ }
1504
+
1505
+ //#endregion
1506
+ export { utcToLocalInputString as C, utcStringToZonedDate as S, CalendarDatePicker as T, getBrowserTimezone as _, formatTimeRangeDisplay as a, getTimezoneOffset as b, getPresetByKey as c, TimezoneSelector as d, QuickRangesPanel as f, formatUtcForDisplay as g, formatTimezoneLabel as h, formatSingleTimeDisplay as i, getPresetByShortcut as l, createTimezoneOption as m, TimeRangePicker as n, DEFAULT_PRESETS as o, CustomRangePanel as p, formatDateForInput as r, getDefaultPreset as s, toApiTimeRange as t, getPresetRange as u, getDefaultTimezoneOptions as v, zonedDateToUtcString as w, localInputStringToUtc as x, getShortTimezoneDisplay as y };