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

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.
package/dist/index.cjs CHANGED
@@ -2531,38 +2531,66 @@ var activeTooltipClose;
2531
2531
  function clampFloating(value, min, max) {
2532
2532
  return Math.min(Math.max(value, min), Math.max(min, max));
2533
2533
  }
2534
- function resolveFloatingPosition(trigger, overlay, placement) {
2534
+ function normalizeFloatingPlacement(placement) {
2535
+ const aliases = {
2536
+ topLeft: "top-start",
2537
+ topRight: "top-end",
2538
+ bottomLeft: "bottom-start",
2539
+ bottomRight: "bottom-end",
2540
+ leftTop: "left-start",
2541
+ leftBottom: "left-end",
2542
+ rightTop: "right-start",
2543
+ rightBottom: "right-end"
2544
+ };
2545
+ return aliases[placement] ?? placement;
2546
+ }
2547
+ function resolveFloatingPosition(trigger, overlay, placement, pointAtCenter, adjust) {
2535
2548
  const viewportWidth = document.documentElement.clientWidth;
2536
2549
  const viewportHeight = document.documentElement.clientHeight;
2537
- let resolvedPlacement = placement;
2538
- if (placement.startsWith("top") && trigger.top - overlay.height - FLOATING_GAP < FLOATING_VIEWPORT_PADDING && trigger.bottom + overlay.height + FLOATING_GAP <= viewportHeight - FLOATING_VIEWPORT_PADDING) {
2539
- resolvedPlacement = placement.replace("top", "bottom");
2540
- } else if (placement.startsWith("bottom") && trigger.bottom + overlay.height + FLOATING_GAP > viewportHeight - FLOATING_VIEWPORT_PADDING && trigger.top - overlay.height - FLOATING_GAP >= FLOATING_VIEWPORT_PADDING) {
2541
- resolvedPlacement = placement.replace("bottom", "top");
2542
- } else if (placement === "left" && trigger.left - overlay.width - FLOATING_GAP < FLOATING_VIEWPORT_PADDING && trigger.right + overlay.width + FLOATING_GAP <= viewportWidth - FLOATING_VIEWPORT_PADDING) {
2543
- resolvedPlacement = "right";
2544
- } else if (placement === "right" && trigger.right + overlay.width + FLOATING_GAP > viewportWidth - FLOATING_VIEWPORT_PADDING && trigger.left - overlay.width - FLOATING_GAP >= FLOATING_VIEWPORT_PADDING) {
2545
- resolvedPlacement = "left";
2546
- }
2547
- let top = trigger.top;
2548
- let left = trigger.left;
2549
- if (resolvedPlacement.startsWith("top") || resolvedPlacement.startsWith("bottom")) {
2550
- top = resolvedPlacement.startsWith("top") ? trigger.top - overlay.height - FLOATING_GAP : trigger.bottom + FLOATING_GAP;
2551
- left = resolvedPlacement.endsWith("-start") ? trigger.left : resolvedPlacement.endsWith("-end") ? trigger.right - overlay.width : trigger.left + (trigger.width - overlay.width) / 2;
2552
- } else {
2553
- top = trigger.top + (trigger.height - overlay.height) / 2;
2554
- left = resolvedPlacement === "left" ? trigger.left - overlay.width - FLOATING_GAP : trigger.right + FLOATING_GAP;
2550
+ let resolvedPlacement = normalizeFloatingPlacement(placement);
2551
+ const side = resolvedPlacement.split("-")[0];
2552
+ const available = { top: trigger.top, bottom: viewportHeight - trigger.bottom, left: trigger.left, right: viewportWidth - trigger.right };
2553
+ const opposite = { top: "bottom", bottom: "top", left: "right", right: "left" };
2554
+ const preferred = side;
2555
+ const other = opposite[preferred];
2556
+ const needed = (side === "top" || side === "bottom" ? overlay.height : overlay.width) + FLOATING_GAP + FLOATING_VIEWPORT_PADDING;
2557
+ if (adjust && available[preferred] < needed && available[other] > available[preferred]) {
2558
+ resolvedPlacement = resolvedPlacement.replace(preferred, other);
2559
+ }
2560
+ const vertical = resolvedPlacement.startsWith("top") || resolvedPlacement.startsWith("bottom");
2561
+ const start = resolvedPlacement.endsWith("-start");
2562
+ const end = resolvedPlacement.endsWith("-end");
2563
+ 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;
2564
+ 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;
2565
+ if (adjust) {
2566
+ if (vertical) left = clampFloating(left, FLOATING_VIEWPORT_PADDING, viewportWidth - overlay.width - FLOATING_VIEWPORT_PADDING);
2567
+ else top = clampFloating(top, FLOATING_VIEWPORT_PADDING, viewportHeight - overlay.height - FLOATING_VIEWPORT_PADDING);
2555
2568
  }
2556
- top = clampFloating(top, FLOATING_VIEWPORT_PADDING, viewportHeight - overlay.height - FLOATING_VIEWPORT_PADDING);
2557
- left = clampFloating(left, FLOATING_VIEWPORT_PADDING, viewportWidth - overlay.width - FLOATING_VIEWPORT_PADDING);
2558
2569
  const result = { top, left, placement: resolvedPlacement };
2559
- if (resolvedPlacement.startsWith("top") || resolvedPlacement.startsWith("bottom")) {
2560
- 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);
2561
- } else {
2562
- result.arrowY = clampFloating(trigger.top + trigger.height / 2 - top - 4, 8, overlay.height - 16);
2563
- }
2570
+ const size = vertical ? trigger.width : trigger.height;
2571
+ const anchorStart = vertical ? trigger.left : trigger.top;
2572
+ const edge = Math.min(size / 2, FLOATING_ARROW_EDGE_OFFSET + 4);
2573
+ const target = anchorStart + (pointAtCenter || !start && !end ? size / 2 : start ? edge : size - edge);
2574
+ if (vertical) result.arrowX = clampFloating(target - left - 4, 8, overlay.width - 16);
2575
+ else result.arrowY = clampFloating(target - top - 4, 8, overlay.height - 16);
2564
2576
  return result;
2565
2577
  }
2578
+ function isFloatingAnchorHidden(anchor, rect) {
2579
+ let left = 0, top = 0, right = document.documentElement.clientWidth, bottom = document.documentElement.clientHeight;
2580
+ for (let parent = anchor.parentElement; parent; parent = parent.parentElement) {
2581
+ const css = getComputedStyle(parent);
2582
+ const bounds = parent.getBoundingClientRect();
2583
+ if (/(auto|scroll|hidden|clip)/.test(css.overflowX)) {
2584
+ left = Math.max(left, bounds.left);
2585
+ right = Math.min(right, bounds.right);
2586
+ }
2587
+ if (/(auto|scroll|hidden|clip)/.test(css.overflowY)) {
2588
+ top = Math.max(top, bounds.top);
2589
+ bottom = Math.min(bottom, bounds.bottom);
2590
+ }
2591
+ }
2592
+ return rect.right <= left || rect.left >= right || rect.bottom <= top || rect.top >= bottom;
2593
+ }
2566
2594
  function Floating({
2567
2595
  children,
2568
2596
  content,
@@ -2573,6 +2601,7 @@ function Floating({
2573
2601
  mouseEnterDelay = 0.1,
2574
2602
  mouseLeaveDelay = 0.1,
2575
2603
  arrow = true,
2604
+ autoAdjustOverflow = true,
2576
2605
  color,
2577
2606
  className = "",
2578
2607
  overlayClassName = "",
@@ -2580,6 +2609,7 @@ function Floating({
2580
2609
  onOpenChange
2581
2610
  }) {
2582
2611
  const rootRef = (0, import_react14.useRef)(null);
2612
+ const triggerElementRef = (0, import_react14.useRef)(null);
2583
2613
  const overlayRef = (0, import_react14.useRef)(null);
2584
2614
  const enterTimer = (0, import_react14.useRef)();
2585
2615
  const leaveTimer = (0, import_react14.useRef)();
@@ -2631,28 +2661,42 @@ function Floating({
2631
2661
  setPosition(void 0);
2632
2662
  return;
2633
2663
  }
2664
+ const getAnchor = () => {
2665
+ const root = rootRef.current;
2666
+ const target = triggerElementRef.current;
2667
+ return target && root?.contains(target) ? target : root?.firstElementChild ?? root;
2668
+ };
2634
2669
  const update = () => {
2635
2670
  if (!rootRef.current || !overlayRef.current) return;
2636
- setPosition(resolveFloatingPosition(rootRef.current.getBoundingClientRect(), overlayRef.current.getBoundingClientRect(), placement));
2671
+ const anchor2 = getAnchor();
2672
+ if (anchor2) {
2673
+ const rect = anchor2.getBoundingClientRect();
2674
+ const next = resolveFloatingPosition(rect, overlayRef.current.getBoundingClientRect(), placement, typeof arrow === "object" && !!arrow.pointAtCenter, autoAdjustOverflow);
2675
+ next.hidden = isFloatingAnchorHidden(anchor2, rect);
2676
+ setPosition(next);
2677
+ }
2637
2678
  };
2638
2679
  update();
2639
2680
  window.addEventListener("resize", update);
2640
2681
  window.addEventListener("scroll", update, true);
2641
2682
  const observer = new ResizeObserver(update);
2642
2683
  if (rootRef.current) observer.observe(rootRef.current);
2684
+ const anchor = getAnchor();
2685
+ if (anchor) observer.observe(anchor);
2643
2686
  if (overlayRef.current) observer.observe(overlayRef.current);
2644
2687
  return () => {
2645
2688
  window.removeEventListener("resize", update);
2646
2689
  window.removeEventListener("scroll", update, true);
2647
2690
  observer.disconnect();
2648
2691
  };
2649
- }, [children, content, placement, visible]);
2692
+ }, [children, content, placement, visible, autoAdjustOverflow, typeof arrow === "object" && arrow.pointAtCenter]);
2650
2693
  (0, import_react14.useEffect)(() => () => {
2651
2694
  clearTimers();
2652
2695
  if (activeTooltipClose === closeSelfRef.current) activeTooltipClose = void 0;
2653
2696
  }, []);
2654
2697
  const child = (0, import_react14.cloneElement)(children, {
2655
2698
  ...triggers.includes("hover") ? { onMouseEnter: (event) => {
2699
+ triggerElementRef.current = event.currentTarget;
2656
2700
  children.props.onMouseEnter?.(event);
2657
2701
  show(mouseEnterDelay);
2658
2702
  }, onMouseLeave: (event) => {
@@ -2660,6 +2704,7 @@ function Floating({
2660
2704
  hide(mouseLeaveDelay);
2661
2705
  } } : {},
2662
2706
  ...triggers.includes("focus") ? { onFocus: (event) => {
2707
+ triggerElementRef.current = event.currentTarget;
2663
2708
  children.props.onFocus?.(event);
2664
2709
  show();
2665
2710
  }, onBlur: (event) => {
@@ -2667,6 +2712,7 @@ function Floating({
2667
2712
  hide();
2668
2713
  } } : {},
2669
2714
  ...triggers.includes("click") ? { onClick: (event) => {
2715
+ triggerElementRef.current = event.currentTarget;
2670
2716
  children.props.onClick?.(event);
2671
2717
  if (visible) closeNow();
2672
2718
  else openNow();
@@ -2681,14 +2727,14 @@ function Floating({
2681
2727
  id: contentId,
2682
2728
  role,
2683
2729
  "data-custom-color": color ? "" : void 0,
2684
- className: `sia-floating__overlay sia-floating__overlay--${position?.placement ?? placement} ${overlayClassName}`.trim(),
2730
+ className: `sia-floating__overlay sia-floating__overlay--${position?.placement ?? normalizeFloatingPlacement(placement)} ${overlayClassName}`.trim(),
2685
2731
  style: {
2686
2732
  "--sia-floating-color": color,
2687
2733
  "--sia-floating-arrow-x": position?.arrowX == null ? void 0 : `${position.arrowX}px`,
2688
2734
  "--sia-floating-arrow-y": position?.arrowY == null ? void 0 : `${position.arrowY}px`,
2689
2735
  top: position?.top ?? 0,
2690
2736
  left: position?.left ?? 0,
2691
- visibility: position ? "visible" : "hidden"
2737
+ visibility: position && !position.hidden ? "visible" : "hidden"
2692
2738
  },
2693
2739
  onMouseEnter: triggers.includes("hover") ? () => show() : void 0,
2694
2740
  onMouseLeave: triggers.includes("hover") ? () => hide(mouseLeaveDelay) : void 0,
@@ -4737,11 +4783,53 @@ function Popconfirm({
4737
4783
  showCancel = true,
4738
4784
  icon = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Icon, { name: "question", variant: "filled" }),
4739
4785
  onConfirm,
4786
+ onConfirmError,
4740
4787
  onCancel,
4741
- onOpenChange
4788
+ onOpenChange,
4789
+ arrow = true,
4790
+ autoAdjustOverflow = true,
4791
+ skipConfirm = false
4742
4792
  }) {
4743
4793
  const [visible, setVisible] = useControllableState({ value: open, defaultValue: defaultOpen, onChange: onOpenChange });
4744
4794
  const [loading, setLoading] = (0, import_react23.useState)(false);
4795
+ const pendingRef = (0, import_react23.useRef)(false);
4796
+ const requestRef = (0, import_react23.useRef)(0);
4797
+ function changeVisible(next) {
4798
+ if (!next) {
4799
+ requestRef.current++;
4800
+ pendingRef.current = false;
4801
+ setLoading(false);
4802
+ }
4803
+ setVisible(next);
4804
+ }
4805
+ (0, import_react23.useEffect)(() => {
4806
+ if (!visible) {
4807
+ requestRef.current++;
4808
+ pendingRef.current = false;
4809
+ setLoading(false);
4810
+ }
4811
+ return () => {
4812
+ requestRef.current++;
4813
+ };
4814
+ }, [visible]);
4815
+ async function confirm(event) {
4816
+ if (disabled || pendingRef.current || okButtonProps?.loading || okButtonProps?.disabled) return;
4817
+ pendingRef.current = true;
4818
+ const request = ++requestRef.current;
4819
+ try {
4820
+ const result = onConfirm?.(event);
4821
+ if (result && typeof result === "object" && typeof result.then === "function") setLoading(true);
4822
+ const resolved = await result;
4823
+ if (request === requestRef.current && resolved !== false && visible) changeVisible(false);
4824
+ } catch (error) {
4825
+ if (request === requestRef.current) onConfirmError?.(error);
4826
+ } finally {
4827
+ if (request === requestRef.current) {
4828
+ pendingRef.current = false;
4829
+ setLoading(false);
4830
+ }
4831
+ }
4832
+ }
4745
4833
  const content = /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "sia-popconfirm", children: [
4746
4834
  /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "sia-popconfirm__message", children: [
4747
4835
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: icon }),
@@ -4753,24 +4841,21 @@ function Popconfirm({
4753
4841
  /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "sia-popconfirm__actions", children: [
4754
4842
  showCancel ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { size: "small", ...cancelButtonProps, onClick: (event) => {
4755
4843
  cancelButtonProps?.onClick?.(event);
4844
+ if (event.defaultPrevented) return;
4756
4845
  onCancel?.(event);
4757
- setVisible(false);
4846
+ changeVisible(false);
4758
4847
  }, children: cancelText }) : null,
4759
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { size: "small", variant: "primary", ...okButtonProps, loading: loading || okButtonProps?.loading, onClick: async (event) => {
4848
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { size: "small", variant: "primary", ...okButtonProps, loading: loading || okButtonProps?.loading, onClick: (event) => {
4760
4849
  okButtonProps?.onClick?.(event);
4761
- const result = onConfirm?.(event);
4762
- if (result instanceof Promise) {
4763
- setLoading(true);
4764
- try {
4765
- if (await result !== false) setVisible(false);
4766
- } finally {
4767
- setLoading(false);
4768
- }
4769
- } else if (result !== false) setVisible(false);
4850
+ if (!event.defaultPrevented) void confirm(event);
4770
4851
  }, children: okText })
4771
4852
  ] })
4772
4853
  ] });
4773
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Popover, { content, placement, trigger: disabled ? [] : trigger, open: visible, onOpenChange: setVisible, children });
4854
+ const target = skipConfirm ? (0, import_react23.cloneElement)(children, { onClick: (event) => {
4855
+ children.props.onClick?.(event);
4856
+ if (!event.defaultPrevented) void confirm(event);
4857
+ } }) : children;
4858
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Popover, { content, placement, arrow, autoAdjustOverflow, trigger: disabled || skipConfirm ? [] : trigger, open: visible && !skipConfirm && !disabled, onOpenChange: changeVisible, children: target });
4774
4859
  }
4775
4860
  function Progress({
4776
4861
  percent: percent2 = 0,
@@ -7345,11 +7430,12 @@ function DateRangePicker({
7345
7430
  const [currentValue, setCurrentValue] = useControllableState({ value: value === void 0 ? void 0 : Array.isArray(value) ? value : ["", ""], defaultValue, onChange });
7346
7431
  const [visible, setVisible] = useControllableState({ value: open, defaultValue: defaultOpen, onChange: onOpenChange });
7347
7432
  const [draftValue, setDraftValue] = (0, import_react34.useState)(currentValue);
7348
- const [activeIndex, setActiveIndex] = (0, import_react34.useState)(currentValue[0] && !currentValue[1] ? 1 : 0);
7433
+ const [activeIndex, setActiveIndex] = (0, import_react34.useState)(endpointDisabled[0] || currentValue[0] && !currentValue[1] ? 1 : 0);
7434
+ const [confirmedIndex, setConfirmedIndex] = (0, import_react34.useState)(null);
7435
+ const [presetSelected, setPresetSelected] = (0, import_react34.useState)(false);
7349
7436
  const [hoverDate, setHoverDate] = (0, import_react34.useState)("");
7350
7437
  const [viewMonth, setViewMonth] = (0, import_react34.useState)(() => startOfMonth(parseDate2(dayFromValue(currentValue[0] || currentValue[1])) ?? /* @__PURE__ */ new Date()));
7351
7438
  const [endViewMonth, setEndViewMonth] = (0, import_react34.useState)(() => startOfMonth(parseDate2(dayFromValue(currentValue[1])) ?? addMonths(parseDate2(dayFromValue(currentValue[0])) ?? /* @__PURE__ */ new Date(), 1)));
7352
- const [compactDateTime, setCompactDateTime] = (0, import_react34.useState)(false);
7353
7439
  const showSecond = showSecondFrom(showTime);
7354
7440
  const defaultTime = defaultTimeFrom(showTime);
7355
7441
  const defaultEndTime = defaultTimeFrom(showTime, 1);
@@ -7360,51 +7446,46 @@ function DateRangePicker({
7360
7446
  const resolvedNeedConfirm = needConfirm ?? Boolean(showTime);
7361
7447
  const rangeDates = [dayFromValue(draftValue[0]), dayFromValue(draftValue[1])];
7362
7448
  const invalidDateTimeRange = Boolean(showTime && draftValue[0] && draftValue[1] && draftValue[0] > draftValue[1]);
7363
- (0, import_react34.useEffect)(() => {
7364
- if (!showTime || typeof document === "undefined") {
7365
- setCompactDateTime(false);
7366
- return void 0;
7367
- }
7368
- const updateLayout = () => {
7369
- const pairedPanelWidth = 2 * (280 + (showSecond ? 144 : 96) + 1) + 3;
7370
- setCompactDateTime(document.documentElement.clientWidth < pairedPanelWidth + 16);
7371
- };
7372
- updateLayout();
7373
- window.addEventListener("resize", updateLayout);
7374
- return () => window.removeEventListener("resize", updateLayout);
7375
- }, [showSecond, showTime]);
7376
7449
  (0, import_react34.useEffect)(() => {
7377
7450
  if (!visible) return void 0;
7378
7451
  const close = (event) => {
7379
7452
  const target = event.target;
7380
- if (!rootRef.current?.contains(target) && !popupRef.current?.contains(target)) setVisible(false);
7453
+ if (!rootRef.current?.contains(target) && !popupRef.current?.contains(target)) dismissPanel();
7381
7454
  };
7382
7455
  document.addEventListener("pointerdown", close);
7383
7456
  return () => document.removeEventListener("pointerdown", close);
7384
- }, [setVisible, visible]);
7385
- function changeOpen(next) {
7386
- if (next) {
7457
+ });
7458
+ function dismissPanel() {
7459
+ setVisible(false);
7460
+ }
7461
+ function changeOpen(next, endpoint) {
7462
+ if (next && !visible) {
7463
+ setConfirmedIndex(null);
7464
+ setPresetSelected(false);
7387
7465
  setDraftValue(currentValue);
7388
7466
  setTimes([timePart(currentValue[0], defaultTime), timePart(currentValue[1], defaultEndTime)]);
7389
- setActiveIndex(endpointDisabled[0] ? 1 : endpointDisabled[1] ? 0 : currentValue[0] && !currentValue[1] ? 1 : 0);
7467
+ setActiveIndex(endpointDisabled[0] ? 1 : endpointDisabled[1] ? 0 : endpoint ?? (currentValue[0] && !currentValue[1] ? 1 : 0));
7390
7468
  const nextStartMonth = startOfMonth(parseDate2(dayFromValue(currentValue[0] || currentValue[1])) ?? /* @__PURE__ */ new Date());
7391
7469
  setViewMonth(nextStartMonth);
7392
7470
  setEndViewMonth(startOfMonth(parseDate2(dayFromValue(currentValue[1])) ?? addMonths(nextStartMonth, 1)));
7393
7471
  }
7472
+ if (next && endpoint !== void 0 && !endpointDisabled[endpoint]) setActiveIndex(endpoint);
7394
7473
  setVisible(next);
7395
7474
  }
7396
- function isDisabled(day, index = activeIndex, pairedDateTime = false) {
7475
+ function isDisabled(day, index = activeIndex, dateTimeStep = false) {
7397
7476
  if (endpointDisabled[index]) return true;
7398
7477
  const minimum = minDate ?? props.min;
7399
7478
  const maximum = maxDate ?? props.max;
7400
7479
  if (minimum && day < String(minimum).slice(0, 10)) return true;
7401
7480
  if (maximum && day > String(maximum).slice(0, 10)) return true;
7402
7481
  const from = index === 1 ? rangeDates[0] : void 0;
7403
- if (pairedDateTime) {
7404
- const otherEndpoint = index === 0 ? rangeDates[1] : rangeDates[0];
7405
- if (index === 0 && otherEndpoint && day > otherEndpoint) return true;
7406
- if (index === 1 && otherEndpoint && day < otherEndpoint) return true;
7407
- if (otherEndpoint && maxRangeDays && Math.abs(daysBetween(otherEndpoint, day)) >= maxRangeDays) return true;
7482
+ if (dateTimeStep) {
7483
+ const otherIndex2 = index === 0 ? 1 : 0;
7484
+ const otherEndpoint = rangeDates[otherIndex2];
7485
+ if (otherEndpoint && (endpointDisabled[otherIndex2] || confirmedIndex === otherIndex2)) {
7486
+ if (index === 0 && day > otherEndpoint || index === 1 && day < otherEndpoint) return true;
7487
+ if (maxRangeDays && Math.abs(daysBetween(otherEndpoint, day)) >= maxRangeDays) return true;
7488
+ }
7408
7489
  } else if (from && maxRangeDays && Math.abs(daysBetween(from, day)) >= maxRangeDays) return true;
7409
7490
  return disabledDate?.(day, { from, type: "date" }) ?? false;
7410
7491
  }
@@ -7412,8 +7493,12 @@ function DateRangePicker({
7412
7493
  return showTime ? withTime(day, times[index], showSecond) : day;
7413
7494
  }
7414
7495
  function updateDraft(next) {
7496
+ setPresetSelected(false);
7415
7497
  setDraftValue(next);
7416
7498
  onCalendarChange?.(next);
7499
+ if (!showTime && isValidRange(next) && (next[0] !== currentValue[0] || next[1] !== currentValue[1])) {
7500
+ setCurrentValue(next);
7501
+ }
7417
7502
  }
7418
7503
  function selectDate(day) {
7419
7504
  if (isDisabled(day)) return;
@@ -7423,7 +7508,6 @@ function DateRangePicker({
7423
7508
  next[index] = buildRangeValue(day, index);
7424
7509
  updateDraft(next);
7425
7510
  if (!resolvedNeedConfirm && isValidRange(next)) {
7426
- setCurrentValue(next);
7427
7511
  changeOpen(false);
7428
7512
  }
7429
7513
  return;
@@ -7441,7 +7525,6 @@ function DateRangePicker({
7441
7525
  setActiveIndex(0);
7442
7526
  setHoverDate("");
7443
7527
  if (!resolvedNeedConfirm) {
7444
- setCurrentValue(ordered);
7445
7528
  changeOpen(false);
7446
7529
  }
7447
7530
  }
@@ -7451,16 +7534,7 @@ function DateRangePicker({
7451
7534
  nextValue[index] = buildRangeValue(day, index);
7452
7535
  updateDraft(nextValue);
7453
7536
  setHoverDate("");
7454
- if (!resolvedNeedConfirm && compactDateTime && index === 0) {
7455
- setActiveIndex(1);
7456
- setEndViewMonth(startOfMonth(parseDate2(day) ?? /* @__PURE__ */ new Date()));
7457
- return;
7458
- }
7459
7537
  setActiveIndex(index);
7460
- if (!resolvedNeedConfirm && nextValue[0] && nextValue[1] && nextValue[0] <= nextValue[1]) {
7461
- setCurrentValue(nextValue);
7462
- changeOpen(false);
7463
- }
7464
7538
  }
7465
7539
  function changeTime(index, nextTime) {
7466
7540
  if (endpointDisabled[index]) return;
@@ -7496,11 +7570,16 @@ function DateRangePicker({
7496
7570
  }
7497
7571
  return true;
7498
7572
  }
7573
+ const otherIndex = activeIndex === 0 ? 1 : 0;
7574
+ const needsOtherConfirmation = Boolean(showTime && !presetSelected && !endpointDisabled[otherIndex] && confirmedIndex !== otherIndex);
7499
7575
  function confirm() {
7500
- if (compactDateTime && showTime && activeIndex === 0) {
7501
- if (!draftValue[0]) return;
7502
- setActiveIndex(1);
7503
- setEndViewMonth(startOfMonth(parseDate2(dayFromValue(draftValue[1] || draftValue[0])) ?? /* @__PURE__ */ new Date()));
7576
+ if (needsOtherConfirmation) {
7577
+ if (!draftValue[activeIndex] && !allowEmpty[activeIndex]) return;
7578
+ setConfirmedIndex(activeIndex);
7579
+ setActiveIndex(otherIndex);
7580
+ const month = startOfMonth(parseDate2(dayFromValue(draftValue[activeIndex])) ?? /* @__PURE__ */ new Date());
7581
+ if (otherIndex === 0) setViewMonth(month);
7582
+ else setEndViewMonth(month);
7504
7583
  setHoverDate("");
7505
7584
  return;
7506
7585
  }
@@ -7516,12 +7595,13 @@ function DateRangePicker({
7516
7595
  ];
7517
7596
  if (!isValidRange(next)) return;
7518
7597
  updateDraft(next);
7598
+ setConfirmedIndex(null);
7599
+ setPresetSelected(true);
7519
7600
  setTimes([timePart(next[0], defaultTime), timePart(next[1], defaultEndTime)]);
7520
7601
  const nextStartMonth = startOfMonth(parseDate2(dayFromValue(next[0] || next[1])) ?? /* @__PURE__ */ new Date());
7521
7602
  setViewMonth(nextStartMonth);
7522
7603
  setEndViewMonth(startOfMonth(parseDate2(dayFromValue(next[1])) ?? addMonths(nextStartMonth, 1)));
7523
- if (!resolvedNeedConfirm) {
7524
- setCurrentValue(next);
7604
+ if (!showTime && !resolvedNeedConfirm) {
7525
7605
  changeOpen(false);
7526
7606
  }
7527
7607
  }
@@ -7571,6 +7651,7 @@ function DateRangePicker({
7571
7651
  value: times[index],
7572
7652
  showSecond,
7573
7653
  ariaLabel: `${endpointLabel}\u65F6\u95F4`,
7654
+ disabledTime: endpointDisabled[index] ? () => true : void 0,
7574
7655
  onChange: (nextTime) => changeTime(index, nextTime)
7575
7656
  }
7576
7657
  )
@@ -7579,8 +7660,9 @@ function DateRangePicker({
7579
7660
  endpointLabel
7580
7661
  );
7581
7662
  }
7582
- const startFloating = useFloatingPlaceholder({ mode: placeholderMode, placeholder: placeholder[0], filled: Boolean(currentValue[0]), active: visible });
7583
- const endFloating = useFloatingPlaceholder({ mode: placeholderMode, placeholder: placeholder[1], filled: Boolean(currentValue[1]), active: visible });
7663
+ const displayValue = visible && allowEmpty.some(Boolean) ? draftValue : currentValue;
7664
+ const startFloating = useFloatingPlaceholder({ mode: placeholderMode, placeholder: placeholder[0], filled: Boolean(displayValue[0]), active: visible });
7665
+ const endFloating = useFloatingPlaceholder({ mode: placeholderMode, placeholder: placeholder[1], filled: Boolean(displayValue[1]), active: visible });
7584
7666
  return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("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: [
7585
7667
  /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
7586
7668
  "button",
@@ -7596,66 +7678,68 @@ function DateRangePicker({
7596
7678
  "aria-describedby": props["aria-describedby"],
7597
7679
  "aria-errormessage": props["aria-errormessage"],
7598
7680
  disabled,
7599
- onClick: () => changeOpen(!visible),
7681
+ onClick: (event) => {
7682
+ const field = event.target.closest("[data-range-endpoint]");
7683
+ const endpoint = field?.dataset.rangeEndpoint;
7684
+ if (showTime && (endpoint === "0" || endpoint === "1")) {
7685
+ const index = Number(endpoint);
7686
+ if (!endpointDisabled[index]) changeOpen(true, index);
7687
+ } else if (visible) dismissPanel();
7688
+ else changeOpen(true);
7689
+ },
7600
7690
  children: [
7601
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: `sia-picker-range-control__field${startFloating.className}`, children: [
7602
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: `sia-picker-range-control__value${currentValue[0] ? "" : " is-placeholder"}`, children: currentValue[0] ? formatValue2(currentValue[0]) : placeholder[0] }),
7691
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { "data-range-endpoint": "0", className: `sia-picker-range-control__field${startFloating.className}${visible && activeIndex === 0 ? " is-active" : ""}`, children: [
7692
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: `sia-picker-range-control__value${displayValue[0] ? "" : " is-placeholder"}`, children: displayValue[0] ? formatValue2(displayValue[0]) : placeholder[0] }),
7603
7693
  startFloating.label
7604
7694
  ] }),
7605
7695
  /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "sia-picker-range-control__separator", children: separator }),
7606
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: `sia-picker-range-control__field${endFloating.className}`, children: [
7607
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: `sia-picker-range-control__value${currentValue[1] ? "" : " is-placeholder"}`, children: currentValue[1] ? formatValue2(currentValue[1]) : placeholder[1] }),
7696
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { "data-range-endpoint": "1", className: `sia-picker-range-control__field${endFloating.className}${visible && activeIndex === 1 ? " is-active" : ""}`, children: [
7697
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: `sia-picker-range-control__value${displayValue[1] ? "" : " is-placeholder"}`, children: displayValue[1] ? formatValue2(displayValue[1]) : placeholder[1] }),
7608
7698
  endFloating.label
7609
7699
  ] }),
7610
7700
  /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "sia-picker__icon", "aria-hidden": "true", children: suffixIcon ?? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Icon, { name: "calendar", size: 16 }) })
7611
7701
  ]
7612
7702
  }
7613
7703
  ),
7614
- allowClear && (currentValue[0] || currentValue[1]) && !disabled ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("button", { type: "button", className: "sia-picker__clear", "aria-label": "\u6E05\u9664\u65E5\u671F\u8303\u56F4", onClick: clearValue, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Icon, { name: "circle-close", variant: "filled", size: 15 }) }) : null,
7615
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(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: [
7616
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "sia-date-panel__body", children: showTime ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "sia-date-panel__range-date-time", children: compactDateTime ? renderDateTimeGroup(activeIndex) : /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
7617
- renderDateTimeGroup(0),
7618
- renderDateTimeGroup(1)
7619
- ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "sia-date-panel__range-calendars", children: [
7620
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("section", { className: "sia-date-panel__calendar", children: [
7621
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
7622
- CalendarHeader,
7623
- {
7624
- month: viewMonth,
7625
- range: true,
7626
- onPreviousYear: () => setViewMonth(addMonths(viewMonth, -12)),
7627
- onPreviousMonth: () => setViewMonth(addMonths(viewMonth, -1))
7628
- }
7629
- ),
7630
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CalendarMonth, { month: viewMonth, range: rangeDates, previewEnd: activeIndex === 1 ? hoverDate : "", disabledDate: isDisabled, onSelect: selectDate, onHover: activeIndex === 1 ? setHoverDate : void 0 })
7631
- ] }),
7632
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("section", { className: "sia-date-panel__calendar", children: [
7633
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
7634
- CalendarHeader,
7635
- {
7636
- month: addMonths(viewMonth, 1),
7637
- range: true,
7638
- onNextMonth: () => setViewMonth(addMonths(viewMonth, 1)),
7639
- onNextYear: () => setViewMonth(addMonths(viewMonth, 12))
7640
- }
7641
- ),
7642
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CalendarMonth, { month: addMonths(viewMonth, 1), range: rangeDates, previewEnd: activeIndex === 1 ? hoverDate : "", disabledDate: isDisabled, onSelect: selectDate, onHover: activeIndex === 1 ? setHoverDate : void 0 })
7704
+ allowClear && (displayValue[0] || displayValue[1]) && !disabled ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("button", { type: "button", className: "sia-picker__clear", "aria-label": "\u6E05\u9664\u65E5\u671F\u8303\u56F4", onClick: clearValue, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Icon, { name: "circle-close", variant: "filled", size: 15 }) }) : null,
7705
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(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: [
7706
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "sia-date-panel__body", children: [
7707
+ presets?.length ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("aside", { className: "sia-date-panel__presets", "aria-label": "\u5FEB\u6377\u65E5\u671F\u8303\u56F4", children: presets.map((preset2, index) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("button", { type: "button", onClick: () => applyPreset(preset2), children: preset2.label }, index)) }) : null,
7708
+ showTime ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "sia-date-panel__range-date-time", children: renderDateTimeGroup(activeIndex) }) : /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "sia-date-panel__range-calendars", children: [
7709
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("section", { className: "sia-date-panel__calendar", children: [
7710
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
7711
+ CalendarHeader,
7712
+ {
7713
+ month: viewMonth,
7714
+ range: true,
7715
+ onPreviousYear: () => setViewMonth(addMonths(viewMonth, -12)),
7716
+ onPreviousMonth: () => setViewMonth(addMonths(viewMonth, -1))
7717
+ }
7718
+ ),
7719
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CalendarMonth, { month: viewMonth, range: rangeDates, previewEnd: activeIndex === 1 ? hoverDate : "", disabledDate: isDisabled, onSelect: selectDate, onHover: activeIndex === 1 ? setHoverDate : void 0 })
7720
+ ] }),
7721
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("section", { className: "sia-date-panel__calendar", children: [
7722
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
7723
+ CalendarHeader,
7724
+ {
7725
+ month: addMonths(viewMonth, 1),
7726
+ range: true,
7727
+ onNextMonth: () => setViewMonth(addMonths(viewMonth, 1)),
7728
+ onNextYear: () => setViewMonth(addMonths(viewMonth, 12))
7729
+ }
7730
+ ),
7731
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CalendarMonth, { month: addMonths(viewMonth, 1), range: rangeDates, previewEnd: activeIndex === 1 ? hoverDate : "", disabledDate: isDisabled, onSelect: selectDate, onHover: activeIndex === 1 ? setHoverDate : void 0 })
7732
+ ] })
7643
7733
  ] })
7644
- ] }) }),
7734
+ ] }),
7645
7735
  /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
