@windrun-huaiin/third-ui 29.2.1 → 30.0.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 (96) hide show
  1. package/dist/fuma/mdx/cheet-table.d.ts +13 -0
  2. package/dist/fuma/mdx/cheet-table.js +295 -0
  3. package/dist/fuma/mdx/cheet-table.mjs +293 -0
  4. package/dist/fuma/mdx/index.d.ts +1 -0
  5. package/dist/fuma/mdx/index.js +2 -0
  6. package/dist/fuma/mdx/index.mjs +1 -0
  7. package/dist/fuma/server/features/widgets.js +2 -0
  8. package/dist/fuma/server/features/widgets.mjs +2 -0
  9. package/dist/lib/fuma-schema-check-util.d.ts +1 -1
  10. package/dist/main/alert-dialog/confirm-dialog.js +1 -1
  11. package/dist/main/alert-dialog/confirm-dialog.mjs +2 -2
  12. package/dist/main/alert-dialog/dialog-loading-action.js +5 -2
  13. package/dist/main/alert-dialog/dialog-loading-action.mjs +5 -2
  14. package/dist/main/alert-dialog/dialog-styles.d.ts +4 -2
  15. package/dist/main/alert-dialog/dialog-styles.js +8 -4
  16. package/dist/main/alert-dialog/dialog-styles.mjs +7 -5
  17. package/dist/main/alert-dialog/high-priority-confirm-dialog.js +5 -5
  18. package/dist/main/alert-dialog/high-priority-confirm-dialog.mjs +6 -6
  19. package/dist/main/alert-dialog/info-dialog.js +1 -1
  20. package/dist/main/alert-dialog/info-dialog.mjs +2 -2
  21. package/dist/main/alert-dialog/undoable-confirm-dialog.js +2 -2
  22. package/dist/main/alert-dialog/undoable-confirm-dialog.mjs +3 -3
  23. package/dist/main/anime/anime-beam-frame.d.ts +3 -0
  24. package/dist/main/anime/anime-beam-frame.js +63 -0
  25. package/dist/main/anime/anime-beam-frame.mjs +61 -0
  26. package/dist/main/anime/anime-spiral-loading.d.ts +10 -0
  27. package/dist/main/anime/anime-spiral-loading.js +77 -0
  28. package/dist/main/anime/anime-spiral-loading.mjs +75 -0
  29. package/dist/main/anime/index.d.ts +2 -0
  30. package/dist/main/anime/index.js +10 -0
  31. package/dist/main/anime/index.mjs +3 -0
  32. package/dist/main/beam-frame/animate.d.ts +3 -0
  33. package/dist/main/beam-frame/animate.js +63 -0
  34. package/dist/main/beam-frame/animate.mjs +61 -0
  35. package/dist/main/beam-frame/beam-frame.d.ts +4 -0
  36. package/dist/main/beam-frame/beam-frame.js +262 -0
  37. package/dist/main/beam-frame/beam-frame.mjs +258 -0
  38. package/dist/main/beam-frame/index.d.ts +4 -0
  39. package/dist/main/beam-frame/index.js +11 -0
  40. package/dist/main/beam-frame/index.mjs +3 -0
  41. package/dist/main/beam-frame/motion.d.ts +3 -0
  42. package/dist/main/beam-frame/motion.js +61 -0
  43. package/dist/main/beam-frame/motion.mjs +59 -0
  44. package/dist/main/beam-frame/share-config.d.ts +54 -0
  45. package/dist/main/beam-frame/share-config.js +161 -0
  46. package/dist/main/beam-frame/share-config.mjs +152 -0
  47. package/dist/main/beam-frame-config.d.ts +54 -0
  48. package/dist/main/beam-frame-config.js +161 -0
  49. package/dist/main/beam-frame-config.mjs +152 -0
  50. package/dist/main/calendar/random-date-range-dialog.js +177 -51
  51. package/dist/main/calendar/random-date-range-dialog.mjs +178 -52
  52. package/dist/main/cta.js +17 -1
  53. package/dist/main/cta.mjs +18 -2
  54. package/dist/main/delayed-img.d.ts +1 -1
  55. package/dist/main/delayed-img.js +8 -5
  56. package/dist/main/delayed-img.mjs +8 -5
  57. package/dist/main/info-tooltip.js +70 -9
  58. package/dist/main/info-tooltip.mjs +70 -9
  59. package/dist/main/loading-frame/index.d.ts +1 -0
  60. package/dist/main/loading.d.ts +2 -1
  61. package/dist/main/loading.js +64 -26
  62. package/dist/main/loading.mjs +64 -26
  63. package/dist/main/motion/index.d.ts +1 -0
  64. package/dist/main/motion/index.js +9 -0
  65. package/dist/main/motion/index.mjs +2 -0
  66. package/dist/main/motion/motion-beam-frame.d.ts +3 -0
  67. package/dist/main/motion/motion-beam-frame.js +61 -0
  68. package/dist/main/motion/motion-beam-frame.mjs +59 -0
  69. package/dist/main/snake-loading-frame.d.ts +7 -3
  70. package/dist/main/snake-loading-frame.js +44 -252
  71. package/dist/main/snake-loading-frame.mjs +46 -254
  72. package/package.json +16 -5
  73. package/src/fuma/mdx/cheet-table.tsx +650 -0
  74. package/src/fuma/mdx/index.ts +1 -0
  75. package/src/fuma/server/features/widgets.tsx +2 -0
  76. package/src/main/alert-dialog/confirm-dialog.tsx +2 -1
  77. package/src/main/alert-dialog/dialog-loading-action.tsx +7 -5
  78. package/src/main/alert-dialog/dialog-styles.ts +13 -3
  79. package/src/main/alert-dialog/high-priority-confirm-dialog.tsx +26 -23
  80. package/src/main/alert-dialog/info-dialog.tsx +2 -1
  81. package/src/main/alert-dialog/undoable-confirm-dialog.tsx +18 -17
  82. package/src/main/anime/anime-beam-frame.tsx +128 -0
  83. package/src/main/anime/anime-spiral-loading.tsx +123 -0
  84. package/src/main/anime/index.ts +9 -0
  85. package/src/main/beam-frame-config.tsx +341 -0
  86. package/src/main/calendar/random-date-range-dialog.tsx +225 -69
  87. package/src/main/cta.tsx +50 -21
  88. package/src/main/delayed-img.tsx +9 -4
  89. package/src/main/info-tooltip.tsx +116 -20
  90. package/src/main/loading-frame/index.ts +4 -0
  91. package/src/main/loading.tsx +75 -24
  92. package/src/main/motion/index.ts +8 -0
  93. package/src/main/motion/motion-beam-frame.tsx +137 -0
  94. package/src/main/snake-loading-frame.tsx +95 -496
  95. package/src/styles/cta.css +21 -4
  96. package/src/styles/third-ui.css +0 -20
