@windrun-huaiin/third-ui 29.0.4 → 29.2.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 (64) hide show
  1. package/dist/fuma/base/custom-header.js +6 -3
  2. package/dist/fuma/base/custom-header.mjs +6 -3
  3. package/dist/main/alert-dialog/confirm-dialog.d.ts +7 -3
  4. package/dist/main/alert-dialog/confirm-dialog.js +11 -6
  5. package/dist/main/alert-dialog/confirm-dialog.mjs +13 -8
  6. package/dist/main/alert-dialog/dialog-loading-action.d.ts +12 -0
  7. package/dist/main/alert-dialog/dialog-loading-action.js +42 -0
  8. package/dist/main/alert-dialog/dialog-loading-action.mjs +40 -0
  9. package/dist/main/alert-dialog/high-priority-confirm-dialog.d.ts +6 -3
  10. package/dist/main/alert-dialog/high-priority-confirm-dialog.js +13 -4
  11. package/dist/main/alert-dialog/high-priority-confirm-dialog.mjs +14 -5
  12. package/dist/main/alert-dialog/index.d.ts +1 -0
  13. package/dist/main/alert-dialog/info-dialog.d.ts +4 -2
  14. package/dist/main/alert-dialog/info-dialog.js +6 -5
  15. package/dist/main/alert-dialog/info-dialog.mjs +7 -6
  16. package/dist/main/alert-dialog/undoable-confirm-dialog.d.ts +8 -4
  17. package/dist/main/alert-dialog/undoable-confirm-dialog.js +23 -16
  18. package/dist/main/alert-dialog/undoable-confirm-dialog.mjs +24 -17
  19. package/dist/main/buttons/gradient-button.d.ts +3 -1
  20. package/dist/main/buttons/gradient-button.js +29 -3
  21. package/dist/main/buttons/gradient-button.mjs +29 -3
  22. package/dist/main/buttons/index.d.ts +1 -0
  23. package/dist/main/buttons/index.js +3 -0
  24. package/dist/main/buttons/index.mjs +1 -0
  25. package/dist/main/buttons/use-press-feedback.d.ts +18 -0
  26. package/dist/main/buttons/use-press-feedback.js +42 -0
  27. package/dist/main/buttons/use-press-feedback.mjs +39 -0
  28. package/dist/main/buttons/x-button.d.ts +3 -0
  29. package/dist/main/buttons/x-button.js +36 -6
  30. package/dist/main/buttons/x-button.mjs +36 -6
  31. package/dist/main/calendar/calendar-date-range-input.d.ts +17 -0
  32. package/dist/main/calendar/calendar-date-range-input.js +81 -0
  33. package/dist/main/calendar/calendar-date-range-input.mjs +79 -0
  34. package/dist/main/calendar/calendar-status-view.d.ts +23 -0
  35. package/dist/main/calendar/calendar-status-view.js +155 -0
  36. package/dist/main/calendar/calendar-status-view.mjs +153 -0
  37. package/dist/main/calendar/index.d.ts +3 -0
  38. package/dist/main/calendar/index.js +12 -0
  39. package/dist/main/calendar/index.mjs +4 -0
  40. package/dist/main/calendar/random-date-range-dialog.d.ts +15 -0
  41. package/dist/main/calendar/random-date-range-dialog.js +447 -0
  42. package/dist/main/calendar/random-date-range-dialog.mjs +445 -0
  43. package/dist/main/features.js +2 -2
  44. package/dist/main/features.mjs +1 -1
  45. package/dist/main/usage.js +2 -2
  46. package/dist/main/usage.mjs +1 -1
  47. package/package.json +9 -4
  48. package/src/fuma/base/custom-header.tsx +6 -3
  49. package/src/main/alert-dialog/confirm-dialog.tsx +59 -46
  50. package/src/main/alert-dialog/dialog-loading-action.tsx +63 -0
  51. package/src/main/alert-dialog/high-priority-confirm-dialog.tsx +67 -48
  52. package/src/main/alert-dialog/index.ts +1 -0
  53. package/src/main/alert-dialog/info-dialog.tsx +50 -44
  54. package/src/main/alert-dialog/undoable-confirm-dialog.tsx +96 -81
  55. package/src/main/buttons/gradient-button.tsx +36 -3
  56. package/src/main/buttons/index.ts +1 -0
  57. package/src/main/buttons/use-press-feedback.ts +58 -0
  58. package/src/main/buttons/x-button.tsx +53 -11
  59. package/src/main/calendar/calendar-date-range-input.tsx +173 -0
  60. package/src/main/calendar/calendar-status-view.tsx +365 -0
  61. package/src/main/calendar/index.ts +5 -0
  62. package/src/main/calendar/random-date-range-dialog.tsx +741 -0
  63. package/src/main/features.tsx +1 -1
  64. package/src/main/usage.tsx +1 -1