7646
7736
  DatePanelFooter,
7647
7737
  {
7648
7738
  showToday: showToday && !presets?.length,
7649
- needConfirm: resolvedNeedConfirm || allowEmpty.some(Boolean),
7650
- disabledConfirm: compactDateTime && showTime && activeIndex === 0 ? !draftValue[0] : !isValidRange(draftValue),
7651
- confirmText: compactDateTime && showTime && activeIndex === 0 ? "\u4E0B\u4E00\u6B65" : "\u786E\u5B9A",
7739
+ needConfirm: Boolean(showTime) || resolvedNeedConfirm || allowEmpty.some(Boolean),
7740
+ disabledConfirm: needsOtherConfirmation ? !draftValue[activeIndex] && !allowEmpty[activeIndex] : !isValidRange(draftValue),
7652
7741
  extra: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
7653
7742
  renderExtraFooter?.(),
7654
- presets?.map((preset2, index) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("button", { type: "button", onClick: () => applyPreset(preset2), children: preset2.label }, index)),
7655
- compactDateTime && showTime && activeIndex === 1 ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("button", { type: "button", onClick: () => {
7656
- setActiveIndex(0);
7657
- setViewMonth(startOfMonth(parseDate2(dayFromValue(draftValue[0])) ?? /* @__PURE__ */ new Date()));
7658
- }, children: "\u4E0A\u4E00\u6B65" }) : null,
7659
7743
  invalidDateTimeRange ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("small", { className: "sia-date-panel__range-error", children: "\u7ED3\u675F\u65F6\u95F4\u4E0D\u80FD\u65E9\u4E8E\u5F00\u59CB\u65F6\u95F4" }) : maxRangeDays ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("small", { children: [
7660
7744
  "\u6700\u591A\u9009\u62E9 ",
7661
7745
  maxRangeDays,
@@ -15054,8 +15138,8 @@ var SIA_THEME = {
15054
15138
  controlHeight: 32,
15055
15139
  /** 默认布局间距,单位为像素。 */
15056
15140
  spacing: 16,
15057
- /** 默认字号,单位为像素。 */
15058
- fontSize: 16,
15141
+ /** 默认基础字号为 13 像素,对应 --sia-font-size;业务可通过 CSS 变量覆盖。 */
15142
+ fontSize: 13,
15059
15143
  /** 默认小号文字尺寸为 13 像素,对应 --sia-font-size-small;业务可通过 CSS 变量覆盖。 */
15060
15144
  fontSizeSmall: 13,
15061
15145
  /** 大号文字尺寸,单位为像素。 */
package/dist/index.css CHANGED
@@ -121,6 +121,16 @@ fieldset:disabled .sia-input-number__floating-placeholder {
121
121
  min-width: 0;
122
122
  height: 100%;
123
123
  }
124
+ .sia-picker-range-control__field.is-active::after {
125
+ content: "";
126
+ position: absolute;
127
+ right: 0;
128
+ bottom: -1px;
129
+ left: 0;
130
+ height: 3px;
131
+ background: var(--sia-color-primary);
132
+ pointer-events: none;
133
+ }
124
134
  .sia-picker-range-control__field.sia-placeholder-floating > .is-placeholder {
125
135
  color: transparent;
126
136
  }
@@ -405,7 +415,7 @@ fieldset:disabled .sia-input-number__floating-placeholder {
405
415
  --sia-control-height-large: 38px;
406
416
  --sia-control-height: var(--sia-control-height-medium);
407
417
  --sia-spacing: 16px;
408
- --sia-font-size: 16px;
418
+ --sia-font-size: 13px;
409
419
  --sia-font-size-small: 13px;
410
420
  --sia-control-font-size: 13px;
411
421
  --sia-font-size-large: 18px;
@@ -7380,6 +7390,7 @@ fieldset:disabled .sia-input-number__floating-placeholder {
7380
7390
  .sia-form-item__label {
7381
7391
  padding-top: 8px;
7382
7392
  text-align: right;
7393
+ font-size: 13px;
7383
7394
  line-height: 1.45;
7384
7395
  }
7385
7396
  .sia-form-item__required-mark {
@@ -9075,13 +9086,17 @@ body > .sia-popup-portal[data-sia-popup-layer] {
9075
9086
  border-top-width: 1px;
9076
9087
  border-left-width: 1px;
9077
9088
  }
9078
- .sia-floating__overlay--left .sia-floating__arrow {
9089
+ .sia-floating__overlay--left .sia-floating__arrow,
9090
+ .sia-floating__overlay--left-start .sia-floating__arrow,
9091
+ .sia-floating__overlay--left-end .sia-floating__arrow {
9079
9092
  top: var(--sia-floating-arrow-y, calc(50% - 4px));
9080
9093
  right: -4px;
9081
9094
  border-top-width: 1px;
9082
9095
  border-right-width: 1px;
9083
9096
  }
9084
- .sia-floating__overlay--right .sia-floating__arrow {
9097
+ .sia-floating__overlay--right .sia-floating__arrow,
9098
+ .sia-floating__overlay--right-start .sia-floating__arrow,
9099
+ .sia-floating__overlay--right-end .sia-floating__arrow {
9085
9100
  top: var(--sia-floating-arrow-y, calc(50% - 4px));
9086
9101
  left: -4px;
9087
9102
  border-bottom-width: 1px;