@@ -2,16 +2,18 @@
2
2
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
3
3
  import { useState, useRef, useMemo, useCallback, useEffect } from 'react';
4
4
  import { createPortal } from 'react-dom';
5
- import { XIcon, CheckCheckIcon, ChevronsLeftIcon, ChevronLeftIcon, ChevronRightIcon, ChevronsRightIcon } from '@windrun-huaiin/base-ui/icons';
5
+ import { XIcon, ChevronsLeftIcon, ChevronLeftIcon, ChevronRightIcon, ChevronsRightIcon, CheckCheckIcon } from '@windrun-huaiin/base-ui/icons';
6
+ import { themeSvgIconColor } from '@windrun-huaiin/base-ui/lib';
6
7
  import { cn } from '@windrun-huaiin/lib/utils';
7
8
  import { useDialogLoadingAction } from '../alert-dialog/dialog-loading-action.mjs';
9
+ import { XButton } from '../buttons/x-button.mjs';
8
10
  import { usePressFeedback } from '../buttons/use-press-feedback.mjs';
9
11
 
10
12
  const DEFAULT_RANGE_DAYS = 7;
11
- const MAX_RANGE_DAYS = 30;
12
- const TRACK_MIN_DAYS = 45;
13
- const TRACK_PADDING_DAYS = 20;
14
- 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';
13
+ const MAX_RANGE_DAYS = 31;
14
+ const VISIBLE_TRACK_DAYS = 36;
15
+ const EDGE_OVERFLOW_PIXELS_PER_DAY = 24;
16
+ const DIALOG_ICON_BUTTON_CLASS_NAME = 'inline-flex h-8 w-8 items-center justify-center rounded-full bg-white text-slate-500 transition duration-150 hover:bg-black/5 hover:text-slate-900 dark:bg-slate-950 dark:text-slate-300 dark:hover:bg-white/5 dark:hover:text-white';
15
17
  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';
16
18
  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';
17
19
  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)]';
@@ -53,12 +55,31 @@ function clampWindowDays(days) {
53
55
  }
54
56
  function buildTrackRange(referenceDate, windowDays = DEFAULT_RANGE_DAYS) {
55
57
  const resolvedWindowDays = clampWindowDays(windowDays);
56
- const resolvedTotalDays = Math.max(TRACK_MIN_DAYS, resolvedWindowDays + TRACK_PADDING_DAYS);
57
- const daysBefore = Math.floor((resolvedTotalDays - resolvedWindowDays) / 3);
58
+ const daysBefore = Math.floor((VISIBLE_TRACK_DAYS - resolvedWindowDays) / 3);
58
59
  const startDate = addDays(referenceDate, -daysBefore);
59
- const endDate = addDays(startDate, resolvedTotalDays - 1);
60
+ const endDate = addDays(startDate, VISIBLE_TRACK_DAYS - 1);
60
61
  return { startDate, endDate };
61
62
  }
63
+ function ensureRangeVisibleOnTrack(range, bounds) {
64
+ if (!range.startDate || !range.endDate || !bounds.startDate || !bounds.endDate) {
65
+ return bounds;
66
+ }
67
+ let nextStartDate = bounds.startDate;
68
+ if (compareDateStrings(range.startDate, nextStartDate) < 0) {
69
+ nextStartDate = range.startDate;
70
+ }
71
+ const nextEndDate = addDays(nextStartDate, VISIBLE_TRACK_DAYS - 1);
72
+ if (compareDateStrings(range.endDate, nextEndDate) > 0) {
73
+ nextStartDate = addDays(range.endDate, -35);
74
+ }
75
+ if (nextStartDate === bounds.startDate && addDays(nextStartDate, VISIBLE_TRACK_DAYS - 1) === bounds.endDate) {
76
+ return bounds;
77
+ }
78
+ return {
79
+ startDate: nextStartDate,
80
+ endDate: addDays(nextStartDate, VISIBLE_TRACK_DAYS - 1),
81
+ };
82
+ }
62
83
  function clampDateToRange(date, bounds) {
63
84
  if (!bounds.startDate || !bounds.endDate) {
64
85
  return date;
@@ -81,6 +102,19 @@ function getDateByRatio(bounds, ratio) {
81
102
  return getTodayString();
82
103
  }
83
104
  const totalDays = Math.max(1, getDaysBetween(bounds.startDate, bounds.endDate));
105
+ return addDays(bounds.startDate, Math.round(totalDays * Math.max(0, Math.min(1, ratio))));
106
+ }
107
+ function getDateByOverflowRatio(bounds, ratio, trackWidth) {
108
+ if (!bounds.startDate || !bounds.endDate) {
109
+ return getTodayString();
110
+ }
111
+ const totalDays = Math.max(1, getDaysBetween(bounds.startDate, bounds.endDate));
112
+ if (ratio < 0) {
113
+ return addDays(bounds.startDate, Math.floor((ratio * trackWidth) / EDGE_OVERFLOW_PIXELS_PER_DAY));
114
+ }
115
+ if (ratio > 1) {
116
+ return addDays(bounds.endDate, Math.ceil(((ratio - 1) * trackWidth) / EDGE_OVERFLOW_PIXELS_PER_DAY));
117
+ }
84
118
  return addDays(bounds.startDate, Math.round(totalDays * ratio));
85
119
  }
86
120
  function getRatioByDate(date, bounds) {
@@ -117,8 +151,24 @@ function getMonthEnd(value) {
117
151
  const date = parseDateString(value);
118
152
  return formatDateString(new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 0)));
119
153
  }