@@ -0,0 +1,447 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var React = require('react');
6
+ var reactDom = require('react-dom');
7
+ var icons = require('@windrun-huaiin/base-ui/icons');
8
+ var utils = require('@windrun-huaiin/lib/utils');
9
+ var usePressFeedback = require('../buttons/use-press-feedback.js');
10
+
11
+ const DEFAULT_RANGE_DAYS = 7;
12
+ const MAX_RANGE_DAYS = 30;
13
+ const TRACK_MIN_DAYS = 45;
14
+ const TRACK_PADDING_DAYS = 20;
15
+ const DIALOG_ICON_BUTTON_CLASS_NAME = 'inline-flex h-8 w-8 items-center justify-center rounded-full border border-black/10 bg-white text-slate-500 transition duration-150 hover:border-black/20 hover:bg-black/5 hover:text-slate-900 dark:border-white/10 dark:bg-slate-950 dark:text-slate-300 dark:hover:bg-white/5 dark:hover:text-white';
16
+ const DIALOG_NAV_BUTTON_CLASS_NAME = 'inline-flex h-8 w-8 items-center justify-center rounded-full transition-[transform,background-color,color,box-shadow,border-color] duration-150 ease-out';
17
+ const DIALOG_NAV_BUTTON_REST_CLASS_NAME = 'border border-black/10 bg-white text-slate-500 shadow-[0_1px_2px_rgba(15,23,42,0.08)] hover:border-black/15 dark:border-white/10 dark:bg-slate-950 dark:text-slate-400 dark:hover:border-white/15';
18
+ const DIALOG_NAV_BUTTON_PRESSED_CLASS_NAME = 'translate-y-[2px] scale-[0.9] border border-black/30 bg-slate-300 text-slate-950 shadow-[inset_0_2px_4px_rgba(15,23,42,0.22)] dark:border-white/25 dark:bg-white/20 dark:text-white dark:shadow-[inset_0_2px_4px_rgba(255,255,255,0.16)]';
19
+ const DIALOG_PILL_BUTTON_CLASS_NAME = 'rounded-full bg-slate-100 px-3 py-1.5 text-xs font-semibold text-slate-700 shadow-sm transition-[transform,background-color,color,box-shadow] duration-100 ease-out active:scale-[0.94] active:bg-slate-300 active:text-slate-950 active:shadow-inner dark:bg-white/10 dark:text-slate-200 dark:active:scale-[0.94] dark:active:bg-white/22 dark:active:text-white sm:text-sm';
20
+ const DIALOG_PILL_BUTTON_COMPACT_CLASS_NAME = 'rounded-full bg-slate-100 px-2.5 py-1 text-xs font-semibold text-slate-700 shadow-sm transition-[transform,background-color,color,box-shadow] duration-100 ease-out active:scale-[0.94] active:bg-slate-300 active:text-slate-950 active:shadow-inner dark:bg-white/10 dark:text-slate-200 dark:active:scale-[0.94] dark:active:bg-white/22 dark:active:text-white';
21
+ function parseDateString(value) {
22
+ return new Date(`${value}T00:00:00.000Z`);
23
+ }
24
+ function getTodayString() {
25
+ return new Date().toISOString().slice(0, 10);
26
+ }
27
+ function formatDateString(date) {
28
+ return date.toISOString().slice(0, 10);
29
+ }
30
+ function addDays(value, days) {
31
+ const date = parseDateString(value);
32
+ date.setUTCDate(date.getUTCDate() + days);
33
+ return formatDateString(date);
34
+ }
35
+ function compareDateStrings(left, right) {
36
+ return left.localeCompare(right);
37
+ }
38
+ function getInclusiveDayCount(range) {
39
+ if (!range.startDate || !range.endDate) {
40
+ return 0;
41
+ }
42
+ const startTime = parseDateString(range.startDate).getTime();
43
+ const endTime = parseDateString(range.endDate).getTime();
44
+ return Math.max(0, Math.floor((endTime - startTime) / 86400000) + 1);
45
+ }
46
+ function getRangeLabel(range) {
47
+ if (!range.startDate || !range.endDate) {
48
+ return 'No range selected';
49
+ }
50
+ return `${range.startDate} ~ ${range.endDate}`;
51
+ }
52
+ function clampWindowDays(days) {
53
+ return Math.max(1, Math.min(MAX_RANGE_DAYS, Math.floor(days)));
54
+ }
55
+ function buildTrackRange(referenceDate, windowDays = DEFAULT_RANGE_DAYS) {
56
+ const resolvedWindowDays = clampWindowDays(windowDays);
57
+ const resolvedTotalDays = Math.max(TRACK_MIN_DAYS, resolvedWindowDays + TRACK_PADDING_DAYS);
58
+ const daysBefore = Math.floor((resolvedTotalDays - resolvedWindowDays) / 3);
59
+ const startDate = addDays(referenceDate, -daysBefore);
60
+ const endDate = addDays(startDate, resolvedTotalDays - 1);
61
+ return { startDate, endDate };
62
+ }
63
+ function clampDateToRange(date, bounds) {
64
+ if (!bounds.startDate || !bounds.endDate) {
65
+ return date;
66
+ }
67
+ if (compareDateStrings(date, bounds.startDate) < 0) {
68
+ return bounds.startDate;
69
+ }
70
+ if (compareDateStrings(date, bounds.endDate) > 0) {
71
+ return bounds.endDate;
72
+ }
73
+ return date;
74
+ }
75
+ function getDaysBetween(startDate, endDate) {
76
+ const start = parseDateString(startDate).getTime();
77
+ const end = parseDateString(endDate).getTime();
78
+ return Math.max(0, Math.floor((end - start) / 86400000));
79
+ }
80
+ function getDateByRatio(bounds, ratio) {
81
+ if (!bounds.startDate || !bounds.endDate) {
82
+ return getTodayString();
83
+ }
84
+ const totalDays = Math.max(1, getDaysBetween(bounds.startDate, bounds.endDate));
85
+ return addDays(bounds.startDate, Math.round(totalDays * ratio));
86
+ }
87
+ function getRatioByDate(date, bounds) {
88
+ if (!bounds.startDate || !bounds.endDate) {
89
+ return 0;
90
+ }
91
+ const totalDays = Math.max(1, getDaysBetween(bounds.startDate, bounds.endDate));
92
+ const distance = getDaysBetween(bounds.startDate, clampDateToRange(date, bounds));
93
+ return distance / totalDays;
94
+ }
95
+ function formatMonthShort(value) {
96
+ return parseDateString(value).toLocaleDateString('en-US', {
97
+ month: 'short',
98
+ timeZone: 'UTC',
99
+ });
100
+ }
101
+ function addMonthsClamped(value, months) {
102
+ const source = parseDateString(value);
103
+ const sourceYear = source.getUTCFullYear();
104
+ const sourceMonth = source.getUTCMonth();
105
+ const sourceDay = source.getUTCDate();
106
+ const targetMonthIndex = sourceMonth + months;
107
+ const targetYear = sourceYear + Math.floor(targetMonthIndex / 12);
108
+ const normalizedMonth = ((targetMonthIndex % 12) + 12) % 12;
109
+ const targetMonthLastDay = new Date(Date.UTC(targetYear, normalizedMonth + 1, 0)).getUTCDate();
110
+ const targetDay = Math.min(sourceDay, targetMonthLastDay);
111
+ return formatDateString(new Date(Date.UTC(targetYear, normalizedMonth, targetDay)));
112
+ }
113
+ function getMonthStart(value) {
114
+ const date = parseDateString(value);
115
+ return formatDateString(new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1)));
116
+ }
117
+ function getMonthEnd(value) {
118
+ const date = parseDateString(value);
119
+ return formatDateString(new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 0)));
120
+ }
121
+ function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEFAULT_RANGE_DAYS, onOpenChange, onApply, onClear, }) {
122
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
123
+ const resolvedDefaultRangeDays = clampWindowDays(defaultRangeDays);
124
+ const [draftRange, setDraftRange] = React.useState(value);
125
+ const [referenceDate, setReferenceDate] = React.useState(anchorDate);
126
+ const [trackBounds, setTrackBounds] = React.useState(() => buildTrackRange(anchorDate || getTodayString(), resolvedDefaultRangeDays));
127
+ const [windowDays, setWindowDays] = React.useState(resolvedDefaultRangeDays);
128
+ const { pressedKey: pressedNavButton, flash: flashNavButtonPress, getPressProps: getNavButtonPressProps, } = usePressFeedback.usePressFeedback();
129
+ const dragStartRangeRef = React.useRef(null);
130
+ const dragModeRef = React.useRef(null);
131
+ const pointerIdRef = React.useRef(null);
132
+ const windowDragOffsetDaysRef = React.useRef(0);
133
+ const trackRef = React.useRef(null);
134
+ const selectionRef = React.useRef(null);
135
+ const startHandleRef = React.useRef(null);
136
+ const endHandleRef = React.useRef(null);
137
+ const resultLabelRef = React.useRef(null);
138
+ const selectionDaysRef = React.useRef(null);
139
+ const dragPreviewRef = React.useRef(null);
140
+ const frameRef = React.useRef(null);
141
+ const pendingClientXRef = React.useRef(null);
142
+ const syncPreviewDomRef = React.useRef(() => { });
143
+ const buildDraggedRangeRef = React.useRef(() => null);
144
+ const previousBodyOverflowRef = React.useRef(null);
145
+ const today = React.useMemo(() => getTodayString(), []);
146
+ const baseReferenceDate = anchorDate || today;
147
+ const previousOpenRef = React.useRef(false);
148
+ const startRatio = getRatioByDate((_a = draftRange.startDate) !== null && _a !== void 0 ? _a : baseReferenceDate, trackBounds);
149
+ const endRatio = getRatioByDate((_b = draftRange.endDate) !== null && _b !== void 0 ? _b : baseReferenceDate, trackBounds);
150
+ const leftPercent = Math.min(startRatio, endRatio) * 100;
151
+ const rightPercent = Math.max(startRatio, endRatio) * 100;
152
+ const widthPercent = Math.max(rightPercent - leftPercent, 0.5);
153
+ const isSingleDay = ((_c = draftRange.startDate) !== null && _c !== void 0 ? _c : null) === ((_d = draftRange.endDate) !== null && _d !== void 0 ? _d : null);
154
+ const startHandlePercent = isSingleDay ? Math.max(leftPercent - 0.8, 0) : leftPercent;
155
+ const endHandlePercent = isSingleDay ? Math.min(rightPercent + 0.8, 100) : rightPercent;
156
+ const trackTickCount = Math.max(getDaysBetween((_e = trackBounds.startDate) !== null && _e !== void 0 ? _e : baseReferenceDate, (_f = trackBounds.endDate) !== null && _f !== void 0 ? _f : baseReferenceDate) + 1, 2);
157
+ const monthLabels = React.useMemo(() => {
158
+ const values = [trackBounds.startDate, trackBounds.endDate]
159
+ .filter((item) => Boolean(item))
160
+ .map((item) => formatMonthShort(item));
161
+ return [...new Set(values)];
162
+ }, [trackBounds.endDate, trackBounds.startDate]);
163
+ React.useEffect(() => {
164
+ if (open && !previousOpenRef.current) {
165
+ const nextRange = {
166
+ startDate: baseReferenceDate,
167
+ endDate: addDays(baseReferenceDate, resolvedDefaultRangeDays - 1),
168
+ };
169
+ setDraftRange(nextRange);
170
+ setReferenceDate(baseReferenceDate);
171
+ setTrackBounds(buildTrackRange(baseReferenceDate, resolvedDefaultRangeDays));
172
+ setWindowDays(resolvedDefaultRangeDays);
173
+ dragStartRangeRef.current = null;
174
+ dragModeRef.current = null;
175
+ pointerIdRef.current = null;
176
+ dragPreviewRef.current = nextRange;
177
+ }
178
+ previousOpenRef.current = open;
179
+ }, [baseReferenceDate, open, resolvedDefaultRangeDays]);
180
+ function updateRangeByReference(nextReferenceDate, nextWindowDays, options) {
181
+ const clampedWindowDays = clampWindowDays(nextWindowDays);
182
+ const nextRange = {
183
+ startDate: nextReferenceDate,
184
+ endDate: addDays(nextReferenceDate, Math.max(clampedWindowDays - 1, 0)),
185
+ };
186
+ setReferenceDate(nextReferenceDate);
187
+ setWindowDays(clampedWindowDays);
188
+ setDraftRange(nextRange);
189
+ if (!(options === null || options === void 0 ? void 0 : options.preserveTrack)) {
190
+ setTrackBounds(buildTrackRange(nextReferenceDate, clampedWindowDays));
191
+ }
192
+ }
193
+ const getPreviewPercents = React.useCallback((range) => {
194
+ var _a, _b;
195
+ const start = (_a = range.startDate) !== null && _a !== void 0 ? _a : baseReferenceDate;
196
+ const end = (_b = range.endDate) !== null && _b !== void 0 ? _b : start;
197
+ const startR = getRatioByDate(start, trackBounds);
198
+ const endR = getRatioByDate(end, trackBounds);
199
+ const left = Math.min(startR, endR) * 100;
200
+ const right = Math.max(startR, endR) * 100;
201
+ const width = Math.max(right - left, 0.5);
202
+ const single = start === end;
203
+ return {
204
+ left,
205
+ right,
206
+ width,
207
+ startHandle: single ? Math.max(left - 0.8, 0) : left,
208
+ endHandle: single ? Math.min(right + 0.8, 100) : right,
209
+ };
210
+ }, [baseReferenceDate, trackBounds]);
211
+ const syncPreviewDom = React.useCallback((range) => {
212
+ const percents = getPreviewPercents(range);
213
+ if (selectionRef.current) {
214
+ selectionRef.current.style.left = `${percents.left}%`;
215
+ selectionRef.current.style.width = `${percents.width}%`;
216
+ }
217
+ if (startHandleRef.current) {
218
+ startHandleRef.current.style.left = `${percents.startHandle}%`;
219
+ }
220
+ if (endHandleRef.current) {
221
+ endHandleRef.current.style.left = `${percents.endHandle}%`;
222
+ }
223
+ if (resultLabelRef.current) {
224
+ resultLabelRef.current.textContent = getRangeLabel(range);
225
+ }
226
+ if (selectionDaysRef.current) {
227
+ selectionDaysRef.current.textContent = `${getInclusiveDayCount(range)}D`;
228
+ }
229
+ }, [getPreviewPercents]);
230
+ React.useEffect(() => {
231
+ dragPreviewRef.current = draftRange;
232
+ syncPreviewDom(draftRange);
233
+ }, [draftRange, syncPreviewDom]);
234
+ function resetReferenceFromClientX(clientX) {
235
+ if (!trackRef.current) {
236
+ return;
237
+ }
238
+ const rect = trackRef.current.getBoundingClientRect();
239
+ const ratio = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
240
+ const nextReferenceDate = getDateByRatio(trackBounds, ratio);
241
+ updateRangeByReference(nextReferenceDate, resolvedDefaultRangeDays, { preserveTrack: true });
242
+ }
243
+ function applyQuickRange(dayCount) {
244
+ updateRangeByReference(referenceDate, dayCount);
245
+ }
246
+ function shiftReferenceDateByMonths(monthOffset) {
247
+ updateRangeByReference(addMonthsClamped(referenceDate, monthOffset), windowDays);
248
+ }
249
+ function shiftReferenceDateByYears(yearOffset) {
250
+ updateRangeByReference(addMonthsClamped(referenceDate, yearOffset * 12), windowDays);
251
+ }
252
+ function beginDrag(mode, pointerId, clientX) {
253
+ document.body.style.userSelect = 'none';
254
+ dragModeRef.current = mode;
255
+ pointerIdRef.current = pointerId;
256
+ dragStartRangeRef.current = Object.assign({}, draftRange);
257
+ dragPreviewRef.current = Object.assign({}, draftRange);
258
+ if (mode === 'window' &&
259
+ clientX !== undefined &&
260
+ trackRef.current &&
261
+ draftRange.startDate &&
262
+ draftRange.endDate &&
263
+ trackBounds.startDate &&
264
+ trackBounds.endDate) {
265
+ const rect = trackRef.current.getBoundingClientRect();
266
+ const ratio = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
267
+ const pointerDate = getDateByRatio(trackBounds, ratio);
268
+ windowDragOffsetDaysRef.current = getDaysBetween(draftRange.startDate, pointerDate);
269
+ }
270
+ else {
271
+ windowDragOffsetDaysRef.current = 0;
272
+ }
273
+ }
274
+ const buildDraggedRange = React.useCallback((clientX) => {
275
+ if (!dragModeRef.current || !dragStartRangeRef.current || !trackBounds.startDate || !trackBounds.endDate || !trackRef.current) {
276
+ return null;
277
+ }
278
+ const rect = trackRef.current.getBoundingClientRect();
279
+ const ratio = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
280
+ const pointerDate = getDateByRatio(trackBounds, ratio);
281
+ const currentRange = dragStartRangeRef.current;
282
+ if (!currentRange.startDate || !currentRange.endDate) {
283
+ return null;
284
+ }
285
+ if (dragModeRef.current === 'start') {
286
+ const earliestStart = addDays(currentRange.endDate, -29);
287
+ const boundedPointerDate = compareDateStrings(pointerDate, earliestStart) < 0 ? earliestStart : pointerDate;
288
+ const nextStart = compareDateStrings(boundedPointerDate, currentRange.endDate) > 0 ? currentRange.endDate : boundedPointerDate;
289
+ return { startDate: nextStart, endDate: currentRange.endDate };
290
+ }
291
+ if (dragModeRef.current === 'end') {
292
+ const latestEnd = addDays(currentRange.startDate, MAX_RANGE_DAYS - 1);
293
+ const boundedPointerDate = compareDateStrings(pointerDate, latestEnd) > 0 ? latestEnd : pointerDate;
294
+ const nextEnd = compareDateStrings(boundedPointerDate, currentRange.startDate) < 0 ? currentRange.startDate : boundedPointerDate;
295
+ return { startDate: currentRange.startDate, endDate: nextEnd };
296
+ }
297
+ const spanDays = getDaysBetween(currentRange.startDate, currentRange.endDate);
298
+ const nextStart = clampDateToRange(addDays(pointerDate, -windowDragOffsetDaysRef.current), {
299
+ startDate: trackBounds.startDate,
300
+ endDate: addDays(trackBounds.endDate, -spanDays),
301
+ });
302
+ const nextEnd = addDays(nextStart, spanDays);
303
+ return { startDate: nextStart, endDate: nextEnd };
304
+ }, [trackBounds]);
305
+ React.useEffect(() => {
306
+ syncPreviewDomRef.current = syncPreviewDom;
307
+ buildDraggedRangeRef.current = buildDraggedRange;
308
+ }, [syncPreviewDom, buildDraggedRange]);
309
+ function endDrag() {
310
+ if (frameRef.current !== null) {
311
+ window.cancelAnimationFrame(frameRef.current);
312
+ frameRef.current = null;
313
+ }
314
+ pendingClientXRef.current = null;
315
+ document.body.style.userSelect = '';
316
+ const nextRange = dragPreviewRef.current;
317
+ dragStartRangeRef.current = null;
318
+ dragModeRef.current = null;
319
+ pointerIdRef.current = null;
320
+ windowDragOffsetDaysRef.current = 0;
321
+ if ((nextRange === null || nextRange === void 0 ? void 0 : nextRange.startDate) && nextRange.endDate) {
322
+ setDraftRange(nextRange);
323
+ setReferenceDate(nextRange.startDate);
324
+ setWindowDays(getInclusiveDayCount(nextRange));
325
+ }
326
+ }
327
+ React.useEffect(() => {
328
+ if (!open) {
329
+ return undefined;
330
+ }
331
+ previousBodyOverflowRef.current = document.body.style.overflow;
332
+ document.body.style.overflow = 'hidden';
333
+ function handleWindowPointerMove(event) {
334
+ if (dragModeRef.current === null) {
335
+ return;
336
+ }
337
+ pendingClientXRef.current = event.clientX;
338
+ if (frameRef.current !== null) {
339
+ return;
340
+ }
341
+ frameRef.current = window.requestAnimationFrame(() => {
342
+ frameRef.current = null;
343
+ if (pendingClientXRef.current === null) {
344
+ return;
345
+ }
346
+ const nextRange = buildDraggedRangeRef.current(pendingClientXRef.current);
347
+ if (nextRange) {
348
+ dragPreviewRef.current = nextRange;
349
+ syncPreviewDomRef.current(nextRange);
350
+ }
351
+ });
352
+ }
353
+ function handleWindowPointerUp(event) {
354
+ if (pointerIdRef.current !== null && event.pointerId !== pointerIdRef.current) {
355
+ return;
356
+ }
357
+ if (dragModeRef.current !== null) {
358
+ endDrag();
359
+ }
360
+ }
361
+ window.addEventListener('pointermove', handleWindowPointerMove, { passive: true });
362
+ window.addEventListener('pointerup', handleWindowPointerUp);
363
+ window.addEventListener('pointercancel', handleWindowPointerUp);
364
+ return () => {
365
+ var _a;
366
+ document.body.style.overflow = (_a = previousBodyOverflowRef.current) !== null && _a !== void 0 ? _a : '';
367
+ previousBodyOverflowRef.current = null;
368
+ document.body.style.userSelect = '';
369
+ window.removeEventListener('pointermove', handleWindowPointerMove);
370
+ window.removeEventListener('pointerup', handleWindowPointerUp);
371
+ window.removeEventListener('pointercancel', handleWindowPointerUp);
372
+ };
373
+ }, [open]);
374
+ if (!open) {
375
+ return null;
376
+ }
377
+ return reactDom.createPortal(jsxRuntime.jsx("div", { className: "fixed inset-0 z-120 flex select-none items-center justify-center bg-slate-950/60 px-3 py-6 backdrop-blur-sm", children: jsxRuntime.jsx("div", { className: "w-full max-w-2xl overflow-hidden rounded-3xl border border-black/10 bg-white shadow-2xl dark:border-white/10 dark:bg-slate-950", children: jsxRuntime.jsxs("div", { className: "space-y-5 p-4", children: [jsxRuntime.jsxs("div", { className: "relative flex items-center justify-center px-16 text-center", children: [jsxRuntime.jsx("div", { ref: resultLabelRef, className: "select-none text-base font-semibold text-slate-900 dark:text-white", children: getRangeLabel(draftRange) }), jsxRuntime.jsxs("div", { className: "absolute right-0 top-1/2 flex -translate-y-1/2 items-center gap-2", children: [jsxRuntime.jsx("button", { type: "button", onClick: () => onOpenChange(false), className: DIALOG_ICON_BUTTON_CLASS_NAME, "aria-label": "Cancel", children: jsxRuntime.jsx(icons.XIcon, { className: "h-4 w-4" }) }), jsxRuntime.jsx("button", { type: "button", onClick: () => {
378
+ onApply(draftRange);
379
+ onOpenChange(false);
380
+ }, disabled: !draftRange.startDate || !draftRange.endDate, className: utils.cn(DIALOG_ICON_BUTTON_CLASS_NAME, 'text-slate-700 dark:text-slate-100', 'disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:border-black/10 disabled:hover:bg-white disabled:hover:text-slate-700 dark:disabled:hover:border-white/10 dark:disabled:hover:bg-slate-950 dark:disabled:hover:text-slate-100'), "aria-label": "Apply", children: jsxRuntime.jsx(icons.CheckCheckIcon, { className: "h-4 w-4" }) })] })] }), jsxRuntime.jsxs("div", { className: "space-y-4", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [jsxRuntime.jsx("button", Object.assign({ type: "button", onClick: () => {
381
+ flashNavButtonPress('prevYear');
382
+ shiftReferenceDateByYears(-1);
383
+ }, className: utils.cn(DIALOG_NAV_BUTTON_CLASS_NAME, pressedNavButton === 'prevYear'
384
+ ? DIALOG_NAV_BUTTON_PRESSED_CLASS_NAME
385
+ : DIALOG_NAV_BUTTON_REST_CLASS_NAME) }, getNavButtonPressProps('prevYear'), { "aria-label": "Previous year", title: "Previous year", children: jsxRuntime.jsx(icons.ChevronsLeftIcon, { className: "h-4 w-4" }) })), jsxRuntime.jsx("button", Object.assign({ type: "button", onClick: () => {
386
+ flashNavButtonPress('prevMonth');
387
+ shiftReferenceDateByMonths(-1);
388
+ }, className: utils.cn(DIALOG_NAV_BUTTON_CLASS_NAME, pressedNavButton === 'prevMonth'
389
+ ? DIALOG_NAV_BUTTON_PRESSED_CLASS_NAME
390
+ : DIALOG_NAV_BUTTON_REST_CLASS_NAME) }, getNavButtonPressProps('prevMonth'), { "aria-label": "Previous month", title: "Previous month", children: jsxRuntime.jsx(icons.ChevronLeftIcon, { className: "h-4 w-4" }) }))] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx("button", { type: "button", onClick: () => {
391
+ const nextRange = {
392
+ startDate: baseReferenceDate,
393
+ endDate: addDays(baseReferenceDate, resolvedDefaultRangeDays - 1),
394
+ };
395
+ setReferenceDate(baseReferenceDate);
396
+ setTrackBounds(buildTrackRange(baseReferenceDate, resolvedDefaultRangeDays));
397
+ setWindowDays(resolvedDefaultRangeDays);
398
+ setDraftRange(nextRange);
399
+ onClear === null || onClear === void 0 ? void 0 : onClear(nextRange);
400
+ }, className: DIALOG_PILL_BUTTON_CLASS_NAME, children: "Current Day" }), jsxRuntime.jsx("button", { type: "button", onClick: () => {
401
+ const nextRange = {
402
+ startDate: getMonthStart(referenceDate),
403
+ endDate: addDays(getMonthStart(referenceDate), MAX_RANGE_DAYS - 1),
404
+ };
405
+ const clampedEndDate = compareDateStrings(nextRange.endDate, getMonthEnd(referenceDate)) > 0
406
+ ? getMonthEnd(referenceDate)
407
+ : nextRange.endDate;
408
+ const normalizedRange = {
409
+ startDate: nextRange.startDate,
410
+ endDate: clampedEndDate,
411
+ };
412
+ setDraftRange(normalizedRange);
413
+ setWindowDays(getInclusiveDayCount(normalizedRange));
414
+ setTrackBounds(buildTrackRange(normalizedRange.startDate, getInclusiveDayCount(normalizedRange)));
415
+ }, className: DIALOG_PILL_BUTTON_CLASS_NAME, children: "This Month" })] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [jsxRuntime.jsx("button", Object.assign({ type: "button", onClick: () => {
416
+ flashNavButtonPress('nextMonth');
417
+ shiftReferenceDateByMonths(1);
418
+ }, className: utils.cn(DIALOG_NAV_BUTTON_CLASS_NAME, pressedNavButton === 'nextMonth'
419
+ ? DIALOG_NAV_BUTTON_PRESSED_CLASS_NAME
420
+ : DIALOG_NAV_BUTTON_REST_CLASS_NAME) }, getNavButtonPressProps('nextMonth'), { "aria-label": "Next month", title: "Next month", children: jsxRuntime.jsx(icons.ChevronRightIcon, { className: "h-4 w-4" }) })), jsxRuntime.jsx("button", Object.assign({ type: "button", onClick: () => {
421
+ flashNavButtonPress('nextYear');
422
+ shiftReferenceDateByYears(1);
423
+ }, className: utils.cn(DIALOG_NAV_BUTTON_CLASS_NAME, pressedNavButton === 'nextYear'
424
+ ? DIALOG_NAV_BUTTON_PRESSED_CLASS_NAME
425
+ : DIALOG_NAV_BUTTON_REST_CLASS_NAME) }, getNavButtonPressProps('nextYear'), { "aria-label": "Next year", title: "Next year", children: jsxRuntime.jsx(icons.ChevronsRightIcon, { className: "h-4 w-4" }) }))] })] }), jsxRuntime.jsxs("div", { className: "relative h-24", children: [jsxRuntime.jsxs("div", { className: "absolute inset-x-0 top-0 grid grid-cols-[3.5rem_minmax(0,1fr)_3.5rem] items-center gap-2 text-sm font-semibold text-slate-500 dark:text-slate-400", children: [jsxRuntime.jsxs("span", { className: "relative block select-none text-center", children: [(_g = monthLabels[0]) !== null && _g !== void 0 ? _g : formatMonthShort((_h = trackBounds.startDate) !== null && _h !== void 0 ? _h : baseReferenceDate), jsxRuntime.jsx("span", { className: "pointer-events-none absolute left-1/2 top-7 h-2.5 w-2.5 -translate-x-1/2 rounded-full bg-slate-400 dark:bg-slate-500" }), jsxRuntime.jsx("span", { className: "pointer-events-none absolute left-1/2 top-[1.95rem] h-9 w-0.5 -translate-x-1/2 bg-slate-400 dark:bg-slate-500" })] }), jsxRuntime.jsx("div", { className: "flex min-w-0 items-center justify-center gap-1", children: [
426
+ { label: '+7', days: 7 },
427
+ { label: '+10', days: 10 },
428
+ { label: '+15', days: 15 },
429
+ { label: '+30', days: 30 },
430
+ ].map((item) => (jsxRuntime.jsx("button", { type: "button", onClick: () => applyQuickRange(item.days), className: DIALOG_PILL_BUTTON_COMPACT_CLASS_NAME, children: item.label }, item.label))) }), jsxRuntime.jsxs("span", { className: "relative block select-none text-center", children: [(_j = monthLabels[1]) !== null && _j !== void 0 ? _j : formatMonthShort((_k = trackBounds.endDate) !== null && _k !== void 0 ? _k : baseReferenceDate), jsxRuntime.jsx("span", { className: "pointer-events-none absolute right-1/2 top-7 h-2.5 w-2.5 translate-x-1/2 rounded-full bg-slate-400 dark:bg-slate-500" }), jsxRuntime.jsx("span", { className: "pointer-events-none absolute right-1/2 top-[1.95rem] h-9 w-0.5 translate-x-1/2 bg-slate-400 dark:bg-slate-500" })] })] }), jsxRuntime.jsx("div", { className: "absolute inset-x-0 top-[3.35rem] h-10 touch-none", onDoubleClick: (event) => {
431
+ event.stopPropagation();
432
+ resetReferenceFromClientX(event.clientX);
433
+ }, children: jsxRuntime.jsxs("div", { ref: trackRef, className: "absolute inset-x-0 top-1/2 h-3 -translate-y-1/2 rounded-full bg-slate-400/30 dark:bg-slate-500/25", children: [jsxRuntime.jsx("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-x-0 top-1/2 grid h-8 -translate-y-1/2 items-center", style: { gridTemplateColumns: `repeat(${trackTickCount}, minmax(0, 1fr))` }, children: Array.from({ length: trackTickCount }, (_, index) => {
434
+ return (jsxRuntime.jsx("span", { className: "flex justify-center", children: jsxRuntime.jsx("span", { className: utils.cn('rounded-full bg-slate-400/55 dark:bg-slate-500/55', 'h-3 w-px') }) }, index));
435
+ }) }), jsxRuntime.jsx("div", { ref: selectionRef, className: "absolute top-1/2 z-10 h-4 touch-none -translate-y-1/2 overflow-visible rounded-md border border-sky-500 bg-white dark:border-sky-300 dark:bg-slate-950", style: { left: `${leftPercent}%`, width: `${widthPercent}%` }, onPointerDown: (event) => {
436
+ event.stopPropagation();
437
+ beginDrag('window', event.pointerId, event.clientX);
438
+ }, children: jsxRuntime.jsx("div", { ref: selectionDaysRef, className: "pointer-events-none absolute inset-0 z-30 flex select-none items-center justify-center text-xs font-semibold text-sky-700 dark:text-sky-100", children: `${getInclusiveDayCount(draftRange)}D` }) }), jsxRuntime.jsx("button", { ref: startHandleRef, type: "button", className: "absolute top-1/2 z-20 h-6 w-6 touch-none -translate-x-1/2 -translate-y-1/2 rounded-full border border-sky-500 bg-white shadow-sm dark:border-sky-300 dark:bg-slate-950", style: { left: `${startHandlePercent}%` }, onPointerDown: (event) => {
439
+ event.stopPropagation();
440
+ beginDrag('start', event.pointerId);
441
+ }, "aria-label": "Adjust start date" }), jsxRuntime.jsx("button", { ref: endHandleRef, type: "button", className: "absolute top-1/2 z-20 h-6 w-6 touch-none -translate-x-1/2 -translate-y-1/2 rounded-full border border-sky-500 bg-white shadow-sm dark:border-sky-300 dark:bg-slate-950", style: { left: `${endHandlePercent}%` }, onPointerDown: (event) => {
442
+ event.stopPropagation();
443
+ beginDrag('end', event.pointerId);
444
+ }, "aria-label": "Adjust end date" })] }) })] })] })] }) }) }), document.body);
445
+ }
446
+
447
+ exports.RandomDateRangeDialog = RandomDateRangeDialog;