@sia.soul/sia-react-ui 0.1.39 → 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.
@@ -2,11 +2,10 @@ import {
2
2
  TextArea
3
3
  } from "./chunk-SMCYEPBL.js";
4
4
  import {
5
- FloatingScrollbarProvider,
6
5
  Popover,
7
6
  Tooltip,
8
7
  useOverlayLifecycle
9
- } from "./chunk-LRGD2QDA.js";
8
+ } from "./chunk-3Q3S6CDZ.js";
10
9
  import {
11
10
  Dropdown,
12
11
  Icon
@@ -191,6 +190,7 @@ function Tag({
191
190
  // src/components/Tabs.tsx
192
191
  import { useEffect, useId, useLayoutEffect as useLayoutEffect2, useMemo, useRef as useRef2, useState as useState3 } from "react";
193
192
  import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
193
+ import { createElement } from "react";
194
194
  function Tabs({
195
195
  items,
196
196
  activeKey,
@@ -225,6 +225,42 @@ function Tabs({
225
225
  const sliding = ["capsule", "line", "underline", "tech", "tech-line"].includes(type);
226
226
  const listRef = useRef2(null);
227
227
  const indicatorRef = useRef2(null);
228
+ const moreRef = useRef2(null);
229
+ const [overflow, setOverflow] = useState3({ count: items.length, width: 0 });
230
+ const [moreOpen, setMoreOpen] = useState3(false);
231
+ const visibleCount = resolvedOrientation === "horizontal" ? overflow.count : items.length;
232
+ const hiddenItems = items.slice(visibleCount);
233
+ useLayoutEffect2(() => {
234
+ const list = listRef.current;
235
+ if (!list || resolvedOrientation !== "horizontal") return;
236
+ const entries = Array.from(list.children).filter((node) => node instanceof HTMLElement && node.hasAttribute("data-tab-entry"));
237
+ const measure = () => {
238
+ const css = getComputedStyle(list);
239
+ const gap = parseFloat(css.columnGap) || 0;
240
+ const padding = (parseFloat(css.paddingLeft) || 0) + (parseFloat(css.paddingRight) || 0);
241
+ const widths = entries.map((node) => node.getBoundingClientRect().width);
242
+ const total = widths.reduce((sum, width2) => sum + width2, 0) + gap * Math.max(0, widths.length - 1);
243
+ const available = Math.max(0, list.clientWidth - padding);
244
+ let count = widths.length;
245
+ if (total > available + 0.5) {
246
+ const moreWidth = moreRef.current?.getBoundingClientRect().width ?? 36;
247
+ let used = moreWidth;
248
+ count = 0;
249
+ for (const width2 of widths) {
250
+ if (used + gap + width2 > available + 0.5) break;
251
+ used += gap + width2;
252
+ count++;
253
+ }
254
+ }
255
+ const width = Math.ceil(total + padding + (parseFloat(css.borderLeftWidth) || 0) + (parseFloat(css.borderRightWidth) || 0));
256
+ setOverflow((previous) => previous.count === count && previous.width === width ? previous : { count, width });
257
+ };
258
+ measure();
259
+ const observer = new ResizeObserver(measure);
260
+ observer.observe(list);
261
+ entries.forEach((entry) => observer.observe(entry));
262
+ return () => observer.disconnect();
263
+ }, [items, type, size, closable, resolvedOrientation, tabBarTitle, tabBarExtraContent]);
228
264
  const [contentState, setContentState] = useState3(() => ({ key: selectedKey, visited: /* @__PURE__ */ new Set([selectedKey]) }));
229
265
  const settledKeyRef = useRef2(selectedKey);
230
266
  const afterChangeRef = useRef2(onAfterChange);
@@ -239,16 +275,12 @@ function Tabs({
239
275
  function updateIndicator() {
240
276
  if (!list || !indicator) return;
241
277
  const active = list.querySelector('[role="tab"][aria-selected="true"]');
242
- if (!active) {
278
+ if (!active || active.closest('[data-tab-hidden="true"]')) {
243
279
  indicator.style.visibility = "hidden";
244
280
  return;
245
281
  }
246
282
  const listRect = list.getBoundingClientRect();
247
283
  const rect = active.getBoundingClientRect();
248
- if (type === "tech-line" && resolvedOrientation === "horizontal") {
249
- if (rect.left < listRect.left) list.scrollLeft += rect.left - listRect.left;
250
- else if (rect.right > listRect.right) list.scrollLeft += rect.right - listRect.right;
251
- }
252
284
  const currentRect = active.getBoundingClientRect();
253
285
  indicator.style.transform = `translate(${currentRect.left - listRect.left - list.clientLeft + list.scrollLeft}px, ${currentRect.top - listRect.top - list.clientTop + list.scrollTop}px)`;
254
286
  indicator.style.width = `${rect.width}px`;
@@ -264,7 +296,7 @@ function Tabs({
264
296
  observer.observe(list);
265
297
  list.querySelectorAll('[role="tab"]').forEach((tab) => observer.observe(tab));
266
298
  return () => observer.disconnect();
267
- }, [sliding, type, selectedKey, items, size, resolvedPosition, centered, closable]);
299
+ }, [sliding, type, selectedKey, items, size, resolvedPosition, centered, closable, visibleCount]);
268
300
  useEffect(() => {
269
301
  let cancelled = false;
270
302
  let frame = 0;
@@ -298,7 +330,8 @@ function Tabs({
298
330
  }
299
331
  function focusAndSelect(key) {
300
332
  selectTab(key);
301
- document.getElementById(`${baseId}-tab-${key}`)?.focus();
333
+ if (items.findIndex((item) => item.key === key) >= visibleCount) moreRef.current?.focus();
334
+ else document.getElementById(`${baseId}-tab-${key}`)?.focus();
302
335
  }
303
336
  function handleKeyDown(event, key) {
304
337
  const previousKey = resolvedOrientation === "horizontal" ? "ArrowLeft" : "ArrowUp";
@@ -320,54 +353,53 @@ function Tabs({
320
353
  ...withTitleTooltip(props),
321
354
  children: [
322
355
  /* @__PURE__ */ jsxs4("div", { className: "sia-tabs__header", children: [
323
- /* @__PURE__ */ jsx4(FloatingScrollbarProvider, { targetRef: listRef, disabled: type !== "tech-line" || resolvedOrientation !== "horizontal" }),
324
356
  tabBarTitle ? /* @__PURE__ */ jsxs4("div", { className: "sia-tabs__title", children: [
325
357
  tabBarTitle,
326
358
  type === "tech-line" ? /* @__PURE__ */ jsx4("svg", { className: "sia-tabs__title-connector", viewBox: "0 0 32 40", "aria-hidden": "true", children: /* @__PURE__ */ jsx4("path", { d: "M0 39.25 H5 Q8 39.25 10 35.25 L28 3.75 Q29 1.75 32 1.75", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinejoin: "round" }) }) : null
327
359
  ] }) : null,
328
- /* @__PURE__ */ jsxs4("div", { ref: listRef, className: `sia-tabs__list${sliding ? " sia-tabs__list--sliding" : ""}`, role: "tablist", "aria-orientation": resolvedOrientation, children: [
360
+ /* @__PURE__ */ jsxs4("div", { ref: listRef, style: resolvedOrientation === "horizontal" && overflow.width ? { width: overflow.width } : void 0, className: `sia-tabs__list${sliding ? " sia-tabs__list--sliding" : ""}`, role: "tablist", "aria-orientation": resolvedOrientation, children: [
329
361
  sliding ? /* @__PURE__ */ jsx4("span", { ref: indicatorRef, className: `sia-tabs__indicator${type === "capsule" ? " sia-tabs__capsule-indicator" : ""}`, "aria-hidden": "true", children: type === "tech-line" ? /* @__PURE__ */ jsx4("span", { className: "sia-tabs__indicator-shape", "aria-hidden": "true" }) : null }, type) : null,
330
- items.map((item) => {
362
+ items.map((item, index) => {
331
363
  const selected = item.key === selectedKey;
332
364
  const canClose = item.closable ?? closable;
333
- const tabNode = /* @__PURE__ */ jsxs4("span", { className: `sia-tabs__tab-wrap${canClose ? " is-closable" : ""}`, children: [
334
- /* @__PURE__ */ jsxs4(
335
- "button",
336
- {
337
- id: `${baseId}-tab-${item.key}`,
338
- type: "button",
339
- className: "sia-tabs__tab",
340
- role: "tab",
341
- "aria-selected": selected,
342
- "aria-controls": hasPanels ? `${baseId}-panel-${item.key}` : void 0,
343
- tabIndex: selected ? 0 : -1,
344
- disabled: item.disabled,
345
- onClick: () => selectTab(item.key),
346
- onKeyDown: (event) => handleKeyDown(event, item.key),
347
- children: [
348
- type === "tech-line" ? /* @__PURE__ */ jsx4("span", { className: "sia-tabs__tab-shape", "aria-hidden": "true" }) : null,
349
- item.icon ? /* @__PURE__ */ jsx4("span", { className: "sia-tabs__icon", children: item.icon }) : null,
350
- /* @__PURE__ */ jsx4("span", { children: item.label })
351
- ]
352
- }
353
- ),
354
- canClose ? /* @__PURE__ */ jsx4(
355
- "button",
356
- {
357
- type: "button",
358
- className: "sia-tabs__close",
359
- "aria-label": `\u5173\u95ED${typeof item.label === "string" ? item.label : "\u6807\u7B7E\u9875"}`,
360
- disabled: item.disabled,
361
- onClick: () => onEdit?.(item.key, "remove"),
362
- children: /* @__PURE__ */ jsx4(Icon, { name: "close", size: 12 })
363
- }
364
- ) : null
365
- ] }, item.key);
366
365
  const contextMenuItems = typeof tabContextMenu === "function" ? tabContextMenu(item) : tabContextMenu;
366
+ const entryProps = { "data-tab-entry": "", "data-tab-hidden": index >= visibleCount, "aria-hidden": index >= visibleCount || void 0 };
367
+ const tabNode = /* @__PURE__ */ createElement("span", { ...!contextMenuItems?.length ? entryProps : {}, className: `sia-tabs__tab-wrap${canClose ? " is-closable" : ""}`, key: item.key }, /* @__PURE__ */ jsxs4(
368
+ "button",
369
+ {
370
+ id: `${baseId}-tab-${item.key}`,
371
+ type: "button",
372
+ className: "sia-tabs__tab",
373
+ role: "tab",
374
+ "aria-selected": selected,
375
+ "aria-controls": hasPanels ? `${baseId}-panel-${item.key}` : void 0,
376
+ tabIndex: selected ? 0 : -1,
377
+ disabled: item.disabled,
378
+ onClick: () => selectTab(item.key),
379
+ onKeyDown: (event) => handleKeyDown(event, item.key),
380
+ children: [
381
+ type === "tech-line" ? /* @__PURE__ */ jsx4("span", { className: "sia-tabs__tab-shape", "aria-hidden": "true" }) : null,
382
+ item.icon ? /* @__PURE__ */ jsx4("span", { className: "sia-tabs__icon", children: item.icon }) : null,
383
+ /* @__PURE__ */ jsx4("span", { children: item.label })
384
+ ]
385
+ }
386
+ ), canClose ? /* @__PURE__ */ jsx4(
387
+ "button",
388
+ {
389
+ type: "button",
390
+ className: "sia-tabs__close",
391
+ "aria-label": `\u5173\u95ED${typeof item.label === "string" ? item.label : "\u6807\u7B7E\u9875"}`,
392
+ disabled: item.disabled,
393
+ onClick: () => onEdit?.(item.key, "remove"),
394
+ children: /* @__PURE__ */ jsx4(Icon, { name: "close", size: 12 })
395
+ }
396
+ ) : null);
367
397
  if (!contextMenuItems?.length) return tabNode;
368
- return /* @__PURE__ */ jsx4(
398
+ return /* @__PURE__ */ createElement(
369
399
  Dropdown,
370
400
  {
401
+ ...entryProps,
402
+ key: item.key,
371
403
  className: "sia-tabs__tab-context-trigger",
372
404
  popupClassName: "sia-tabs__tab-context-menu",
373
405
  trigger: ["contextMenu"],
@@ -376,12 +408,26 @@ function Tabs({
376
408
  items: contextMenuItems,
377
409
  selectable: false,
378
410
  onClick: (info) => onTabContextMenuClick?.({ ...info, tabKey: item.key, tab: item })
379
- },
380
- children: tabNode
411
+ }
381
412
  },
382
- item.key
413
+ tabNode
383
414
  );
384
- })
415
+ }),
416
+ resolvedOrientation === "horizontal" ? /* @__PURE__ */ jsx4(
417
+ Dropdown,
418
+ {
419
+ className: "sia-tabs__more",
420
+ "data-tab-hidden": !hiddenItems.length,
421
+ trigger: ["hover", "click"],
422
+ placement: "bottomRight",
423
+ showTriggerIcon: false,
424
+ autoFocus: true,
425
+ open: moreOpen && hiddenItems.length > 0,
426
+ onOpenChange: setMoreOpen,
427
+ menu: { items: hiddenItems.map((item) => ({ key: item.key, label: item.label, icon: item.icon, disabled: item.disabled })), selectedKeys: [selectedKey], onClick: (info) => selectTab(info.key) },
428
+ children: /* @__PURE__ */ jsx4(Button, { ref: moreRef, variant: "text", icon: /* @__PURE__ */ jsx4(Icon, { name: "more-horizontal" }), "aria-label": "\u66F4\u591A\u9009\u9879\u5361", onKeyDown: (event) => handleKeyDown(event, selectedKey), className: hiddenItems.some((item) => item.key === selectedKey) ? "is-active" : void 0 })
429
+ }
430
+ ) : null
385
431
  ] }),
386
432
  tabBarExtraContent ? /* @__PURE__ */ jsx4("div", { className: "sia-tabs__extra", children: tabBarExtraContent }) : null
387
433
  ] }),
@@ -412,7 +458,7 @@ function Tabs({
412
458
  }
413
459
 
414
460
  // src/components/Feedback.tsx
415
- 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";
416
462
  import { createPortal } from "react-dom";
417
463
  import { createRoot } from "react-dom/client";
418
464
  import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
@@ -432,11 +478,53 @@ function Popconfirm({
432
478
  showCancel = true,
433
479
  icon = /* @__PURE__ */ jsx5(Icon, { name: "question", variant: "filled" }),
434
480
  onConfirm,
481
+ onConfirmError,
435
482
  onCancel,
436
- onOpenChange
483
+ onOpenChange,
484
+ arrow = true,
485
+ autoAdjustOverflow = true,
486
+ skipConfirm = false
437
487
  }) {
438
488
  const [visible, setVisible] = useControllableState({ value: open, defaultValue: defaultOpen, onChange: onOpenChange });
439
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
+ }
440
528
  const content = /* @__PURE__ */ jsxs5("div", { className: "sia-popconfirm", children: [
441
529
  /* @__PURE__ */ jsxs5("div", { className: "sia-popconfirm__message", children: [
442
530
  /* @__PURE__ */ jsx5("span", { children: icon }),
@@ -448,24 +536,21 @@ function Popconfirm({
448
536
  /* @__PURE__ */ jsxs5("div", { className: "sia-popconfirm__actions", children: [
449
537
  showCancel ? /* @__PURE__ */ jsx5(Button, { size: "small", ...cancelButtonProps, onClick: (event) => {
450
538
  cancelButtonProps?.onClick?.(event);
539
+ if (event.defaultPrevented) return;
451
540
  onCancel?.(event);
452
- setVisible(false);
541
+ changeVisible(false);
453
542
  }, children: cancelText }) : null,
454
- /* @__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) => {
455
544
  okButtonProps?.onClick?.(event);
456
- const result = onConfirm?.(event);
457
- if (result instanceof Promise) {
458
- setLoading(true);
459
- try {
460
- if (await result !== false) setVisible(false);
461
- } finally {
462
- setLoading(false);
463
- }
464
- } else if (result !== false) setVisible(false);
545
+ if (!event.defaultPrevented) void confirm(event);
465
546
  }, children: okText })
466
547
  ] })
467
548
  ] });
468
- 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 });
469
554
  }
470
555
  function Progress({
471
556
  percent = 0,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  FloatingScrollbarProvider,
3
3
  Select
4
- } from "./chunk-LRGD2QDA.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,