154
+ function RollingMonthLabel({ value }) {
155
+ const [displayValue, setDisplayValue] = useState(value);
156
+ const [previousValue, setPreviousValue] = useState(null);
157
+ useEffect(() => {
158
+ if (value === displayValue) {
159
+ return undefined;
160
+ }
161
+ setPreviousValue(displayValue);
162
+ setDisplayValue(value);
163
+ const timeout = window.setTimeout(() => {
164
+ setPreviousValue(null);
165
+ }, 180);
166
+ return () => window.clearTimeout(timeout);
167
+ }, [displayValue, value]);
168
+ return (jsxs("span", { className: "relative inline-block h-5 min-w-10 overflow-hidden align-bottom", children: [previousValue ? (jsx("span", { className: "rd-date-range-month-out absolute inset-x-0 top-0 text-center", children: previousValue })) : null, jsx("span", { className: cn('absolute inset-x-0 top-0 text-center', previousValue && 'rd-date-range-month-in'), children: displayValue })] }));
169
+ }
120
170
  function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEFAULT_RANGE_DAYS, onOpenChange, loadingActions, loadingFullPage, onApply, onClear, }) {
121
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
171
+ var _a, _b, _c, _d, _e, _f;
122
172
  const resolvedDefaultRangeDays = clampWindowDays(defaultRangeDays);
123
173
  const [draftRange, setDraftRange] = useState(value);
124
174
  const [referenceDate, setReferenceDate] = useState(anchorDate);
@@ -136,6 +186,8 @@ function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEF
136
186
  const resultLabelRef = useRef(null);
137
187
  const selectionDaysRef = useRef(null);
138
188
  const dragPreviewRef = useRef(null);
189
+ const trackBoundsRef = useRef(trackBounds);
190
+ const dragStartTrackBoundsRef = useRef(null);
139
191
  const frameRef = useRef(null);
140
192
  const pendingClientXRef = useRef(null);
141
193
  const syncPreviewDomRef = useRef(() => { });
@@ -153,25 +205,27 @@ function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEF
153
205
  const isSingleDay = ((_c = draftRange.startDate) !== null && _c !== void 0 ? _c : null) === ((_d = draftRange.endDate) !== null && _d !== void 0 ? _d : null);
154
206
  const startHandlePercent = isSingleDay ? Math.max(leftPercent - 0.8, 0) : leftPercent;
155
207
  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 = 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]);
208
+ const trackTickCount = VISIBLE_TRACK_DAYS;
209
+ const leftMonthLabel = formatMonthShort((_e = trackBounds.startDate) !== null && _e !== void 0 ? _e : baseReferenceDate);
210
+ const rightMonthLabel = formatMonthShort((_f = trackBounds.endDate) !== null && _f !== void 0 ? _f : baseReferenceDate);
163
211
  const handleApply = useCallback(() => {
164
212
  return onApply(draftRange);
165
213
  }, [draftRange, onApply]);
