@sia.soul/sia-react-ui 0.1.40 → 0.1.42

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.
@@ -167,38 +167,66 @@ var activeTooltipClose;
167
167
  function clampFloating(value, min, max) {
168
168
  return Math.min(Math.max(value, min), Math.max(min, max));
169
169
  }
170
- function resolveFloatingPosition(trigger, overlay, placement) {
170
+ function normalizeFloatingPlacement(placement) {
171
+ const aliases = {
172
+ topLeft: "top-start",
173
+ topRight: "top-end",
174
+ bottomLeft: "bottom-start",
175
+ bottomRight: "bottom-end",
176
+ leftTop: "left-start",
177
+ leftBottom: "left-end",
178
+ rightTop: "right-start",
179
+ rightBottom: "right-end"
180
+ };
181
+ return aliases[placement] ?? placement;
182
+ }
183
+ function resolveFloatingPosition(trigger, overlay, placement, pointAtCenter, adjust) {
171
184
  const viewportWidth = document.documentElement.clientWidth;
172
185
  const viewportHeight = document.documentElement.clientHeight;
173
- let resolvedPlacement = placement;
174
- if (placement.startsWith("top") && trigger.top - overlay.height - FLOATING_GAP < FLOATING_VIEWPORT_PADDING && trigger.bottom + overlay.height + FLOATING_GAP <= viewportHeight - FLOATING_VIEWPORT_PADDING) {
175
- resolvedPlacement = placement.replace("top", "bottom");
176
- } else if (placement.startsWith("bottom") && trigger.bottom + overlay.height + FLOATING_GAP > viewportHeight - FLOATING_VIEWPORT_PADDING && trigger.top - overlay.height - FLOATING_GAP >= FLOATING_VIEWPORT_PADDING) {
177
- resolvedPlacement = placement.replace("bottom", "top");
178
- } else if (placement === "left" && trigger.left - overlay.width - FLOATING_GAP < FLOATING_VIEWPORT_PADDING && trigger.right + overlay.width + FLOATING_GAP <= viewportWidth - FLOATING_VIEWPORT_PADDING) {
179
- resolvedPlacement = "right";
180
- } else if (placement === "right" && trigger.right + overlay.width + FLOATING_GAP > viewportWidth - FLOATING_VIEWPORT_PADDING && trigger.left - overlay.width - FLOATING_GAP >= FLOATING_VIEWPORT_PADDING) {
181
- resolvedPlacement = "left";
186
+ let resolvedPlacement = normalizeFloatingPlacement(placement);
187
+ const side = resolvedPlacement.split("-")[0];
188
+ const available = { top: trigger.top, bottom: viewportHeight - trigger.bottom, left: trigger.left, right: viewportWidth - trigger.right };
189
+ const opposite = { top: "bottom", bottom: "top", left: "right", right: "left" };
190
+ const preferred = side;
191
+ const other = opposite[preferred];
192
+ const needed = (side === "top" || side === "bottom" ? overlay.height : overlay.width) + FLOATING_GAP + FLOATING_VIEWPORT_PADDING;
193
+ if (adjust && available[preferred] < needed && available[other] > available[preferred]) {
194
+ resolvedPlacement = resolvedPlacement.replace(preferred, other);
182
195
  }
183
- let top = trigger.top;
184
- let left = trigger.left;
185
- if (resolvedPlacement.startsWith("top") || resolvedPlacement.startsWith("bottom")) {
186
- top = resolvedPlacement.startsWith("top") ? trigger.top - overlay.height - FLOATING_GAP : trigger.bottom + FLOATING_GAP;
187
- left = resolvedPlacement.endsWith("-start") ? trigger.left : resolvedPlacement.endsWith("-end") ? trigger.right - overlay.width : trigger.left + (trigger.width - overlay.width) / 2;
188
- } else {
189
- top = trigger.top + (trigger.height - overlay.height) / 2;
190
- left = resolvedPlacement === "left" ? trigger.left - overlay.width - FLOATING_GAP : trigger.right + FLOATING_GAP;
196
+ const vertical = resolvedPlacement.startsWith("top") || resolvedPlacement.startsWith("bottom");
197
+ const start = resolvedPlacement.endsWith("-start");
198
+ const end = resolvedPlacement.endsWith("-end");
199
+ let top = vertical ? resolvedPlacement.startsWith("top") ? trigger.top - overlay.height - FLOATING_GAP : trigger.bottom + FLOATING_GAP : start ? trigger.top : end ? trigger.bottom - overlay.height : trigger.top + (trigger.height - overlay.height) / 2;
200
+ let left = vertical ? start ? trigger.left : end ? trigger.right - overlay.width : trigger.left + (trigger.width - overlay.width) / 2 : resolvedPlacement.startsWith("left") ? trigger.left - overlay.width - FLOATING_GAP : trigger.right + FLOATING_GAP;
201
+ if (adjust) {
202
+ if (vertical) left = clampFloating(left, FLOATING_VIEWPORT_PADDING, viewportWidth - overlay.width - FLOATING_VIEWPORT_PADDING);
203
+ else top = clampFloating(top, FLOATING_VIEWPORT_PADDING, viewportHeight - overlay.height - FLOATING_VIEWPORT_PADDING);
191
204
  }
192
- top = clampFloating(top, FLOATING_VIEWPORT_PADDING, viewportHeight - overlay.height - FLOATING_VIEWPORT_PADDING);
193
- left = clampFloating(left, FLOATING_VIEWPORT_PADDING, viewportWidth - overlay.width - FLOATING_VIEWPORT_PADDING);
194
205
  const result = { top, left, placement: resolvedPlacement };
195
- if (resolvedPlacement.startsWith("top") || resolvedPlacement.startsWith("bottom")) {
196
- result.arrowX = resolvedPlacement.endsWith("-start") ? clampFloating(FLOATING_ARROW_EDGE_OFFSET, 8, overlay.width - 16) : resolvedPlacement.endsWith("-end") ? clampFloating(overlay.width - FLOATING_ARROW_EDGE_OFFSET - 8, 8, overlay.width - 16) : clampFloating(trigger.left + trigger.width / 2 - left - 4, 8, overlay.width - 16);
197
- } else {
198
- result.arrowY = clampFloating(trigger.top + trigger.height / 2 - top - 4, 8, overlay.height - 16);
199
- }
206
+ const size = vertical ? trigger.width : trigger.height;
207
+ const anchorStart = vertical ? trigger.left : trigger.top;
208
+ const edge = Math.min(size / 2, FLOATING_ARROW_EDGE_OFFSET + 4);
209
+ const target = anchorStart + (pointAtCenter || !start && !end ? size / 2 : start ? edge : size - edge);
210
+ if (vertical) result.arrowX = clampFloating(target - left - 4, 8, overlay.width - 16);
211
+ else result.arrowY = clampFloating(target - top - 4, 8, overlay.height - 16);
200
212
  return result;
201
213
  }
214
+ function isFloatingAnchorHidden(anchor, rect) {
215
+ let left = 0, top = 0, right = document.documentElement.clientWidth, bottom = document.documentElement.clientHeight;
216
+ for (let parent = anchor.parentElement; parent; parent = parent.parentElement) {
217
+ const css = getComputedStyle(parent);
218
+ const bounds = parent.getBoundingClientRect();
219
+ if (/(auto|scroll|hidden|clip)/.test(css.overflowX)) {
220
+ left = Math.max(left, bounds.left);
221
+ right = Math.min(right, bounds.right);
222
+ }
223
+ if (/(auto|scroll|hidden|clip)/.test(css.overflowY)) {
224
+ top = Math.max(top, bounds.top);
225
+ bottom = Math.min(bottom, bounds.bottom);
226
+ }
227
+ }
228
+ return rect.right <= left || rect.left >= right || rect.bottom <= top || rect.top >= bottom;
229
+ }
202
230
  function Floating({
203
231
  children,
204
232
  content,
@@ -209,6 +237,7 @@ function Floating({
209
237
  mouseEnterDelay = 0.1,
210
238
  mouseLeaveDelay = 0.1,
211
239
  arrow = true,
240
+ autoAdjustOverflow = true,
212
241
  color,
213
242
  className = "",
214
243
  overlayClassName = "",
@@ -216,6 +245,7 @@ function Floating({
216
245
  onOpenChange
217
246
  }) {
218
247
  const rootRef = useRef2(null);
248
+ const triggerElementRef = useRef2(null);
219
249
  const overlayRef = useRef2(null);
220
250
  const enterTimer = useRef2();
221
251
  const leaveTimer = useRef2();
@@ -267,28 +297,42 @@ function Floating({
267
297
  setPosition(void 0);
268
298
  return;
269
299
  }
300
+ const getAnchor = () => {
301
+ const root = rootRef.current;
302
+ const target = triggerElementRef.current;
303
+ return target && root?.contains(target) ? target : root?.firstElementChild ?? root;
304
+ };
270
305
  const update = () => {
271
306
  if (!rootRef.current || !overlayRef.current) return;
272
- setPosition(resolveFloatingPosition(rootRef.current.getBoundingClientRect(), overlayRef.current.getBoundingClientRect(), placement));
307
+ const anchor2 = getAnchor();
308
+ if (anchor2) {
309
+ const rect = anchor2.getBoundingClientRect();
310
+ const next = resolveFloatingPosition(rect, overlayRef.current.getBoundingClientRect(), placement, typeof arrow === "object" && !!arrow.pointAtCenter, autoAdjustOverflow);
311
+ next.hidden = isFloatingAnchorHidden(anchor2, rect);
312
+ setPosition(next);
313
+ }
273
314
  };
274
315
  update();
275
316
  window.addEventListener("resize", update);
276
317
  window.addEventListener("scroll", update, true);
277
318
  const observer = new ResizeObserver(update);
278
319
  if (rootRef.current) observer.observe(rootRef.current);
320
+ const anchor = getAnchor();
321
+ if (anchor) observer.observe(anchor);
279
322
  if (overlayRef.current) observer.observe(overlayRef.current);
280
323
  return () => {
281
324
  window.removeEventListener("resize", update);
282
325
  window.removeEventListener("scroll", update, true);
283
326
  observer.disconnect();
284
327
  };
285
- }, [children, content, placement, visible]);
328
+ }, [children, content, placement, visible, autoAdjustOverflow, typeof arrow === "object" && arrow.pointAtCenter]);
286
329
  useEffect2(() => () => {
287
330
  clearTimers();
288
331
  if (activeTooltipClose === closeSelfRef.current) activeTooltipClose = void 0;
289
332
  }, []);
290
333
  const child = cloneElement(children, {
291
334
  ...triggers.includes("hover") ? { onMouseEnter: (event) => {
335
+ triggerElementRef.current = event.currentTarget;
292
336
  children.props.onMouseEnter?.(event);
293
337
  show(mouseEnterDelay);
294
338
  }, onMouseLeave: (event) => {
@@ -296,6 +340,7 @@ function Floating({
296
340
  hide(mouseLeaveDelay);
297
341
  } } : {},
298
342
  ...triggers.includes("focus") ? { onFocus: (event) => {
343
+ triggerElementRef.current = event.currentTarget;
299
344
  children.props.onFocus?.(event);
300
345
  show();
301
346
  }, onBlur: (event) => {
@@ -303,6 +348,7 @@ function Floating({
303
348
  hide();
304
349
  } } : {},
305
350
  ...triggers.includes("click") ? { onClick: (event) => {
351
+ triggerElementRef.current = event.currentTarget;
306
352
  children.props.onClick?.(event);
307
353
  if (visible) closeNow();
308
354
  else openNow();
@@ -317,14 +363,14 @@ function Floating({
317
363
  id: contentId,
318
364
  role,
319
365
  "data-custom-color": color ? "" : void 0,
320
- className: `sia-floating__overlay sia-floating__overlay--${position?.placement ?? placement} ${overlayClassName}`.trim(),
366
+ className: `sia-floating__overlay sia-floating__overlay--${position?.placement ?? normalizeFloatingPlacement(placement)} ${overlayClassName}`.trim(),
321
367
  style: {
322
368
  "--sia-floating-color": color,
323
369
  "--sia-floating-arrow-x": position?.arrowX == null ? void 0 : `${position.arrowX}px`,
324
370
  "--sia-floating-arrow-y": position?.arrowY == null ? void 0 : `${position.arrowY}px`,
325
371
  top: position?.top ?? 0,
326
372
  left: position?.left ?? 0,
327
- visibility: position ? "visible" : "hidden"
373
+ visibility: position && !position.hidden ? "visible" : "hidden"
328
374
  },
329
375
  onMouseEnter: triggers.includes("hover") ? () => show() : void 0,
330
376
  onMouseLeave: triggers.includes("hover") ? () => hide(mouseLeaveDelay) : void 0,
@@ -5,7 +5,7 @@ import {
5
5
  Popover,
6
6
  Tooltip,
7
7
  useOverlayLifecycle
8
- } from "./chunk-ZTJUFVJO.js";
8
+ } from "./chunk-3Q3S6CDZ.js";
9
9
  import {
10
10
  Dropdown,
11
11
  Icon
@@ -458,7 +458,7 @@ function Tabs({
458
458
  }
459
459
 
460
460
  // src/components/Feedback.tsx
461
- import { useEffect as useEffect2, useMemo as useMemo2, useState as useState4 } from "react";
461
+ import { cloneElement, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef3, useState as useState4 } from "react";
462
462
  import { createPortal } from "react-dom";
463
463
  import { createRoot } from "react-dom/client";
464
464
  import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
@@ -478,11 +478,53 @@ function Popconfirm({
478
478
  showCancel = true,
479
479
  icon = /* @__PURE__ */ jsx5(Icon, { name: "question", variant: "filled" }),
480
480
  onConfirm,
481
+ onConfirmError,
481
482
  onCancel,
482
- onOpenChange
483
+ onOpenChange,
484
+ arrow = true,
485
+ autoAdjustOverflow = true,
486
+ skipConfirm = false
483
487
  }) {
484
488
  const [visible, setVisible] = useControllableState({ value: open, defaultValue: defaultOpen, onChange: onOpenChange });
485
489
  const [loading, setLoading] = useState4(false);
490
+ const pendingRef = useRef3(false);
491
+ const requestRef = useRef3(0);
492
+ function changeVisible(next) {
493
+ if (!next) {
494
+ requestRef.current++;
495
+ pendingRef.current = false;
496
+ setLoading(false);
497
+ }
498
+ setVisible(next);
499
+ }
500
+ useEffect2(() => {
501
+ if (!visible) {
502
+ requestRef.current++;
503
+ pendingRef.current = false;
504
+ setLoading(false);
505
+ }
506
+ return () => {
507
+ requestRef.current++;
508
+ };
509
+ }, [visible]);
510
+ async function confirm(event) {
511
+ if (disabled || pendingRef.current || okButtonProps?.loading || okButtonProps?.disabled) return;
512
+ pendingRef.current = true;
513
+ const request = ++requestRef.current;
514
+ try {
515
+ const result = onConfirm?.(event);
516
+ if (result && typeof result === "object" && typeof result.then === "function") setLoading(true);
517
+ const resolved = await result;
518
+ if (request === requestRef.current && resolved !== false && visible) changeVisible(false);
519
+ } catch (error) {
520
+ if (request === requestRef.current) onConfirmError?.(error);
521
+ } finally {
522
+ if (request === requestRef.current) {
523
+ pendingRef.current = false;
524
+ setLoading(false);
525
+ }
526
+ }
527
+ }
486
528
  const content = /* @__PURE__ */ jsxs5("div", { className: "sia-popconfirm", children: [
487
529
  /* @__PURE__ */ jsxs5("div", { className: "sia-popconfirm__message", children: [
488
530
  /* @__PURE__ */ jsx5("span", { children: icon }),
@@ -494,24 +536,21 @@ function Popconfirm({
494
536
  /* @__PURE__ */ jsxs5("div", { className: "sia-popconfirm__actions", children: [
495
537
  showCancel ? /* @__PURE__ */ jsx5(Button, { size: "small", ...cancelButtonProps, onClick: (event) => {
496
538
  cancelButtonProps?.onClick?.(event);
539
+ if (event.defaultPrevented) return;
497
540
  onCancel?.(event);
498
- setVisible(false);
541
+ changeVisible(false);
499
542
  }, children: cancelText }) : null,
500
- /* @__PURE__ */ jsx5(Button, { size: "small", variant: "primary", ...okButtonProps, loading: loading || okButtonProps?.loading, onClick: async (event) => {
543
+ /* @__PURE__ */ jsx5(Button, { size: "small", variant: "primary", ...okButtonProps, loading: loading || okButtonProps?.loading, onClick: (event) => {
501
544
  okButtonProps?.onClick?.(event);
502
- const result = onConfirm?.(event);
503
- if (result instanceof Promise) {
504
- setLoading(true);
505
- try {
506
- if (await result !== false) setVisible(false);
507
- } finally {
508
- setLoading(false);
509
- }
510
- } else if (result !== false) setVisible(false);
545
+ if (!event.defaultPrevented) void confirm(event);
511
546
  }, children: okText })
512
547
  ] })
513
548
  ] });
514
- return /* @__PURE__ */ jsx5(Popover, { content, placement, trigger: disabled ? [] : trigger, open: visible, onOpenChange: setVisible, children });
549
+ const target = skipConfirm ? cloneElement(children, { onClick: (event) => {
550
+ children.props.onClick?.(event);
551
+ if (!event.defaultPrevented) void confirm(event);
552
+ } }) : children;
553
+ return /* @__PURE__ */ jsx5(Popover, { content, placement, arrow, autoAdjustOverflow, trigger: disabled || skipConfirm ? [] : trigger, open: visible && !skipConfirm && !disabled, onOpenChange: changeVisible, children: target });
515
554
  }
516
555
  function Progress({
517
556
  percent = 0,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  FloatingScrollbarProvider,
3
3
  Select
4
- } from "./chunk-ZTJUFVJO.js";
4
+ } from "./chunk-3Q3S6CDZ.js";
5
5
  import {
6
6
  Icon
7
7
  } from "./chunk-XCVAVCIO.js";
@@ -495,11 +495,12 @@ function DateRangePicker({
495
495
  const [currentValue, setCurrentValue] = useControllableState({ value: value === void 0 ? void 0 : Array.isArray(value) ? value : ["", ""], defaultValue, onChange });
496
496
  const [visible, setVisible] = useControllableState({ value: open, defaultValue: defaultOpen, onChange: onOpenChange });
497
497
  const [draftValue, setDraftValue] = useState(currentValue);
498
- const [activeIndex, setActiveIndex] = useState(currentValue[0] && !currentValue[1] ? 1 : 0);
498
+ const [activeIndex, setActiveIndex] = useState(endpointDisabled[0] || currentValue[0] && !currentValue[1] ? 1 : 0);
499
+ const [confirmedIndex, setConfirmedIndex] = useState(null);
500
+ const [presetSelected, setPresetSelected] = useState(false);
499
501
  const [hoverDate, setHoverDate] = useState("");
500
502
  const [viewMonth, setViewMonth] = useState(() => startOfMonth(parseDate(dayFromValue(currentValue[0] || currentValue[1])) ?? /* @__PURE__ */ new Date()));
501
503
  const [endViewMonth, setEndViewMonth] = useState(() => startOfMonth(parseDate(dayFromValue(currentValue[1])) ?? addMonths(parseDate(dayFromValue(currentValue[0])) ?? /* @__PURE__ */ new Date(), 1)));
502
- const [compactDateTime, setCompactDateTime] = useState(false);
503
504
  const showSecond = showSecondFrom(showTime);
504
505
  const defaultTime = defaultTimeFrom(showTime);
505
506
  const defaultEndTime = defaultTimeFrom(showTime, 1);
@@ -510,51 +511,46 @@ function DateRangePicker({
510
511
  const resolvedNeedConfirm = needConfirm ?? Boolean(showTime);
511
512
  const rangeDates = [dayFromValue(draftValue[0]), dayFromValue(draftValue[1])];
512
513
  const invalidDateTimeRange = Boolean(showTime && draftValue[0] && draftValue[1] && draftValue[0] > draftValue[1]);
513
- useEffect(() => {
514
- if (!showTime || typeof document === "undefined") {
515
- setCompactDateTime(false);
516
- return void 0;
517
- }
518
- const updateLayout = () => {
519
- const pairedPanelWidth = 2 * (280 + (showSecond ? 144 : 96) + 1) + 3;
520
- setCompactDateTime(document.documentElement.clientWidth < pairedPanelWidth + 16);
521
- };
522
- updateLayout();
523
- window.addEventListener("resize", updateLayout);
524
- return () => window.removeEventListener("resize", updateLayout);
525
- }, [showSecond, showTime]);
526
514
  useEffect(() => {
527
515
  if (!visible) return void 0;
528
516
  const close = (event) => {
529
517
  const target = event.target;
530
- if (!rootRef.current?.contains(target) && !popupRef.current?.contains(target)) setVisible(false);
518
+ if (!rootRef.current?.contains(target) && !popupRef.current?.contains(target)) dismissPanel();
531
519
  };
532
520
  document.addEventListener("pointerdown", close);
533
521
  return () => document.removeEventListener("pointerdown", close);
534
- }, [setVisible, visible]);
535
- function changeOpen(next) {
536
- if (next) {
522
+ });
523
+ function dismissPanel() {
524
+ setVisible(false);
525
+ }
526
+ function changeOpen(next, endpoint) {
527
+ if (next && !visible) {
528
+ setConfirmedIndex(null);
529
+ setPresetSelected(false);
537
530
  setDraftValue(currentValue);
538
531
  setTimes([timePart(currentValue[0], defaultTime), timePart(currentValue[1], defaultEndTime)]);
539
- setActiveIndex(endpointDisabled[0] ? 1 : endpointDisabled[1] ? 0 : currentValue[0] && !currentValue[1] ? 1 : 0);
532
+ setActiveIndex(endpointDisabled[0] ? 1 : endpointDisabled[1] ? 0 : endpoint ?? (currentValue[0] && !currentValue[1] ? 1 : 0));
540
533
  const nextStartMonth = startOfMonth(parseDate(dayFromValue(currentValue[0] || currentValue[1])) ?? /* @__PURE__ */ new Date());
541
534
  setViewMonth(nextStartMonth);
542
535
  setEndViewMonth(startOfMonth(parseDate(dayFromValue(currentValue[1])) ?? addMonths(nextStartMonth, 1)));
543
536
  }
537
+ if (next && endpoint !== void 0 && !endpointDisabled[endpoint]) setActiveIndex(endpoint);
544
538
  setVisible(next);
545
539
  }
546
- function isDisabled(day, index = activeIndex, pairedDateTime = false) {
540
+ function isDisabled(day, index = activeIndex, dateTimeStep = false) {
547
541
  if (endpointDisabled[index]) return true;
548
542
  const minimum = minDate ?? props.min;
549
543
  const maximum = maxDate ?? props.max;
550
544
  if (minimum && day < String(minimum).slice(0, 10)) return true;
551
545
  if (maximum && day > String(maximum).slice(0, 10)) return true;
552
546
  const from = index === 1 ? rangeDates[0] : void 0;
553
- if (pairedDateTime) {
554
- const otherEndpoint = index === 0 ? rangeDates[1] : rangeDates[0];
555
- if (index === 0 && otherEndpoint && day > otherEndpoint) return true;
556
- if (index === 1 && otherEndpoint && day < otherEndpoint) return true;
557
- if (otherEndpoint && maxRangeDays && Math.abs(daysBetween(otherEndpoint, day)) >= maxRangeDays) return true;
547
+ if (dateTimeStep) {
548
+ const otherIndex2 = index === 0 ? 1 : 0;
549
+ const otherEndpoint = rangeDates[otherIndex2];
550
+ if (otherEndpoint && (endpointDisabled[otherIndex2] || confirmedIndex === otherIndex2)) {
551
+ if (index === 0 && day > otherEndpoint || index === 1 && day < otherEndpoint) return true;
552
+ if (maxRangeDays && Math.abs(daysBetween(otherEndpoint, day)) >= maxRangeDays) return true;
553
+ }
558
554
  } else if (from && maxRangeDays && Math.abs(daysBetween(from, day)) >= maxRangeDays) return true;
559
555
  return disabledDate?.(day, { from, type: "date" }) ?? false;
560
556
  }
@@ -562,8 +558,12 @@ function DateRangePicker({
562
558
  return showTime ? withTime(day, times[index], showSecond) : day;
563
559
  }
564
560
  function updateDraft(next) {
561
+ setPresetSelected(false);
565
562
  setDraftValue(next);
566
563
  onCalendarChange?.(next);
564
+ if (!showTime && isValidRange(next) && (next[0] !== currentValue[0] || next[1] !== currentValue[1])) {
565
+ setCurrentValue(next);
566
+ }
567
567
  }
568
568
  function selectDate(day) {
569
569
  if (isDisabled(day)) return;
@@ -573,7 +573,6 @@ function DateRangePicker({
573
573
  next[index] = buildRangeValue(day, index);
574
574
  updateDraft(next);
575
575
  if (!resolvedNeedConfirm && isValidRange(next)) {
576
- setCurrentValue(next);
577
576
  changeOpen(false);
578
577
  }
579
578
  return;
@@ -591,7 +590,6 @@ function DateRangePicker({
591
590
  setActiveIndex(0);
592
591
  setHoverDate("");
593
592
  if (!resolvedNeedConfirm) {
594
- setCurrentValue(ordered);
595
593
  changeOpen(false);
596
594
  }
597
595
  }
@@ -601,16 +599,7 @@ function DateRangePicker({
601
599
  nextValue[index] = buildRangeValue(day, index);
602
600
  updateDraft(nextValue);
603
601
  setHoverDate("");
604
- if (!resolvedNeedConfirm && compactDateTime && index === 0) {
605
- setActiveIndex(1);
606
- setEndViewMonth(startOfMonth(parseDate(day) ?? /* @__PURE__ */ new Date()));
607
- return;
608
- }
609
602
  setActiveIndex(index);
610
- if (!resolvedNeedConfirm && nextValue[0] && nextValue[1] && nextValue[0] <= nextValue[1]) {
611
- setCurrentValue(nextValue);
612
- changeOpen(false);
613
- }
614
603
  }
615
604
  function changeTime(index, nextTime) {
616
605
  if (endpointDisabled[index]) return;
@@ -646,11 +635,16 @@ function DateRangePicker({
646
635
  }
647
636
  return true;
648
637
  }
638
+ const otherIndex = activeIndex === 0 ? 1 : 0;
639
+ const needsOtherConfirmation = Boolean(showTime && !presetSelected && !endpointDisabled[otherIndex] && confirmedIndex !== otherIndex);
649
640
  function confirm() {
650
- if (compactDateTime && showTime && activeIndex === 0) {
651
- if (!draftValue[0]) return;
652
- setActiveIndex(1);
653
- setEndViewMonth(startOfMonth(parseDate(dayFromValue(draftValue[1] || draftValue[0])) ?? /* @__PURE__ */ new Date()));
641
+ if (needsOtherConfirmation) {
642
+ if (!draftValue[activeIndex] && !allowEmpty[activeIndex]) return;
643
+ setConfirmedIndex(activeIndex);
644
+ setActiveIndex(otherIndex);
645
+ const month = startOfMonth(parseDate(dayFromValue(draftValue[activeIndex])) ?? /* @__PURE__ */ new Date());
646
+ if (otherIndex === 0) setViewMonth(month);
647
+ else setEndViewMonth(month);
654
648
  setHoverDate("");
655
649
  return;
656
650
  }
@@ -666,12 +660,13 @@ function DateRangePicker({
666
660
  ];
667
661
  if (!isValidRange(next)) return;
668
662
  updateDraft(next);
663
+ setConfirmedIndex(null);
664
+ setPresetSelected(true);
669
665
  setTimes([timePart(next[0], defaultTime), timePart(next[1], defaultEndTime)]);
670
666
  const nextStartMonth = startOfMonth(parseDate(dayFromValue(next[0] || next[1])) ?? /* @__PURE__ */ new Date());
671
667
  setViewMonth(nextStartMonth);
672
668
  setEndViewMonth(startOfMonth(parseDate(dayFromValue(next[1])) ?? addMonths(nextStartMonth, 1)));
673
- if (!resolvedNeedConfirm) {
674
- setCurrentValue(next);
669
+ if (!showTime && !resolvedNeedConfirm) {
675
670
  changeOpen(false);
676
671
  }
677
672
  }
@@ -721,6 +716,7 @@ function DateRangePicker({
721
716
  value: times[index],
722
717
  showSecond,
723
718
  ariaLabel: `${endpointLabel}\u65F6\u95F4`,
719
+ disabledTime: endpointDisabled[index] ? () => true : void 0,
724
720
  onChange: (nextTime) => changeTime(index, nextTime)
725
721
  }
726
722
  )
@@ -729,8 +725,9 @@ function DateRangePicker({
729
725
  endpointLabel
730
726
  );
731
727
  }
732
- const startFloating = useFloatingPlaceholder({ mode: placeholderMode, placeholder: placeholder[0], filled: Boolean(currentValue[0]), active: visible });
733
- const endFloating = useFloatingPlaceholder({ mode: placeholderMode, placeholder: placeholder[1], filled: Boolean(currentValue[1]), active: visible });
728
+ const displayValue = visible && allowEmpty.some(Boolean) ? draftValue : currentValue;
729
+ const startFloating = useFloatingPlaceholder({ mode: placeholderMode, placeholder: placeholder[0], filled: Boolean(displayValue[0]), active: visible });
730
+ const endFloating = useFloatingPlaceholder({ mode: placeholderMode, placeholder: placeholder[1], filled: Boolean(displayValue[1]), active: visible });
734
731
  return /* @__PURE__ */ jsxs2("span", { ref: rootRef, className: `sia-picker sia-picker-range-control sia-picker--${size} sia-picker--${status}${visible ? " is-open" : ""}${disabled ? " is-disabled" : ""} ${className}`.trim(), children: [
735
732
  /* @__PURE__ */ jsxs2(
736
733
  "button",
@@ -746,66 +743,68 @@ function DateRangePicker({
746
743
  "aria-describedby": props["aria-describedby"],
747
744
  "aria-errormessage": props["aria-errormessage"],
748
745
  disabled,
749
- onClick: () => changeOpen(!visible),
746
+ onClick: (event) => {
747
+ const field = event.target.closest("[data-range-endpoint]");
748
+ const endpoint = field?.dataset.rangeEndpoint;
749
+ if (showTime && (endpoint === "0" || endpoint === "1")) {
750
+ const index = Number(endpoint);
751
+ if (!endpointDisabled[index]) changeOpen(true, index);
752
+ } else if (visible) dismissPanel();
753
+ else changeOpen(true);
754
+ },
750
755
  children: [
751
- /* @__PURE__ */ jsxs2("span", { className: `sia-picker-range-control__field${startFloating.className}`, children: [
752
- /* @__PURE__ */ jsx2("span", { className: `sia-picker-range-control__value${currentValue[0] ? "" : " is-placeholder"}`, children: currentValue[0] ? formatValue(currentValue[0]) : placeholder[0] }),
756
+ /* @__PURE__ */ jsxs2("span", { "data-range-endpoint": "0", className: `sia-picker-range-control__field${startFloating.className}${visible && activeIndex === 0 ? " is-active" : ""}`, children: [
757
+ /* @__PURE__ */ jsx2("span", { className: `sia-picker-range-control__value${displayValue[0] ? "" : " is-placeholder"}`, children: displayValue[0] ? formatValue(displayValue[0]) : placeholder[0] }),
753
758
  startFloating.label
754
759
  ] }),
755
760
  /* @__PURE__ */ jsx2("span", { className: "sia-picker-range-control__separator", children: separator }),
756
- /* @__PURE__ */ jsxs2("span", { className: `sia-picker-range-control__field${endFloating.className}`, children: [
757
- /* @__PURE__ */ jsx2("span", { className: `sia-picker-range-control__value${currentValue[1] ? "" : " is-placeholder"}`, children: currentValue[1] ? formatValue(currentValue[1]) : placeholder[1] }),
761
+ /* @__PURE__ */ jsxs2("span", { "data-range-endpoint": "1", className: `sia-picker-range-control__field${endFloating.className}${visible && activeIndex === 1 ? " is-active" : ""}`, children: [
762
+ /* @__PURE__ */ jsx2("span", { className: `sia-picker-range-control__value${displayValue[1] ? "" : " is-placeholder"}`, children: displayValue[1] ? formatValue(displayValue[1]) : placeholder[1] }),
758
763
  endFloating.label
759
764
  ] }),
760
765
  /* @__PURE__ */ jsx2("span", { className: "sia-picker__icon", "aria-hidden": "true", children: suffixIcon ?? /* @__PURE__ */ jsx2(Icon, { name: "calendar", size: 16 }) })
761
766
  ]
762
767
  }
763
768
  ),
764
- allowClear && (currentValue[0] || currentValue[1]) && !disabled ? /* @__PURE__ */ jsx2("button", { type: "button", className: "sia-picker__clear", "aria-label": "\u6E05\u9664\u65E5\u671F\u8303\u56F4", onClick: clearValue, children: /* @__PURE__ */ jsx2(Icon, { name: "circle-close", variant: "filled", size: 15 }) }) : null,
765
- /* @__PURE__ */ jsxs2(PopupPortal, { ref: popupRef, anchorRef: rootRef, open: visible, className: `sia-date-panel sia-date-panel--range${showTime ? ` sia-date-panel--with-time sia-date-panel--range-time-${compactDateTime ? "compact" : "paired"}` : ""}${presets?.length ? " sia-date-panel--with-presets" : ""}`, role: "dialog", "aria-label": "\u65E5\u671F\u8303\u56F4\u9009\u62E9\u9762\u677F", children: [
766
- /* @__PURE__ */ jsx2("div", { className: "sia-date-panel__body", children: showTime ? /* @__PURE__ */ jsx2("div", { className: "sia-date-panel__range-date-time", children: compactDateTime ? renderDateTimeGroup(activeIndex) : /* @__PURE__ */ jsxs2(Fragment, { children: [
767
- renderDateTimeGroup(0),
768
- renderDateTimeGroup(1)
769
- ] }) }) : /* @__PURE__ */ jsxs2("div", { className: "sia-date-panel__range-calendars", children: [
770
- /* @__PURE__ */ jsxs2("section", { className: "sia-date-panel__calendar", children: [
771
- /* @__PURE__ */ jsx2(
772
- CalendarHeader,
773
- {
774
- month: viewMonth,
775
- range: true,
776
- onPreviousYear: () => setViewMonth(addMonths(viewMonth, -12)),
777
- onPreviousMonth: () => setViewMonth(addMonths(viewMonth, -1))
778
- }
779
- ),
780
- /* @__PURE__ */ jsx2(CalendarMonth, { month: viewMonth, range: rangeDates, previewEnd: activeIndex === 1 ? hoverDate : "", disabledDate: isDisabled, onSelect: selectDate, onHover: activeIndex === 1 ? setHoverDate : void 0 })
781
- ] }),
782
- /* @__PURE__ */ jsxs2("section", { className: "sia-date-panel__calendar", children: [
783
- /* @__PURE__ */ jsx2(
784
- CalendarHeader,
785
- {
786
- month: addMonths(viewMonth, 1),
787
- range: true,
788
- onNextMonth: () => setViewMonth(addMonths(viewMonth, 1)),
789
- onNextYear: () => setViewMonth(addMonths(viewMonth, 12))
790
- }
791
- ),
792
- /* @__PURE__ */ jsx2(CalendarMonth, { month: addMonths(viewMonth, 1), range: rangeDates, previewEnd: activeIndex === 1 ? hoverDate : "", disabledDate: isDisabled, onSelect: selectDate, onHover: activeIndex === 1 ? setHoverDate : void 0 })
769
+ allowClear && (displayValue[0] || displayValue[1]) && !disabled ? /* @__PURE__ */ jsx2("button", { type: "button", className: "sia-picker__clear", "aria-label": "\u6E05\u9664\u65E5\u671F\u8303\u56F4", onClick: clearValue, children: /* @__PURE__ */ jsx2(Icon, { name: "circle-close", variant: "filled", size: 15 }) }) : null,
770
+ /* @__PURE__ */ jsxs2(PopupPortal, { ref: popupRef, anchorRef: rootRef, open: visible, className: `sia-date-panel sia-date-panel--range${showTime ? " sia-date-panel--with-time sia-date-panel--range-time-compact" : ""}${presets?.length ? " sia-date-panel--with-presets" : ""}`, role: "dialog", "aria-label": "\u65E5\u671F\u8303\u56F4\u9009\u62E9\u9762\u677F", children: [
771
+ /* @__PURE__ */ jsxs2("div", { className: "sia-date-panel__body", children: [
772
+ presets?.length ? /* @__PURE__ */ jsx2("aside", { className: "sia-date-panel__presets", "aria-label": "\u5FEB\u6377\u65E5\u671F\u8303\u56F4", children: presets.map((preset, index) => /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => applyPreset(preset), children: preset.label }, index)) }) : null,
773
+ showTime ? /* @__PURE__ */ jsx2("div", { className: "sia-date-panel__range-date-time", children: renderDateTimeGroup(activeIndex) }) : /* @__PURE__ */ jsxs2("div", { className: "sia-date-panel__range-calendars", children: [
774
+ /* @__PURE__ */ jsxs2("section", { className: "sia-date-panel__calendar", children: [
775
+ /* @__PURE__ */ jsx2(
776
+ CalendarHeader,
777
+ {
778
+ month: viewMonth,
779
+ range: true,
780
+ onPreviousYear: () => setViewMonth(addMonths(viewMonth, -12)),
781
+ onPreviousMonth: () => setViewMonth(addMonths(viewMonth, -1))
782
+ }
783
+ ),
784
+ /* @__PURE__ */ jsx2(CalendarMonth, { month: viewMonth, range: rangeDates, previewEnd: activeIndex === 1 ? hoverDate : "", disabledDate: isDisabled, onSelect: selectDate, onHover: activeIndex === 1 ? setHoverDate : void 0 })
785
+ ] }),
786
+ /* @__PURE__ */ jsxs2("section", { className: "sia-date-panel__calendar", children: [
787
+ /* @__PURE__ */ jsx2(
788
+ CalendarHeader,
789
+ {
790
+ month: addMonths(viewMonth, 1),
791
+ range: true,
792
+ onNextMonth: () => setViewMonth(addMonths(viewMonth, 1)),
793
+ onNextYear: () => setViewMonth(addMonths(viewMonth, 12))
794
+ }
795
+ ),
796
+ /* @__PURE__ */ jsx2(CalendarMonth, { month: addMonths(viewMonth, 1), range: rangeDates, previewEnd: activeIndex === 1 ? hoverDate : "", disabledDate: isDisabled, onSelect: selectDate, onHover: activeIndex === 1 ? setHoverDate : void 0 })
797
+ ] })
793
798
  ] })
794
- ] }) }),
799
+ ] }),
795
800
  /* @__PURE__ */ jsx2(
796
801
  DatePanelFooter,
797
802
  {
798
803
  showToday: showToday && !presets?.length,
799
- needConfirm: resolvedNeedConfirm || allowEmpty.some(Boolean),
800
- disabledConfirm: compactDateTime && showTime && activeIndex === 0 ? !draftValue[0] : !isValidRange(draftValue),
801
- confirmText: compactDateTime && showTime && activeIndex === 0 ? "\u4E0B\u4E00\u6B65" : "\u786E\u5B9A",
804
+ needConfirm: Boolean(showTime) || resolvedNeedConfirm || allowEmpty.some(Boolean),
805
+ disabledConfirm: needsOtherConfirmation ? !draftValue[activeIndex] && !allowEmpty[activeIndex] : !isValidRange(draftValue),
802
806
  extra: /* @__PURE__ */ jsxs2(Fragment, { children: [
803
807
  renderExtraFooter?.(),
804
- presets?.map((preset, index) => /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => applyPreset(preset), children: preset.label }, index)),
805
- compactDateTime && showTime && activeIndex === 1 ? /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => {
806
- setActiveIndex(0);
807
- setViewMonth(startOfMonth(parseDate(dayFromValue(draftValue[0])) ?? /* @__PURE__ */ new Date()));
808
- }, children: "\u4E0A\u4E00\u6B65" }) : null,
809
808
  invalidDateTimeRange ? /* @__PURE__ */ jsx2("small", { className: "sia-date-panel__range-error", children: "\u7ED3\u675F\u65F6\u95F4\u4E0D\u80FD\u65E9\u4E8E\u5F00\u59CB\u65F6\u95F4" }) : maxRangeDays ? /* @__PURE__ */ jsxs2("small", { children: [
810
809
  "\u6700\u591A\u9009\u62E9 ",
811
810
  maxRangeDays,