214
+ function commitTrackBounds(nextTrackBounds) {
215
+ trackBoundsRef.current = nextTrackBounds;
216
+ setTrackBounds(nextTrackBounds);
217
+ }
166
218
  useEffect(() => {
167
219
  if (open && !previousOpenRef.current) {
220
+ const nextTrackBounds = buildTrackRange(baseReferenceDate, resolvedDefaultRangeDays);
168
221
  const nextRange = {
169
222
  startDate: baseReferenceDate,
170
223
  endDate: addDays(baseReferenceDate, resolvedDefaultRangeDays - 1),
171
224
  };
172
225
  setDraftRange(nextRange);
173
226
  setReferenceDate(baseReferenceDate);
174
- setTrackBounds(buildTrackRange(baseReferenceDate, resolvedDefaultRangeDays));
227
+ trackBoundsRef.current = nextTrackBounds;
228
+ setTrackBounds(nextTrackBounds);
175
229
  setWindowDays(resolvedDefaultRangeDays);
176
230
  dragStartRangeRef.current = null;
177
231
  dragModeRef.current = null;
@@ -189,16 +243,20 @@ function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEF
189
243
  setReferenceDate(nextReferenceDate);
190
244
  setWindowDays(clampedWindowDays);
191
245
  setDraftRange(nextRange);
192
- if (!(options === null || options === void 0 ? void 0 : options.preserveTrack)) {
193
- setTrackBounds(buildTrackRange(nextReferenceDate, clampedWindowDays));
246
+ if (options === null || options === void 0 ? void 0 : options.preserveTrack) {
247
+ commitTrackBounds(ensureRangeVisibleOnTrack(nextRange, trackBoundsRef.current));
248
+ }
249
+ else {
250
+ commitTrackBounds(buildTrackRange(nextReferenceDate, clampedWindowDays));
194
251
  }
195
252
  }
196
253
  const getPreviewPercents = useCallback((range) => {
197
254
  var _a, _b;
198
255
  const start = (_a = range.startDate) !== null && _a !== void 0 ? _a : baseReferenceDate;
199
256
  const end = (_b = range.endDate) !== null && _b !== void 0 ? _b : start;
200
- const startR = getRatioByDate(start, trackBounds);
201
- const endR = getRatioByDate(end, trackBounds);
257
+ const currentTrackBounds = trackBoundsRef.current;
258
+ const startR = getRatioByDate(start, currentTrackBounds);
259
+ const endR = getRatioByDate(end, currentTrackBounds);
202
260
  const left = Math.min(startR, endR) * 100;
203
261
  const right = Math.max(startR, endR) * 100;
204
262
  const width = Math.max(right - left, 0.5);
@@ -210,7 +268,7 @@ function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEF
210
268
  startHandle: single ? Math.max(left - 0.8, 0) : left,
211
269
  endHandle: single ? Math.min(right + 0.8, 100) : right,
212
270
  };
213
- }, [baseReferenceDate, trackBounds]);
271
+ }, [baseReferenceDate]);
214
272
  const syncPreviewDom = useCallback((range) => {
215
273
  const percents = getPreviewPercents(range);
216
274
  if (selectionRef.current) {
@@ -234,17 +292,20 @@ function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEF
234
292
  dragPreviewRef.current = draftRange;
235
293
  syncPreviewDom(draftRange);
236
294
  }, [draftRange, syncPreviewDom]);
295
+ useEffect(() => {
296
+ trackBoundsRef.current = trackBounds;
297
+ }, [trackBounds]);
237
298
  function resetReferenceFromClientX(clientX) {
238
299
  if (!trackRef.current) {
239
300
  return;
240
301
  }
241
302
  const rect = trackRef.current.getBoundingClientRect();
242
- const ratio = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
303
+ const ratio = (clientX - rect.left) / rect.width;
243
304
  const nextReferenceDate = getDateByRatio(trackBounds, ratio);
244
305
  updateRangeByReference(nextReferenceDate, resolvedDefaultRangeDays, { preserveTrack: true });
245
306
  }
246
307
  function applyQuickRange(dayCount) {
247
- updateRangeByReference(referenceDate, dayCount);
308
+ updateRangeByReference(referenceDate, dayCount, { preserveTrack: true });
248
309
  }
249
310
  function shiftReferenceDateByMonths(monthOffset) {
250
311
  updateRangeByReference(addMonthsClamped(referenceDate, monthOffset), windowDays);
@@ -258,16 +319,17 @@ function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEF
258
319
  pointerIdRef.current = pointerId;
259
320
  dragStartRangeRef.current = Object.assign({}, draftRange);
260
321
  dragPreviewRef.current = Object.assign({}, draftRange);
322
+ dragStartTrackBoundsRef.current = Object.assign({}, trackBoundsRef.current);
261
323
  if (mode === 'window' &&
262
324
  clientX !== undefined &&
263
325
  trackRef.current &&
264
326
  draftRange.startDate &&
265
327
  draftRange.endDate &&
266
- trackBounds.startDate &&
267
- trackBounds.endDate) {
328
+ dragStartTrackBoundsRef.current.startDate &&
329
+ dragStartTrackBoundsRef.current.endDate) {
268
330
  const rect = trackRef.current.getBoundingClientRect();
269
- const ratio = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
270
- const pointerDate = getDateByRatio(trackBounds, ratio);
331
+ const ratio = (clientX - rect.left) / rect.width;
332
+ const pointerDate = getDateByRatio(dragStartTrackBoundsRef.current, ratio);
271
333
  windowDragOffsetDaysRef.current = getDaysBetween(draftRange.startDate, pointerDate);
272
334
  }
273
335
  else {
@@ -275,36 +337,62 @@ function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEF
275
337
  }
276
338
  }
277
339
  const buildDraggedRange = useCallback((clientX) => {
278
- if (!dragModeRef.current || !dragStartRangeRef.current || !trackBounds.startDate || !trackBounds.endDate || !trackRef.current) {
340
+ const currentTrackBounds = trackBoundsRef.current;
341
+ const dragStartTrackBounds = dragStartTrackBoundsRef.current;
342
+ if (!dragModeRef.current ||
343
+ !dragStartRangeRef.current ||
344
+ !(dragStartTrackBounds === null || dragStartTrackBounds === void 0 ? void 0 : dragStartTrackBounds.startDate) ||
345
+ !dragStartTrackBounds.endDate ||
346
+ !currentTrackBounds.startDate ||
347
+ !currentTrackBounds.endDate ||
348
+ !trackRef.current) {
279
349
  return null;
280
350
  }
281
351
  const rect = trackRef.current.getBoundingClientRect();
282
- const ratio = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
283
- const pointerDate = getDateByRatio(trackBounds, ratio);
352
+ const ratio = (clientX - rect.left) / rect.width;
353
+ const pointerDate = getDateByOverflowRatio(dragStartTrackBounds, ratio, rect.width);
284
354
  const currentRange = dragStartRangeRef.current;
285
355
  if (!currentRange.startDate || !currentRange.endDate) {
286
356
  return null;
287
357
  }
288
358
  if (dragModeRef.current === 'start') {
289
- const earliestStart = addDays(currentRange.endDate, -29);
359
+ const earliestStart = addDays(currentRange.endDate, -30);
290
360
  const boundedPointerDate = compareDateStrings(pointerDate, earliestStart) < 0 ? earliestStart : pointerDate;
291
361
  const nextStart = compareDateStrings(boundedPointerDate, currentRange.endDate) > 0 ? currentRange.endDate : boundedPointerDate;
292
- return { startDate: nextStart, endDate: currentRange.endDate };
362
+ const nextRange = { startDate: nextStart, endDate: currentRange.endDate };
363
+ const nextTrackBounds = ensureRangeVisibleOnTrack(nextRange, currentTrackBounds);
364
+ if (nextTrackBounds !== currentTrackBounds) {
365
+ trackBoundsRef.current = nextTrackBounds;
366
+ setDraftRange(nextRange);
367
+ setTrackBounds(nextTrackBounds);
368
+ }
369
+ return nextRange;
293
370
  }
294
371
  if (dragModeRef.current === 'end') {
295
372
  const latestEnd = addDays(currentRange.startDate, MAX_RANGE_DAYS - 1);
296
373
  const boundedPointerDate = compareDateStrings(pointerDate, latestEnd) > 0 ? latestEnd : pointerDate;
297
374
  const nextEnd = compareDateStrings(boundedPointerDate, currentRange.startDate) < 0 ? currentRange.startDate : boundedPointerDate;
298
- return { startDate: currentRange.startDate, endDate: nextEnd };
375
+ const nextRange = { startDate: currentRange.startDate, endDate: nextEnd };
376
+ const nextTrackBounds = ensureRangeVisibleOnTrack(nextRange, currentTrackBounds);
377
+ if (nextTrackBounds !== currentTrackBounds) {
378
+ trackBoundsRef.current = nextTrackBounds;
379
+ setDraftRange(nextRange);
380
+ setTrackBounds(nextTrackBounds);
381
+ }
382
+ return nextRange;
299
383
  }
300
384
  const spanDays = getDaysBetween(currentRange.startDate, currentRange.endDate);
301
- const nextStart = clampDateToRange(addDays(pointerDate, -windowDragOffsetDaysRef.current), {
302
- startDate: trackBounds.startDate,
303
- endDate: addDays(trackBounds.endDate, -spanDays),
304
- });
385
+ const nextStart = addDays(pointerDate, -windowDragOffsetDaysRef.current);
305
386
  const nextEnd = addDays(nextStart, spanDays);
306
- return { startDate: nextStart, endDate: nextEnd };
307
- }, [trackBounds]);
387
+ const nextRange = { startDate: nextStart, endDate: nextEnd };
388
+ const nextTrackBounds = ensureRangeVisibleOnTrack(nextRange, currentTrackBounds);
389
+ if (nextTrackBounds !== currentTrackBounds) {
390
+ trackBoundsRef.current = nextTrackBounds;
391
+ setDraftRange(nextRange);
392
+ setTrackBounds(nextTrackBounds);
393
+ }
394
+ return nextRange;
395
+ }, []);
308
396
  useEffect(() => {
309
397
  syncPreviewDomRef.current = syncPreviewDom;
310
398
  buildDraggedRangeRef.current = buildDraggedRange;
@@ -318,6 +406,7 @@ function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEF
318
406
  document.body.style.userSelect = '';
319
407
  const nextRange = dragPreviewRef.current;
320
408
  dragStartRangeRef.current = null;
409
+ dragStartTrackBoundsRef.current = null;
321
410
  dragModeRef.current = null;
322
411
  pointerIdRef.current = null;
323
412
  windowDragOffsetDaysRef.current = 0;
@@ -325,6 +414,7 @@ function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEF
325
414
  setDraftRange(nextRange);
326
415
  setReferenceDate(nextRange.startDate);
327
416
  setWindowDays(getInclusiveDayCount(nextRange));
417
+ commitTrackBounds(ensureRangeVisibleOnTrack(nextRange, trackBoundsRef.current));
328
418
  }
329
419
  }
330
420
  useEffect(() => {
@@ -377,9 +467,7 @@ function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEF
377
467
  if (!open) {
378
468
  return jsx(Fragment, { children: dialogLoading });
379
469
  }
380
- return createPortal(jsxs(Fragment, { children: [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: 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: jsxs("div", { className: "space-y-5 p-4", children: [jsxs("div", { className: "relative flex items-center justify-center px-16 text-center", children: [jsx("div", { ref: resultLabelRef, className: "select-none text-base font-semibold text-slate-900 dark:text-white", children: getRangeLabel(draftRange) }), jsxs("div", { className: "absolute right-0 top-1/2 flex -translate-y-1/2 items-center gap-2", children: [jsx("button", { type: "button", onClick: () => onOpenChange(false), className: DIALOG_ICON_BUTTON_CLASS_NAME, "aria-label": "Cancel", children: jsx(XIcon, { className: "h-4 w-4" }) }), jsx("button", { type: "button", onClick: () => {
381
- void runDialogAction('confirm', handleApply);
382
- }, disabled: !draftRange.startDate || !draftRange.endDate, className: 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: jsx(CheckCheckIcon, { className: "h-4 w-4" }) })] })] }), jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex items-center justify-between gap-2", children: [jsxs("div", { className: "flex items-center gap-1", children: [jsx("button", Object.assign({ type: "button", onClick: () => {
470
+ return createPortal(jsxs(Fragment, { children: [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: 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: jsxs("div", { className: "space-y-5 p-4", children: [jsxs("div", { className: "relative flex items-center justify-center px-9 text-center sm:px-16", children: [jsx("div", { ref: resultLabelRef, className: "min-w-0 select-none truncate text-base font-semibold text-slate-900 dark:text-white", children: getRangeLabel(draftRange) }), jsx("div", { className: "absolute right-0 top-1/2 flex -translate-y-1/2 translate-x-1 items-center sm:translate-x-0", children: jsx("button", { type: "button", onClick: () => onOpenChange(false), className: DIALOG_ICON_BUTTON_CLASS_NAME, "aria-label": "Cancel", children: jsx(XIcon, { className: "h-4 w-4" }) }) })] }), jsxs("div", { className: "space-y-3", children: [jsxs("div", { className: "flex items-center justify-between gap-2", children: [jsxs("div", { className: "flex items-center gap-1", children: [jsx("button", Object.assign({ type: "button", onClick: () => {
383
471
  flashNavButtonPress('prevYear');
384
472
  shiftReferenceDateByYears(-1);
385
473
  }, className: cn(DIALOG_NAV_BUTTON_CLASS_NAME, pressedNavButton === 'prevYear'
@@ -395,11 +483,11 @@ function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEF
395
483
  endDate: addDays(baseReferenceDate, resolvedDefaultRangeDays - 1),
396
484
  };
397
485
  setReferenceDate(baseReferenceDate);
398
- setTrackBounds(buildTrackRange(baseReferenceDate, resolvedDefaultRangeDays));
486
+ commitTrackBounds(buildTrackRange(baseReferenceDate, resolvedDefaultRangeDays));
399
487
  setWindowDays(resolvedDefaultRangeDays);
400
488
  setDraftRange(nextRange);
401
489
  onClear === null || onClear === void 0 ? void 0 : onClear(nextRange);
402
- }, className: DIALOG_PILL_BUTTON_CLASS_NAME, children: "Current Day" }), jsx("button", { type: "button", onClick: () => {
490
+ }, className: DIALOG_PILL_BUTTON_CLASS_NAME, children: "Today" }), jsx("button", { type: "button", onClick: () => {
403
491
  const nextRange = {
404
492
  startDate: getMonthStart(referenceDate),
405
493
  endDate: addDays(getMonthStart(referenceDate), MAX_RANGE_DAYS - 1),
@@ -413,7 +501,8 @@ function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEF
413
501
  };
414
502
  setDraftRange(normalizedRange);
415
503
  setWindowDays(getInclusiveDayCount(normalizedRange));
416
- setTrackBounds(buildTrackRange(normalizedRange.startDate, getInclusiveDayCount(normalizedRange)));
504
+ setReferenceDate(normalizedRange.startDate);
505
+ commitTrackBounds(buildTrackRange(normalizedRange.startDate, getInclusiveDayCount(normalizedRange)));
417
506
  }, className: DIALOG_PILL_BUTTON_CLASS_NAME, children: "This Month" })] }), jsxs("div", { className: "flex items-center gap-1", children: [jsx("button", Object.assign({ type: "button", onClick: () => {
418
507
  flashNavButtonPress('nextMonth');
419
508
  shiftReferenceDateByMonths(1);
@@ -424,26 +513,63 @@ function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEF
424
513
  shiftReferenceDateByYears(1);
425
514
  }, className: cn(DIALOG_NAV_BUTTON_CLASS_NAME, pressedNavButton === 'nextYear'
426
515
  ? DIALOG_NAV_BUTTON_PRESSED_CLASS_NAME
427
- : DIALOG_NAV_BUTTON_REST_CLASS_NAME) }, getNavButtonPressProps('nextYear'), { "aria-label": "Next year", title: "Next year", children: jsx(ChevronsRightIcon, { className: "h-4 w-4" }) }))] })] }), jsxs("div", { className: "relative h-24", children: [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: [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), 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" }), 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" })] }), jsx("div", { className: "flex min-w-0 items-center justify-center gap-1", children: [
516
+ : DIALOG_NAV_BUTTON_REST_CLASS_NAME) }, getNavButtonPressProps('nextYear'), { "aria-label": "Next year", title: "Next year", children: jsx(ChevronsRightIcon, { className: "h-4 w-4" }) }))] })] }), jsxs("div", { className: "relative h-21", children: [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: [jsxs("span", { className: "relative block select-none text-center", children: [jsx(RollingMonthLabel, { value: leftMonthLabel }), 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" }), 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" })] }), jsx("div", { className: "flex min-w-0 items-center justify-center gap-1", children: [
428
517
  { label: '+7', days: 7 },
429
518
  { label: '+10', days: 10 },
430
519
  { label: '+15', days: 15 },
431
520
  { label: '+30', days: 30 },
432
- ].map((item) => (jsx("button", { type: "button", onClick: () => applyQuickRange(item.days), className: DIALOG_PILL_BUTTON_COMPACT_CLASS_NAME, children: item.label }, item.label))) }), 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), 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" }), 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" })] })] }), jsx("div", { className: "absolute inset-x-0 top-[3.35rem] h-10 touch-none", onDoubleClick: (event) => {
521
+ ].map((item) => (jsx("button", { type: "button", onClick: () => applyQuickRange(item.days), className: DIALOG_PILL_BUTTON_COMPACT_CLASS_NAME, children: item.label }, item.label))) }), jsxs("span", { className: "relative block select-none text-center", children: [jsx(RollingMonthLabel, { value: rightMonthLabel }), 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" }), 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" })] })] }), jsx("div", { className: "absolute inset-x-0 top-[3.35rem] h-10 touch-none", onDoubleClick: (event) => {
433
522
  event.stopPropagation();
434
523
  resetReferenceFromClientX(event.clientX);
435
524
  }, children: 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: [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) => {
436
525
  return (jsx("span", { className: "flex justify-center", children: jsx("span", { className: cn('rounded-full bg-slate-400/55 dark:bg-slate-500/55', 'h-3 w-px') }) }, index));
437
- }) }), 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) => {
526
+ }) }), jsx("div", { ref: selectionRef, className: "absolute top-1/2 z-10 h-4 touch-none -translate-y-1/2 overflow-visible rounded-md border bg-white dark:bg-slate-950", style: { left: `${leftPercent}%`, width: `${widthPercent}%`, borderColor: themeSvgIconColor }, onPointerDown: (event) => {
438
527
  event.stopPropagation();
439
528
  beginDrag('window', event.pointerId, event.clientX);
440
- }, children: 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` }) }), 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) => {
529
+ }, children: 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` }) }), 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 bg-white shadow-sm dark:bg-slate-950", style: { left: `${startHandlePercent}%`, borderColor: themeSvgIconColor }, onPointerDown: (event) => {
441
530
  event.stopPropagation();
442
531
  beginDrag('start', event.pointerId);
443
- }, "aria-label": "Adjust start date" }), 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) => {
532
+ }, "aria-label": "Adjust start date" }), 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 bg-white shadow-sm dark:bg-slate-950", style: { left: `${endHandlePercent}%`, borderColor: themeSvgIconColor }, onPointerDown: (event) => {
444
533
  event.stopPropagation();
445
534
  beginDrag('end', event.pointerId);
446
- }, "aria-label": "Adjust end date" })] }) })] })] })] }) }) }), dialogLoading] }), document.body);
535
+ }, "aria-label": "Adjust end date" })] }) })] }), jsx("div", { className: "flex justify-end", children: jsx(XButton, { type: "single", variant: "soft", minWidth: "min-w-[110px]", className: "w-auto", iconClassName: "h-4 w-4", button: {
536
+ icon: jsx(CheckCheckIcon, {}),
537
+ text: 'Apply',
538
+ disabled: !draftRange.startDate || !draftRange.endDate,
539
+ onClick: () => {
540
+ void runDialogAction('confirm', handleApply);
541
+ },
542
+ } }) })] })] }) }) }), jsx("style", { children: `
543
+ @keyframes rd-date-range-month-in {
544
+ from {
545
+ opacity: 0;
546
+ transform: translateY(-0.45rem);
547
+ }
548
+ to {
549
+ opacity: 1;
550
+ transform: translateY(0);
551
+ }
552
+ }
553
+
554
+ @keyframes rd-date-range-month-out {
555
+ from {
556
+ opacity: 1;
557
+ transform: translateY(0);
558
+ }
559
+ to {
560
+ opacity: 0;
561
+ transform: translateY(0.45rem);
562
+ }
563
+ }
564
+
565
+ .rd-date-range-month-in {
566
+ animation: rd-date-range-month-in 180ms ease-out both;
567
+ }
568
+
569
+ .rd-date-range-month-out {
570
+ animation: rd-date-range-month-out 180ms ease-out both;
571
+ }
572
+ ` }), dialogLoading] }), document.body);
447
573
  }
448
574
 
449
575
  export { RandomDateRangeDialog };
package/dist/main/cta.js CHANGED
@@ -11,6 +11,22 @@ var utils = require('@windrun-huaiin/lib/utils');
11
11
  var richTextExpert = require('./rich-text-expert.js');
12
12
  var sectionLayout = require('./section-layout.js');
13
13
 
14
+ const CTA_THEME_PALETTES = {
15
+ purple: { b: '#EC4899', c: '#6366F1' },
16
+ orange: { b: '#F59E0B', c: '#EF4444' },
17
+ indigo: { b: '#3B82F6', c: '#06B6D4' },
18
+ emerald: { b: '#14B8A6', c: '#22C55E' },
19
+ rose: { b: '#EC4899', c: '#FB7185' },
20
+ };
21
+ function createCTAStyle() {
22
+ var _a;
23
+ const palette = (_a = CTA_THEME_PALETTES[lib.themeName]) !== null && _a !== void 0 ? _a : CTA_THEME_PALETTES.purple;
24
+ return {
25
+ '--cta-color-a': lib.themeSvgIconColor,
26
+ '--cta-color-b': palette.b,
27
+ '--cta-color-c': palette.c,
28
+ };
29
+ }
14
30
  function CTA(_a) {
15
31
  return tslib.__awaiter(this, arguments, void 0, function* ({ locale, sectionClassName }) {
16
32
  const t = yield server.getTranslations({ locale, namespace: 'cta' });
@@ -22,7 +38,7 @@ function CTA(_a) {
22
38
  button: t('button'),
23
39
  url: t('url')
24
40
  };
25
- return (jsxRuntime.jsx("section", { id: "cta", className: utils.cn(sectionLayout.responsiveSection, sectionClassName), children: jsxRuntime.jsxs("div", { className: "\n py-3 sm:py-6 md:8\n bg-linear-to-r from-[#f7f8fa] via-[#e0c3fc] to-[#b2fefa]\n dark:bg-linear-to-r dark:from-[#2d0b4e] dark:via-[#6a3fa0] dark:to-[#3a185a]\n rounded-2xl text-center\n bg-size[200%_auto] animate-cta-gradient-wave\n ", children: [jsxRuntime.jsxs("h2", { className: "text-3xl md:text-4xl font-bold mb-6", children: [data.title, " ", jsxRuntime.jsx("span", { className: lib.themeIconColor, children: data.eyesOn }), "?"] }), jsxRuntime.jsxs("p", { className: "text-base sm:text-xl mx-auto mb-8 max-w-3xl", children: [data.description1, jsxRuntime.jsx("br", {}), jsxRuntime.jsx("span", { className: utils.cn(lib.themeIconColor, "text-xl sm:text-2xl"), children: data.description2 })] }), jsxRuntime.jsx(gradientButton.GradientButton, { title: data.button, href: data.url, align: "center" })] }) }));
41
+ return (jsxRuntime.jsx("section", { id: "cta", className: utils.cn(sectionLayout.responsiveSection, sectionClassName), children: jsxRuntime.jsx("div", { className: "\n third-ui-cta-surface\n relative overflow-hidden rounded-2xl border border-black/5 py-3 text-center shadow-sm\n animate-cta-gradient-wave\n sm:py-6 md:py-8\n dark:border-white/10 dark:shadow-none\n ", style: createCTAStyle(), children: jsxRuntime.jsxs("div", { className: "relative z-10 px-4 sm:px-6", children: [jsxRuntime.jsxs("h2", { className: "mb-6 text-3xl font-bold text-neutral-950 md:text-4xl dark:text-neutral-50", children: [data.title, " ", jsxRuntime.jsx("span", { className: lib.themeIconColor, children: data.eyesOn }), "?"] }), jsxRuntime.jsxs("p", { className: "mx-auto mb-8 max-w-3xl text-base text-neutral-700 sm:text-xl dark:text-neutral-300", children: [data.description1, jsxRuntime.jsx("br", {}), jsxRuntime.jsx("span", { className: utils.cn(lib.themeIconColor, "text-xl sm:text-2xl"), children: data.description2 })] }), jsxRuntime.jsx(gradientButton.GradientButton, { title: data.button, href: data.url, align: "center" })] }) }) }));
26
42
  });
27
43
  }
28
44
 
package/dist/main/cta.mjs CHANGED
@@ -4,11 +4,27 @@ import { getTranslations } from 'next-intl/server';
4
4
  import { GradientButton } from './buttons/gradient-button.mjs';
5
5
  import 'react';
6
6
  import '@windrun-huaiin/base-ui/icons';
7
- import { themeIconColor } from '@windrun-huaiin/base-ui/lib';
7
+ import { themeIconColor, themeSvgIconColor, themeName } from '@windrun-huaiin/base-ui/lib';
8
8
  import { cn } from '@windrun-huaiin/lib/utils';
9
9
  import { richText } from './rich-text-expert.mjs';
10
10
  import { responsiveSection } from './section-layout.mjs';
11
11
 
12
+ const CTA_THEME_PALETTES = {
13
+ purple: { b: '#EC4899', c: '#6366F1' },
14
+ orange: { b: '#F59E0B', c: '#EF4444' },
15
+ indigo: { b: '#3B82F6', c: '#06B6D4' },
16
+ emerald: { b: '#14B8A6', c: '#22C55E' },
17
+ rose: { b: '#EC4899', c: '#FB7185' },
18
+ };
19
+ function createCTAStyle() {
20
+ var _a;
21
+ const palette = (_a = CTA_THEME_PALETTES[themeName]) !== null && _a !== void 0 ? _a : CTA_THEME_PALETTES.purple;
22
+ return {
23
+ '--cta-color-a': themeSvgIconColor,
24
+ '--cta-color-b': palette.b,
25
+ '--cta-color-c': palette.c,
26
+ };
27
+ }
12
28
  function CTA(_a) {
13
29
  return __awaiter(this, arguments, void 0, function* ({ locale, sectionClassName }) {
14
30
  const t = yield getTranslations({ locale, namespace: 'cta' });
@@ -20,7 +36,7 @@ function CTA(_a) {
20
36
  button: t('button'),
21
37
  url: t('url')
22
38
  };
23
- return (jsx("section", { id: "cta", className: cn(responsiveSection, sectionClassName), children: jsxs("div", { className: "\n py-3 sm:py-6 md:8\n bg-linear-to-r from-[#f7f8fa] via-[#e0c3fc] to-[#b2fefa]\n dark:bg-linear-to-r dark:from-[#2d0b4e] dark:via-[#6a3fa0] dark:to-[#3a185a]\n rounded-2xl text-center\n bg-size[200%_auto] animate-cta-gradient-wave\n ", children: [jsxs("h2", { className: "text-3xl md:text-4xl font-bold mb-6", children: [data.title, " ", jsx("span", { className: themeIconColor, children: data.eyesOn }), "?"] }), jsxs("p", { className: "text-base sm:text-xl mx-auto mb-8 max-w-3xl", children: [data.description1, jsx("br", {}), jsx("span", { className: cn(themeIconColor, "text-xl sm:text-2xl"), children: data.description2 })] }), jsx(GradientButton, { title: data.button, href: data.url, align: "center" })] }) }));
39
+ return (jsx("section", { id: "cta", className: cn(responsiveSection, sectionClassName), children: jsx("div", { className: "\n third-ui-cta-surface\n relative overflow-hidden rounded-2xl border border-black/5 py-3 text-center shadow-sm\n animate-cta-gradient-wave\n sm:py-6 md:py-8\n dark:border-white/10 dark:shadow-none\n ", style: createCTAStyle(), children: jsxs("div", { className: "relative z-10 px-4 sm:px-6", children: [jsxs("h2", { className: "mb-6 text-3xl font-bold text-neutral-950 md:text-4xl dark:text-neutral-50", children: [data.title, " ", jsx("span", { className: themeIconColor, children: data.eyesOn }), "?"] }), jsxs("p", { className: "mx-auto mb-8 max-w-3xl text-base text-neutral-700 sm:text-xl dark:text-neutral-300", children: [data.description1, jsx("br", {}), jsx("span", { className: cn(themeIconColor, "text-xl sm:text-2xl"), children: data.description2 })] }), jsx(GradientButton, { title: data.button, href: data.url, align: "center" })] }) }) }));
24
40
  });
25
41
  }
26
42
 
@@ -3,5 +3,5 @@ interface DelayedImgProps extends ImageProps {
3
3
  wrapperClassName?: string;
4
4
  placeholderClassName?: string;
5
5
  }
6
- export declare function DelayedImg({ alt, wrapperClassName, placeholderClassName, className, onLoad, ...imageProps }: DelayedImgProps): import("react/jsx-runtime").JSX.Element;
6
+ export declare function DelayedImg({ alt, wrapperClassName, placeholderClassName, className, onError, onLoad, ...imageProps }: DelayedImgProps): import("react/jsx-runtime").JSX.Element;
7
7
  export {};
@@ -17,10 +17,10 @@ const ENV_DELAY_MS = Number.isFinite(parsedDelaySeconds) && parsedDelaySeconds >
17
17
  ? parsedDelaySeconds * 1000
18
18
  : 0;
19
19
  function DelayedImg(_a) {
20
- var { alt, wrapperClassName, placeholderClassName, className, onLoad } = _a, imageProps = tslib.__rest(_a, ["alt", "wrapperClassName", "placeholderClassName", "className", "onLoad"]);
20
+ var { alt, wrapperClassName, placeholderClassName, className, onError, onLoad } = _a, imageProps = tslib.__rest(_a, ["alt", "wrapperClassName", "placeholderClassName", "className", "onError", "onLoad"]);
21
21
  const shouldDelay = ENV_DELAY_ENABLED && ENV_DELAY_MS > 0;
22
22
  const [isMounted, setIsMounted] = React.useState(!shouldDelay);
23
- const [isLoaded, setIsLoaded] = React.useState(false);
23
+ const [isSettled, setIsSettled] = React.useState(false);
24
24
  React.useEffect(() => {
25
25
  if (!shouldDelay || isMounted) {
26
26
  return;
@@ -30,10 +30,13 @@ function DelayedImg(_a) {
30
30
  }, ENV_DELAY_MS);
31
31
  return () => window.clearTimeout(timer);
32
32
  }, [isMounted, shouldDelay]);
33
- return (jsxRuntime.jsxs("div", { className: utils.cn("relative", wrapperClassName), children: [(!isMounted || !isLoaded) && (jsxRuntime.jsx(snakeLoadingFrame.SnakeLoadingFrame, { shape: "rounded-rect", loading: true, themeColor: lib.themeSvgIconColor, className: utils.cn("absolute inset-0 rounded-[inherit] border shadow-sm bg-white/70 dark:bg-white/5", lib.themeBgColor, placeholderClassName), contentClassName: "h-full w-full", children: jsxRuntime.jsx("div", { "aria-hidden": "true", className: "absolute inset-0 rounded-[inherit] bg-white/20 dark:bg-white/0" }) })), isMounted && (jsxRuntime.jsx(Image, Object.assign({}, imageProps, { alt: alt, onLoad: (event) => {
34
- setIsLoaded(true);
33
+ return (jsxRuntime.jsxs("div", { className: utils.cn("relative", wrapperClassName), children: [(!isMounted || !isSettled) && (jsxRuntime.jsx(snakeLoadingFrame.SnakeLoadingFrame, { shape: "rounded-rect", loading: true, themeColor: lib.themeSvgIconColor, className: utils.cn("absolute inset-0 rounded-[inherit] border shadow-sm bg-white/70 dark:bg-white/5", lib.themeBgColor, placeholderClassName), contentClassName: "h-full w-full", children: jsxRuntime.jsx("div", { "aria-hidden": "true", className: "absolute inset-0 rounded-[inherit] bg-white/20 dark:bg-white/0" }) })), isMounted && (jsxRuntime.jsx(Image, Object.assign({}, imageProps, { alt: alt, onError: (event) => {
34
+ setIsSettled(true);
35
+ onError === null || onError === void 0 ? void 0 : onError(event);
36
+ }, onLoad: (event) => {
37
+ setIsSettled(true);
35
38
  onLoad === null || onLoad === void 0 ? void 0 : onLoad(event);
36
- }, className: utils.cn("transition duration-300", isLoaded ? "opacity-100" : "opacity-0", className) })))] }));
39
+ }, className: utils.cn("transition duration-300", isSettled ? "opacity-100" : "opacity-0", className) })))] }));
37
40
  }
38
41
 
39
42
  exports.DelayedImg = DelayedImg;
@@ -15,10 +15,10 @@ const ENV_DELAY_MS = Number.isFinite(parsedDelaySeconds) && parsedDelaySeconds >
15
15
  ? parsedDelaySeconds * 1000
16
16
  : 0;
17
17
  function DelayedImg(_a) {
18
- var { alt, wrapperClassName, placeholderClassName, className, onLoad } = _a, imageProps = __rest(_a, ["alt", "wrapperClassName", "placeholderClassName", "className", "onLoad"]);
18
+ var { alt, wrapperClassName, placeholderClassName, className, onError, onLoad } = _a, imageProps = __rest(_a, ["alt", "wrapperClassName", "placeholderClassName", "className", "onError", "onLoad"]);
19
19
  const shouldDelay = ENV_DELAY_ENABLED && ENV_DELAY_MS > 0;
20
20
  const [isMounted, setIsMounted] = useState(!shouldDelay);
21
- const [isLoaded, setIsLoaded] = useState(false);
21
+ const [isSettled, setIsSettled] = useState(false);
22
22
  useEffect(() => {
23
23
  if (!shouldDelay || isMounted) {
24
24
  return;
@@ -28,10 +28,13 @@ function DelayedImg(_a) {
28
28
  }, ENV_DELAY_MS);
29
29
  return () => window.clearTimeout(timer);
30
30
  }, [isMounted, shouldDelay]);
31
- return (jsxs("div", { className: cn("relative", wrapperClassName), children: [(!isMounted || !isLoaded) && (jsx(SnakeLoadingFrame, { shape: "rounded-rect", loading: true, themeColor: themeSvgIconColor, className: cn("absolute inset-0 rounded-[inherit] border shadow-sm bg-white/70 dark:bg-white/5", themeBgColor, placeholderClassName), contentClassName: "h-full w-full", children: jsx("div", { "aria-hidden": "true", className: "absolute inset-0 rounded-[inherit] bg-white/20 dark:bg-white/0" }) })), isMounted && (jsx(Image, Object.assign({}, imageProps, { alt: alt, onLoad: (event) => {
32
- setIsLoaded(true);
31
+ return (jsxs("div", { className: cn("relative", wrapperClassName), children: [(!isMounted || !isSettled) && (jsx(SnakeLoadingFrame, { shape: "rounded-rect", loading: true, themeColor: themeSvgIconColor, className: cn("absolute inset-0 rounded-[inherit] border shadow-sm bg-white/70 dark:bg-white/5", themeBgColor, placeholderClassName), contentClassName: "h-full w-full", children: jsx("div", { "aria-hidden": "true", className: "absolute inset-0 rounded-[inherit] bg-white/20 dark:bg-white/0" }) })), isMounted && (jsx(Image, Object.assign({}, imageProps, { alt: alt, onError: (event) => {
32
+ setIsSettled(true);
33
+ onError === null || onError === void 0 ? void 0 : onError(event);
34
+ }, onLoad: (event) => {
35
+ setIsSettled(true);
33
36
  onLoad === null || onLoad === void 0 ? void 0 : onLoad(event);
34
- }, className: cn("transition duration-300", isLoaded ? "opacity-100" : "opacity-0", className) })))] }));
37
+ }, className: cn("transition duration-300", isSettled ? "opacity-100" : "opacity-0", className) })))] }));
35
38
  }
36
39
 
37
40
  export { DelayedImg };