gridsmith-ui 0.14.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/charts.d.ts +20 -1
- package/dist/charts.js +65 -29
- package/dist/charts.js.map +1 -1
- package/dist/chat.js +5 -5
- package/dist/{chunk-JSQPVRHQ.js → chunk-2U2X6E2X.js} +39 -16
- package/dist/chunk-2U2X6E2X.js.map +1 -0
- package/dist/{chunk-X4CNZFWC.js → chunk-4LDYR7QP.js} +7 -7
- package/dist/chunk-4LDYR7QP.js.map +1 -0
- package/dist/chunk-5XOJZQIP.js +427 -0
- package/dist/chunk-5XOJZQIP.js.map +1 -0
- package/dist/{chunk-PKLVP5ZB.js → chunk-7Q46JXSK.js} +5 -4
- package/dist/chunk-7Q46JXSK.js.map +1 -0
- package/dist/{chunk-IYD6ZDM2.js → chunk-EMCSARQO.js} +7 -6
- package/dist/chunk-EMCSARQO.js.map +1 -0
- package/dist/{chunk-CR2KF73R.js → chunk-OENJCGTJ.js} +3 -3
- package/dist/{chunk-CR2KF73R.js.map → chunk-OENJCGTJ.js.map} +1 -1
- package/dist/{chunk-U2JT37GJ.js → chunk-PVTGMCVR.js} +4 -4
- package/dist/{chunk-U2JT37GJ.js.map → chunk-PVTGMCVR.js.map} +1 -1
- package/dist/{chunk-QJBCZ7BR.js → chunk-XGSQOMEY.js} +4 -4
- package/dist/{chunk-QJBCZ7BR.js.map → chunk-XGSQOMEY.js.map} +1 -1
- package/dist/{chunk-M3AARGLI.js → chunk-Z63OSN64.js} +9 -8
- package/dist/chunk-Z63OSN64.js.map +1 -0
- package/dist/data-grid.js +4 -4
- package/dist/editor.js +32 -8
- package/dist/editor.js.map +1 -1
- package/dist/{feather-B65FI6CY.js → feather-2JFSFLXN.js} +3 -2
- package/dist/feather-2JFSFLXN.js.map +1 -0
- package/dist/{heroicons-DIR7PXCR.js → heroicons-4AQ4YBVG.js} +3 -2
- package/dist/heroicons-4AQ4YBVG.js.map +1 -0
- package/dist/icons.d.ts +1 -1
- package/dist/icons.js +1 -1
- package/dist/index.d.ts +75 -6
- package/dist/index.js +1371 -603
- package/dist/index.js.map +1 -1
- package/dist/kanban.d.ts +11 -1
- package/dist/kanban.js +227 -115
- package/dist/kanban.js.map +1 -1
- package/dist/{lucide-JH2R3TFV.js → lucide-RZC2FEMS.js} +3 -2
- package/dist/lucide-RZC2FEMS.js.map +1 -0
- package/dist/{phosphor-HCVUMVT5.js → phosphor-CEN25FLM.js} +3 -2
- package/dist/phosphor-CEN25FLM.js.map +1 -0
- package/dist/resizable.d.ts +11 -1
- package/dist/resizable.js +81 -23
- package/dist/resizable.js.map +1 -1
- package/dist/roots.css +11 -8
- package/dist/{tabler-HHIXSM73.js → tabler-YXXC7Y6B.js} +3 -2
- package/dist/tabler-YXXC7Y6B.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-IYD6ZDM2.js.map +0 -1
- package/dist/chunk-JSQPVRHQ.js.map +0 -1
- package/dist/chunk-M3AARGLI.js.map +0 -1
- package/dist/chunk-NHQCMOAN.js +0 -137
- package/dist/chunk-NHQCMOAN.js.map +0 -1
- package/dist/chunk-PKLVP5ZB.js.map +0 -1
- package/dist/chunk-X4CNZFWC.js.map +0 -1
- package/dist/feather-B65FI6CY.js.map +0 -1
- package/dist/heroicons-DIR7PXCR.js.map +0 -1
- package/dist/lucide-JH2R3TFV.js.map +0 -1
- package/dist/phosphor-HCVUMVT5.js.map +0 -1
- package/dist/tabler-HHIXSM73.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import { useAppShell, ControlSizeContext, Button,
|
|
2
|
-
export { AppShell, Button, ButtonSizeContext, ControlSizeContext, Drawer, Sheet, SkipLink, Spinner, useAppShell } from './chunk-
|
|
3
|
-
import { Skeleton } from './chunk-
|
|
4
|
-
export { Skeleton } from './chunk-
|
|
5
|
-
import { useOverlayLayer,
|
|
6
|
-
import { Link } from './chunk-
|
|
7
|
-
export { CodeBlock, Divider, Link } from './chunk-
|
|
8
|
-
import { Badge } from './chunk-
|
|
9
|
-
export { Badge } from './chunk-
|
|
10
|
-
import { inferColumnKinds, CardValue } from './chunk-
|
|
1
|
+
import { useAppShell, ControlSizeContext, Button, useDirtyGuard, OverlayCloseCtx, DiscardConfirm, Spinner, DrawerFooterCtx, useCompact, useElementWidth, Sheet, useCloseSettle, Drawer, useRememberedWidth, pxOf, ResizeEdge, defaultMaxWidth } from './chunk-2U2X6E2X.js';
|
|
2
|
+
export { AppShell, Button, ButtonSizeContext, ControlSizeContext, Drawer, Sheet, SkipLink, Spinner, useAppShell, useUnsavedChanges } from './chunk-2U2X6E2X.js';
|
|
3
|
+
import { Skeleton } from './chunk-Z63OSN64.js';
|
|
4
|
+
export { Skeleton } from './chunk-Z63OSN64.js';
|
|
5
|
+
import { FOCUSABLE, usePopupFocus, useOverlayLayer, useFocusTrap, useFocusBeforeOpen, rememberFocus, focusInitial, OVERLAY_CLOSE_ATTR, focusAfterRemoval, rovingTabStop, useGridKeyboard, useNonModalDialog, usePressMarks, useReturnFocus, useCloseOnFocusOut } from './chunk-5XOJZQIP.js';
|
|
6
|
+
import { Link } from './chunk-XGSQOMEY.js';
|
|
7
|
+
export { CodeBlock, Divider, Link } from './chunk-XGSQOMEY.js';
|
|
8
|
+
import { Badge } from './chunk-PVTGMCVR.js';
|
|
9
|
+
export { Badge } from './chunk-PVTGMCVR.js';
|
|
10
|
+
import { inferColumnKinds, CardValue } from './chunk-OENJCGTJ.js';
|
|
11
11
|
import { SplitPaneCtx, useShellPreferences, TableCardCtx, PREFERENCE_HOUSE_DEFAULTS, preferenceActionKey } from './chunk-TKVTZWBN.js';
|
|
12
12
|
export { PreferencesContext, preferenceActionKey, usePreferences } from './chunk-TKVTZWBN.js';
|
|
13
|
-
import { useBreakpoint } from './chunk-CRQ6KCRD.js';
|
|
13
|
+
import { useBreakpoint, readBreakpointPx } from './chunk-CRQ6KCRD.js';
|
|
14
14
|
export { BreakpointWidthProvider, useBreakpoint } from './chunk-CRQ6KCRD.js';
|
|
15
|
-
import { useTextOverflow, Tooltip, usePosition } from './chunk-
|
|
16
|
-
export { Tooltip, useTextOverflow } from './chunk-
|
|
17
|
-
import { mergeRefs, Slot } from './chunk-
|
|
15
|
+
import { useTextOverflow, Tooltip, usePosition } from './chunk-EMCSARQO.js';
|
|
16
|
+
export { Tooltip, useTextOverflow } from './chunk-EMCSARQO.js';
|
|
17
|
+
import { mergeRefs, Slot } from './chunk-7Q46JXSK.js';
|
|
18
18
|
import { useLatest } from './chunk-WH2FUFAC.js';
|
|
19
|
-
import { Icon } from './chunk-
|
|
20
|
-
import { cn, GLASS_SURFACE, ACTIVE_RING, GLASS_BACKDROP, GLASS_DROPDOWN, ERROR_ACTIVE_RING, ERROR_FOCUS_RING, FOCUS_RING, ERROR_HAS_FOCUS_RING, HAS_FOCUS_RING, ERROR_FOCUS_WITHIN_RING, FOCUS_WITHIN_RING
|
|
21
|
-
import { createContext, forwardRef, useState,
|
|
22
|
-
import { createPortal } from 'react-dom';
|
|
19
|
+
import { Icon } from './chunk-4LDYR7QP.js';
|
|
20
|
+
import { cn, GLASS_SURFACE, ACTIVE_RING, GLASS_BACKDROP, GLASS_DROPDOWN, lockBodyScroll, unlockBodyScroll, GLASS_OVERLAY, ERROR_ACTIVE_RING, ERROR_FOCUS_RING, FOCUS_RING, ERROR_HAS_FOCUS_RING, HAS_FOCUS_RING, ERROR_FOCUS_WITHIN_RING, FOCUS_WITHIN_RING } from './chunk-4KVFH5KC.js';
|
|
21
|
+
import { createContext, forwardRef, useState, useRef, useCallback, useLayoutEffect, useMemo, useContext, useId, memo, useEffect, Children, isValidElement, cloneElement, Fragment as Fragment$1, useSyncExternalStore } from 'react';
|
|
22
|
+
import { createPortal, flushSync } from 'react-dom';
|
|
23
23
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
24
24
|
|
|
25
25
|
function isDivider(entry) {
|
|
@@ -40,15 +40,14 @@ function DropdownMenu({ trigger, items, align = "end", className, container }) {
|
|
|
40
40
|
setPrevOpen(open);
|
|
41
41
|
if (!open) setFocusedIdx(-1);
|
|
42
42
|
}
|
|
43
|
-
const isTopLayer =
|
|
44
|
-
useCloseOnFocusOut(open, triggerRef, menuRef, () => setOpen(false), isTopLayer);
|
|
43
|
+
const { isTop: isTopLayer, returnFocus } = usePopupFocus(open, { trigger: triggerRef, panel: menuRef, close: () => setOpen(false), tabExits: "any" });
|
|
45
44
|
useEffect(() => {
|
|
46
45
|
if (!open) return;
|
|
47
46
|
const onKeyDown = (e) => {
|
|
48
|
-
if (e.key
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
if (e.key !== "Escape" || e.defaultPrevented || !isTopLayer()) return;
|
|
48
|
+
e.preventDefault();
|
|
49
|
+
returnFocus();
|
|
50
|
+
setOpen(false);
|
|
52
51
|
};
|
|
53
52
|
const onClick = (e) => {
|
|
54
53
|
const target = e.target;
|
|
@@ -61,11 +60,10 @@ function DropdownMenu({ trigger, items, align = "end", className, container }) {
|
|
|
61
60
|
document.removeEventListener("keydown", onKeyDown);
|
|
62
61
|
document.removeEventListener("mousedown", onClick);
|
|
63
62
|
};
|
|
64
|
-
}, [open, isTopLayer]);
|
|
63
|
+
}, [open, isTopLayer, returnFocus]);
|
|
65
64
|
useEffect(() => {
|
|
66
65
|
if (open && focusedIdx >= 0) {
|
|
67
|
-
|
|
68
|
-
buttons?.[focusedIdx]?.focus();
|
|
66
|
+
menuRef.current?.querySelector(`[data-index="${focusedIdx}"]`)?.focus();
|
|
69
67
|
}
|
|
70
68
|
}, [open, focusedIdx]);
|
|
71
69
|
function handleMenuKeyDown(e) {
|
|
@@ -108,6 +106,7 @@ function DropdownMenu({ trigger, items, align = "end", className, container }) {
|
|
|
108
106
|
className
|
|
109
107
|
),
|
|
110
108
|
style: { top: pos.top, left: pos.left },
|
|
109
|
+
onClick: (e) => e.stopPropagation(),
|
|
111
110
|
children: items.map((item, i) => {
|
|
112
111
|
if (isDivider(item)) {
|
|
113
112
|
return /* @__PURE__ */ jsx("div", { role: "separator", className: "my-ds-1 h-px bg-[var(--ds-border-default)]" }, i);
|
|
@@ -115,11 +114,13 @@ function DropdownMenu({ trigger, items, align = "end", className, container }) {
|
|
|
115
114
|
return /* @__PURE__ */ jsxs(
|
|
116
115
|
"button",
|
|
117
116
|
{
|
|
117
|
+
"data-index": i,
|
|
118
118
|
role: "menuitem",
|
|
119
119
|
disabled: item.disabled,
|
|
120
120
|
tabIndex: focusedIdx === i ? 0 : -1,
|
|
121
121
|
onClick: () => {
|
|
122
122
|
if (!item.disabled) {
|
|
123
|
+
returnFocus();
|
|
123
124
|
item.onClick();
|
|
124
125
|
setOpen(false);
|
|
125
126
|
}
|
|
@@ -465,13 +466,7 @@ function Dropdown({
|
|
|
465
466
|
useEffect(() => {
|
|
466
467
|
if (!open) return;
|
|
467
468
|
updatePos();
|
|
468
|
-
requestAnimationFrame(() => {
|
|
469
|
-
if (searchRef.current) {
|
|
470
|
-
searchRef.current.focus();
|
|
471
|
-
} else {
|
|
472
|
-
const els = Array.from(menuRef.current?.querySelectorAll('[role="option"]') ?? []);
|
|
473
|
-
(els.find((el) => el.getAttribute("aria-selected") === "true") ?? els[0])?.focus();
|
|
474
|
-
}
|
|
469
|
+
const raf = requestAnimationFrame(() => {
|
|
475
470
|
updatePos();
|
|
476
471
|
setPositioned(true);
|
|
477
472
|
});
|
|
@@ -479,10 +474,22 @@ function Dropdown({
|
|
|
479
474
|
window.addEventListener("scroll", onScroll, true);
|
|
480
475
|
window.addEventListener("resize", updatePos);
|
|
481
476
|
return () => {
|
|
477
|
+
cancelAnimationFrame(raf);
|
|
482
478
|
window.removeEventListener("scroll", onScroll, true);
|
|
483
479
|
window.removeEventListener("resize", updatePos);
|
|
484
480
|
};
|
|
485
481
|
}, [open, updatePos]);
|
|
482
|
+
const moved = useRef(false);
|
|
483
|
+
useLayoutEffect(() => {
|
|
484
|
+
if (!open || !positioned) return;
|
|
485
|
+
moved.current = false;
|
|
486
|
+
if (searchRef.current) {
|
|
487
|
+
searchRef.current.focus();
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
const els = Array.from(menuRef.current?.querySelectorAll('[role="option"]') ?? []);
|
|
491
|
+
(els.find((el) => el.getAttribute("aria-selected") === "true") ?? els[0])?.focus();
|
|
492
|
+
}, [open, positioned]);
|
|
486
493
|
useEffect(() => {
|
|
487
494
|
if (!open) return;
|
|
488
495
|
const handler = (e) => {
|
|
@@ -493,7 +500,13 @@ function Dropdown({
|
|
|
493
500
|
document.addEventListener("mousedown", handler);
|
|
494
501
|
return () => document.removeEventListener("mousedown", handler);
|
|
495
502
|
}, [open]);
|
|
496
|
-
const
|
|
503
|
+
const commitMoved = () => {
|
|
504
|
+
if (multiple || !moved.current) return;
|
|
505
|
+
const el = document.activeElement;
|
|
506
|
+
const id = el instanceof HTMLElement && menuRef.current?.contains(el) ? el.getAttribute("data-option-id") : null;
|
|
507
|
+
if (id) onChange(id);
|
|
508
|
+
};
|
|
509
|
+
const { isTop: isTopLayer, returnFocus } = usePopupFocus(open, { trigger: triggerRef, panel: menuRef, close: () => setOpen(false), tabExits: "any", onTabOut: commitMoved });
|
|
497
510
|
const typeahead = useRef({ buffer: "", at: 0 });
|
|
498
511
|
useEffect(() => {
|
|
499
512
|
if (!open) return;
|
|
@@ -502,6 +515,7 @@ function Dropdown({
|
|
|
502
515
|
const els = optionButtons();
|
|
503
516
|
if (els.length === 0) return;
|
|
504
517
|
els[(idx % els.length + els.length) % els.length].focus();
|
|
518
|
+
moved.current = true;
|
|
505
519
|
};
|
|
506
520
|
const onKey = (e) => {
|
|
507
521
|
const inMenu = menuRef.current?.contains(document.activeElement) || triggerRef.current === document.activeElement;
|
|
@@ -509,10 +523,10 @@ function Dropdown({
|
|
|
509
523
|
const els = optionButtons();
|
|
510
524
|
const current = els.findIndex((el) => el === document.activeElement);
|
|
511
525
|
if (e.key === "Escape") {
|
|
512
|
-
if (!isTopLayer()) return;
|
|
526
|
+
if (e.defaultPrevented || !isTopLayer()) return;
|
|
513
527
|
e.preventDefault();
|
|
528
|
+
returnFocus();
|
|
514
529
|
setOpen(false);
|
|
515
|
-
triggerRef.current?.focus();
|
|
516
530
|
return;
|
|
517
531
|
}
|
|
518
532
|
if (e.key === "ArrowDown") {
|
|
@@ -536,10 +550,6 @@ function Dropdown({
|
|
|
536
550
|
focusOption(els.length - 1);
|
|
537
551
|
return;
|
|
538
552
|
}
|
|
539
|
-
if (e.key === "Tab") {
|
|
540
|
-
setOpen(false);
|
|
541
|
-
return;
|
|
542
|
-
}
|
|
543
553
|
if (!searchable && e.key.length === 1 && !e.metaKey && !e.ctrlKey && !e.altKey) {
|
|
544
554
|
const now = Date.now();
|
|
545
555
|
typeahead.current.buffer = now - typeahead.current.at > 700 ? e.key : typeahead.current.buffer + e.key;
|
|
@@ -554,7 +564,7 @@ function Dropdown({
|
|
|
554
564
|
};
|
|
555
565
|
document.addEventListener("keydown", onKey);
|
|
556
566
|
return () => document.removeEventListener("keydown", onKey);
|
|
557
|
-
}, [open, searchable, isTopLayer]);
|
|
567
|
+
}, [open, searchable, isTopLayer, returnFocus]);
|
|
558
568
|
const filtered = searchable && search ? options.filter((o) => o.label.toLowerCase().includes(search.toLowerCase())) : options;
|
|
559
569
|
const groups = /* @__PURE__ */ new Map();
|
|
560
570
|
for (const opt of filtered) {
|
|
@@ -568,10 +578,21 @@ function Dropdown({
|
|
|
568
578
|
const arr = selectedValues.includes(id) ? selectedValues.filter((v) => v !== id) : [...selectedValues, id];
|
|
569
579
|
onChange(arr);
|
|
570
580
|
} else {
|
|
581
|
+
returnFocus();
|
|
571
582
|
onChange(id);
|
|
572
583
|
setOpen(false);
|
|
573
584
|
}
|
|
574
585
|
};
|
|
586
|
+
const chipsRef = useRef(null);
|
|
587
|
+
const pendingChipFocus = useRef(null);
|
|
588
|
+
useLayoutEffect(() => {
|
|
589
|
+
const pending = pendingChipFocus.current;
|
|
590
|
+
if (pending === null) return;
|
|
591
|
+
pendingChipFocus.current = null;
|
|
592
|
+
if (selectedValues.includes(pending.value)) return;
|
|
593
|
+
const chips = Array.from(chipsRef.current?.querySelectorAll("[data-chip-remove]") ?? []);
|
|
594
|
+
focusAfterRemoval(chips, pending.index, triggerRef.current);
|
|
595
|
+
});
|
|
575
596
|
const displayLabel = multiple ? selectedValues.length > 0 ? `${selectedValues.length} selected` : placeholder : options.find((o) => o.id === selectedValues[0])?.label ?? placeholder;
|
|
576
597
|
const { ref: overflowRef, isTruncated } = useTextOverflow({ lines: 1, content: displayLabel });
|
|
577
598
|
return /* @__PURE__ */ jsxs("div", { ref, className: cn("relative", className), children: [
|
|
@@ -620,6 +641,7 @@ function Dropdown({
|
|
|
620
641
|
"div",
|
|
621
642
|
{
|
|
622
643
|
ref: menuRef,
|
|
644
|
+
onClick: (e) => e.stopPropagation(),
|
|
623
645
|
className: cn(
|
|
624
646
|
"fixed z-[var(--ds-z-popover)]",
|
|
625
647
|
"bg-[var(--ds-bg-surface-elevated)]",
|
|
@@ -670,7 +692,7 @@ function Dropdown({
|
|
|
670
692
|
),
|
|
671
693
|
container ?? document.body
|
|
672
694
|
),
|
|
673
|
-
multiple && showChips && selectedValues.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-ds-1 mt-ds-1.5", children: selectedValues.map((v) => {
|
|
695
|
+
multiple && showChips && selectedValues.length > 0 && /* @__PURE__ */ jsx("div", { ref: chipsRef, className: "flex flex-wrap gap-ds-1 mt-ds-1.5", children: selectedValues.map((v, i) => {
|
|
674
696
|
const opt = options.find((o) => o.id === v);
|
|
675
697
|
return opt ? /* @__PURE__ */ jsxs(
|
|
676
698
|
"span",
|
|
@@ -681,7 +703,11 @@ function Dropdown({
|
|
|
681
703
|
/* @__PURE__ */ jsx(
|
|
682
704
|
"button",
|
|
683
705
|
{
|
|
684
|
-
|
|
706
|
+
"data-chip-remove": "",
|
|
707
|
+
onClick: () => {
|
|
708
|
+
pendingChipFocus.current = { index: i, value: v };
|
|
709
|
+
handleSelect(v);
|
|
710
|
+
},
|
|
685
711
|
className: "hover:text-[var(--ds-text-primary)] cursor-pointer",
|
|
686
712
|
"aria-label": `Remove ${opt.label}`,
|
|
687
713
|
children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 10 })
|
|
@@ -706,6 +732,7 @@ function OptionButton({
|
|
|
706
732
|
{
|
|
707
733
|
type: "button",
|
|
708
734
|
role: "option",
|
|
735
|
+
"data-option-id": opt.id,
|
|
709
736
|
"aria-selected": isSelected,
|
|
710
737
|
tabIndex: -1,
|
|
711
738
|
onClick: () => onSelect(opt.id),
|
|
@@ -750,6 +777,7 @@ function Combobox({ value, onChange, options, placeholder = "Search\u2026", disa
|
|
|
750
777
|
useOverlayLayer(open);
|
|
751
778
|
const [query, setQuery] = useState("");
|
|
752
779
|
const [highlightIdx, setHighlightIdx] = useState(0);
|
|
780
|
+
const [moved, setMoved] = useState(false);
|
|
753
781
|
const inputRef = useRef(null);
|
|
754
782
|
const triggerRef = useRef(null);
|
|
755
783
|
const [triggerWidth, setTriggerWidth] = useState(void 0);
|
|
@@ -766,6 +794,14 @@ function Combobox({ value, onChange, options, placeholder = "Search\u2026", disa
|
|
|
766
794
|
setPrevQuery(query);
|
|
767
795
|
setHighlightIdx(0);
|
|
768
796
|
}
|
|
797
|
+
const [prevOpen, setPrevOpen] = useState(open);
|
|
798
|
+
if (open !== prevOpen) {
|
|
799
|
+
setPrevOpen(open);
|
|
800
|
+
if (open && query === "") {
|
|
801
|
+
setHighlightIdx(Math.max(0, filtered.findIndex((o) => o.value === value)));
|
|
802
|
+
setMoved(false);
|
|
803
|
+
}
|
|
804
|
+
}
|
|
769
805
|
useEffect(() => {
|
|
770
806
|
if (!open) return;
|
|
771
807
|
const handler = (e) => {
|
|
@@ -781,7 +817,6 @@ function Combobox({ value, onChange, options, placeholder = "Search\u2026", disa
|
|
|
781
817
|
onChange(val);
|
|
782
818
|
setQuery("");
|
|
783
819
|
setOpen(false);
|
|
784
|
-
inputRef.current?.blur();
|
|
785
820
|
},
|
|
786
821
|
[onChange]
|
|
787
822
|
);
|
|
@@ -798,6 +833,7 @@ function Combobox({ value, onChange, options, placeholder = "Search\u2026", disa
|
|
|
798
833
|
return;
|
|
799
834
|
}
|
|
800
835
|
setHighlightIdx((prev) => Math.min(prev + 1, filtered.length - 1));
|
|
836
|
+
setMoved(true);
|
|
801
837
|
} else if (e.key === "ArrowUp") {
|
|
802
838
|
e.preventDefault();
|
|
803
839
|
if (!open) {
|
|
@@ -805,15 +841,23 @@ function Combobox({ value, onChange, options, placeholder = "Search\u2026", disa
|
|
|
805
841
|
return;
|
|
806
842
|
}
|
|
807
843
|
setHighlightIdx((prev) => Math.max(prev - 1, 0));
|
|
844
|
+
setMoved(true);
|
|
808
845
|
} else if (e.key === "Enter" && open && filtered[highlightIdx]) {
|
|
809
846
|
e.preventDefault();
|
|
810
847
|
handleSelect(filtered[highlightIdx].value);
|
|
811
|
-
} else if (e.key === "
|
|
848
|
+
} else if (e.key === "Tab" && open) {
|
|
849
|
+
if (moved && filtered[highlightIdx]) onChange(filtered[highlightIdx].value);
|
|
850
|
+
flushSync(() => {
|
|
851
|
+
setOpen(false);
|
|
852
|
+
setQuery("");
|
|
853
|
+
});
|
|
854
|
+
} else if (e.key === "Escape" && open) {
|
|
855
|
+
e.preventDefault();
|
|
812
856
|
setOpen(false);
|
|
813
857
|
setQuery("");
|
|
814
858
|
}
|
|
815
859
|
},
|
|
816
|
-
[open, filtered, highlightIdx, handleSelect, openList]
|
|
860
|
+
[open, moved, filtered, highlightIdx, handleSelect, openList, onChange]
|
|
817
861
|
);
|
|
818
862
|
const handleBlur = useCallback((e) => {
|
|
819
863
|
const next = e.relatedTarget;
|
|
@@ -858,11 +902,13 @@ function Combobox({ value, onChange, options, placeholder = "Search\u2026", disa
|
|
|
858
902
|
"aria-expanded": open,
|
|
859
903
|
"aria-controls": listboxId,
|
|
860
904
|
"aria-autocomplete": "list",
|
|
905
|
+
"aria-activedescendant": open && filtered[highlightIdx] ? `${listboxId}-opt-${highlightIdx}` : void 0,
|
|
861
906
|
value: open ? query : selectedLabel,
|
|
862
907
|
placeholder,
|
|
863
908
|
disabled,
|
|
864
909
|
onChange: (e) => {
|
|
865
910
|
setQuery(e.target.value);
|
|
911
|
+
setMoved(true);
|
|
866
912
|
if (!open) setOpen(true);
|
|
867
913
|
},
|
|
868
914
|
onFocus: (e) => e.currentTarget.select(),
|
|
@@ -917,8 +963,10 @@ function Combobox({ value, onChange, options, placeholder = "Search\u2026", disa
|
|
|
917
963
|
children: /* @__PURE__ */ jsx("div", { style: { padding: "var(--ds-space-1)" }, children: loading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-ds-4", children: /* @__PURE__ */ jsx(Spinner, { size: "sm", label: "Loading options" }) }) : filtered.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-ds-2 py-ds-3 text-sm text-[var(--ds-text-muted)] text-center", children: "No results" }) : filtered.map((opt, i) => /* @__PURE__ */ jsxs(
|
|
918
964
|
"button",
|
|
919
965
|
{
|
|
966
|
+
id: `${listboxId}-opt-${i}`,
|
|
920
967
|
role: "option",
|
|
921
|
-
|
|
968
|
+
tabIndex: -1,
|
|
969
|
+
"aria-selected": i === highlightIdx,
|
|
922
970
|
onMouseDown: (e) => e.preventDefault(),
|
|
923
971
|
onClick: () => handleSelect(opt.value),
|
|
924
972
|
onMouseEnter: () => setHighlightIdx(i),
|
|
@@ -940,10 +988,7 @@ function Combobox({ value, onChange, options, placeholder = "Search\u2026", disa
|
|
|
940
988
|
container ?? document.body
|
|
941
989
|
)
|
|
942
990
|
] });
|
|
943
|
-
|
|
944
|
-
return /* @__PURE__ */ jsx(Tooltip, { content: selectedLabel, children: triggerContent });
|
|
945
|
-
}
|
|
946
|
-
return triggerContent;
|
|
991
|
+
return /* @__PURE__ */ jsx(Tooltip, { content: selectedLabel, disabled: !labelTruncated || open, children: triggerContent });
|
|
947
992
|
}
|
|
948
993
|
var CHECKBOX_SIZES = {
|
|
949
994
|
sm: { box: "h-[16px] w-[16px]", glyph: 10, label: "text-xs" },
|
|
@@ -1125,6 +1170,42 @@ function RadioGroup({ value, onChange, options, orientation = "vertical", classN
|
|
|
1125
1170
|
] });
|
|
1126
1171
|
}
|
|
1127
1172
|
|
|
1173
|
+
// ../../showcase/src/lib/date-grid.ts
|
|
1174
|
+
function addDays(d, n) {
|
|
1175
|
+
return new Date(d.getFullYear(), d.getMonth(), d.getDate() + n);
|
|
1176
|
+
}
|
|
1177
|
+
function addMonthsClamped(d, n) {
|
|
1178
|
+
const first = new Date(d.getFullYear(), d.getMonth() + n, 1);
|
|
1179
|
+
const last = new Date(first.getFullYear(), first.getMonth() + 1, 0).getDate();
|
|
1180
|
+
return new Date(first.getFullYear(), first.getMonth(), Math.min(d.getDate(), last));
|
|
1181
|
+
}
|
|
1182
|
+
function dayKey(d) {
|
|
1183
|
+
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
1184
|
+
}
|
|
1185
|
+
function moveDay(from, key, shift, weekStartsOn = 0) {
|
|
1186
|
+
const intoWeek = (from.getDay() - weekStartsOn + 7) % 7;
|
|
1187
|
+
switch (key) {
|
|
1188
|
+
case "ArrowLeft":
|
|
1189
|
+
return addDays(from, -1);
|
|
1190
|
+
case "ArrowRight":
|
|
1191
|
+
return addDays(from, 1);
|
|
1192
|
+
case "ArrowUp":
|
|
1193
|
+
return addDays(from, -7);
|
|
1194
|
+
case "ArrowDown":
|
|
1195
|
+
return addDays(from, 7);
|
|
1196
|
+
case "Home":
|
|
1197
|
+
return addDays(from, -intoWeek);
|
|
1198
|
+
case "End":
|
|
1199
|
+
return addDays(from, 6 - intoWeek);
|
|
1200
|
+
case "PageUp":
|
|
1201
|
+
return addMonthsClamped(from, shift ? -12 : -1);
|
|
1202
|
+
case "PageDown":
|
|
1203
|
+
return addMonthsClamped(from, shift ? 12 : 1);
|
|
1204
|
+
default:
|
|
1205
|
+
return null;
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1128
1209
|
// ../../showcase/src/lib/segments.ts
|
|
1129
1210
|
function stepValue(spec, current, delta) {
|
|
1130
1211
|
if (current === null) return delta > 0 ? spec.min : spec.max;
|
|
@@ -1165,6 +1246,7 @@ var TEXT_SIZE2 = {
|
|
|
1165
1246
|
lg: "text-base"
|
|
1166
1247
|
};
|
|
1167
1248
|
var DAYS = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
1249
|
+
var DAY_NAMES = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
1168
1250
|
var MONTHS = [
|
|
1169
1251
|
"January",
|
|
1170
1252
|
"February",
|
|
@@ -1236,7 +1318,9 @@ function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, cl
|
|
|
1236
1318
|
const [hover, setHover] = useState(null);
|
|
1237
1319
|
const [viewDate, setViewDate] = useState(() => value ?? range?.start ?? range?.end ?? /* @__PURE__ */ new Date());
|
|
1238
1320
|
const triggerRef = useRef(null);
|
|
1321
|
+
const buttonRef = useRef(null);
|
|
1239
1322
|
const panelRef = useRef(null);
|
|
1323
|
+
const gridRef = useRef(null);
|
|
1240
1324
|
const generatedId = useId();
|
|
1241
1325
|
const inputId = id ?? generatedId;
|
|
1242
1326
|
const pos = usePosition(triggerRef, panelRef, open, { side: "bottom", align: "start", offset: 4, flip: true });
|
|
@@ -1245,18 +1329,48 @@ function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, cl
|
|
|
1245
1329
|
const daysInMonth = getDaysInMonth(year, month);
|
|
1246
1330
|
const firstDay = getFirstDayOfWeek(year, month);
|
|
1247
1331
|
const today = useMemo(() => /* @__PURE__ */ new Date(), []);
|
|
1248
|
-
const isTopLayer = useOverlayLayer(open);
|
|
1249
|
-
const prevMonth = () => setViewDate(new Date(year, month - 1, 1));
|
|
1250
|
-
const nextMonth = () => setViewDate(new Date(year, month + 1, 1));
|
|
1251
1332
|
const startOf = (d) => new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|
1252
1333
|
const isDisabledDay = (d) => !!min && d < startOf(min) || !!max && d > startOf(max);
|
|
1253
|
-
|
|
1334
|
+
const [focusDate, setFocusDate] = useState(() => startOf(value ?? range?.start ?? range?.end ?? /* @__PURE__ */ new Date()));
|
|
1335
|
+
const [prevOpen, setPrevOpen] = useState(open);
|
|
1336
|
+
if (open !== prevOpen) {
|
|
1337
|
+
setPrevOpen(open);
|
|
1338
|
+
if (open) {
|
|
1339
|
+
const start = startOf(value ?? range?.start ?? range?.end ?? today);
|
|
1340
|
+
setFocusDate(start);
|
|
1341
|
+
setViewDate(new Date(start.getFullYear(), start.getMonth(), 1));
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
const showDay = (d) => {
|
|
1345
|
+
setFocusDate(d);
|
|
1346
|
+
if (d.getFullYear() !== year || d.getMonth() !== month) setViewDate(new Date(d.getFullYear(), d.getMonth(), 1));
|
|
1347
|
+
};
|
|
1348
|
+
const grid = useGridKeyboard({
|
|
1349
|
+
container: gridRef,
|
|
1350
|
+
active: focusDate,
|
|
1351
|
+
setActive: showDay,
|
|
1352
|
+
keyOf: dayKey,
|
|
1353
|
+
move: (from, e) => moveDay(from, e.key, e.shiftKey, 0)
|
|
1354
|
+
});
|
|
1355
|
+
const prevMonth = () => {
|
|
1356
|
+
setViewDate(new Date(year, month - 1, 1));
|
|
1357
|
+
setFocusDate(addMonthsClamped(focusDate, -1));
|
|
1358
|
+
};
|
|
1359
|
+
const nextMonth = () => {
|
|
1360
|
+
setViewDate(new Date(year, month + 1, 1));
|
|
1361
|
+
setFocusDate(addMonthsClamped(focusDate, 1));
|
|
1362
|
+
};
|
|
1363
|
+
const { isTop: isTopLayer, returnFocus } = usePopupFocus(open, { trigger: buttonRef, panel: panelRef, close: () => setOpen(false), tabExits: "edges" });
|
|
1364
|
+
const focusActiveDay = useLatest(grid.focusActive);
|
|
1254
1365
|
useEffect(() => {
|
|
1255
|
-
if (open)
|
|
1256
|
-
|
|
1257
|
-
|
|
1366
|
+
if (!open) return;
|
|
1367
|
+
const raf = requestAnimationFrame(() => focusActiveDay.current());
|
|
1368
|
+
return () => cancelAnimationFrame(raf);
|
|
1369
|
+
}, [open, focusActiveDay]);
|
|
1370
|
+
const choose = (d) => {
|
|
1371
|
+
returnFocus();
|
|
1372
|
+
onChange(d);
|
|
1258
1373
|
setOpen(false);
|
|
1259
|
-
focusSegment(0);
|
|
1260
1374
|
};
|
|
1261
1375
|
const dayFirst = useMemo(() => localeDayFirst(), []);
|
|
1262
1376
|
const [segs, setSegs] = useState(() => value ? { day: value.getDate(), month: value.getMonth() + 1, year: value.getFullYear() } : { day: null, month: null, year: null });
|
|
@@ -1272,7 +1386,6 @@ function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, cl
|
|
|
1272
1386
|
const focusSegment = (i) => {
|
|
1273
1387
|
segmentRefs.current[Math.max(0, Math.min(specs.length - 1, i))]?.focus();
|
|
1274
1388
|
};
|
|
1275
|
-
const focusSegmentRef = useLatest(focusSegment);
|
|
1276
1389
|
useEffect(() => {
|
|
1277
1390
|
if (!open) return;
|
|
1278
1391
|
const handler = (e) => {
|
|
@@ -1281,10 +1394,10 @@ function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, cl
|
|
|
1281
1394
|
setOpen(false);
|
|
1282
1395
|
};
|
|
1283
1396
|
const keyHandler = (e) => {
|
|
1284
|
-
if (e.key
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1397
|
+
if (e.key !== "Escape" || e.defaultPrevented || !isTopLayer()) return;
|
|
1398
|
+
e.preventDefault();
|
|
1399
|
+
returnFocus();
|
|
1400
|
+
setOpen(false);
|
|
1288
1401
|
};
|
|
1289
1402
|
document.addEventListener("mousedown", handler);
|
|
1290
1403
|
document.addEventListener("keydown", keyHandler);
|
|
@@ -1292,7 +1405,7 @@ function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, cl
|
|
|
1292
1405
|
document.removeEventListener("mousedown", handler);
|
|
1293
1406
|
document.removeEventListener("keydown", keyHandler);
|
|
1294
1407
|
};
|
|
1295
|
-
}, [open, isTopLayer,
|
|
1408
|
+
}, [open, isTopLayer, returnFocus]);
|
|
1296
1409
|
const [typedInvalid, setTypedInvalid] = useState(false);
|
|
1297
1410
|
const commitIfComplete = (next) => {
|
|
1298
1411
|
if (next.day === null || next.month === null || next.year === null) {
|
|
@@ -1378,8 +1491,7 @@ function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, cl
|
|
|
1378
1491
|
const selectDay = (day) => {
|
|
1379
1492
|
const d = new Date(year, month, day);
|
|
1380
1493
|
if (isDisabledDay(d)) return;
|
|
1381
|
-
|
|
1382
|
-
closeAndRefocus();
|
|
1494
|
+
choose(d);
|
|
1383
1495
|
};
|
|
1384
1496
|
const rangeA = range?.start ?? null;
|
|
1385
1497
|
const rangeB = range?.end ?? null;
|
|
@@ -1390,6 +1502,9 @@ function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, cl
|
|
|
1390
1502
|
const cells = [];
|
|
1391
1503
|
for (let i = 0; i < firstDay; i++) cells.push(null);
|
|
1392
1504
|
for (let d = 1; d <= daysInMonth; d++) cells.push(d);
|
|
1505
|
+
while (cells.length % 7) cells.push(null);
|
|
1506
|
+
const weeks = [];
|
|
1507
|
+
for (let i = 0; i < cells.length; i += 7) weeks.push(cells.slice(i, i + 7));
|
|
1393
1508
|
return /* @__PURE__ */ jsxs("div", { ref, className: cn(className), children: [
|
|
1394
1509
|
label && /* @__PURE__ */ jsx("label", { htmlFor: inputId, className: "block text-sm font-medium text-[var(--ds-text-primary)] mb-ds-1", children: label }),
|
|
1395
1510
|
/* @__PURE__ */ jsxs(
|
|
@@ -1455,6 +1570,7 @@ function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, cl
|
|
|
1455
1570
|
/* @__PURE__ */ jsx(
|
|
1456
1571
|
"button",
|
|
1457
1572
|
{
|
|
1573
|
+
ref: buttonRef,
|
|
1458
1574
|
type: "button",
|
|
1459
1575
|
"aria-label": "Choose a date",
|
|
1460
1576
|
"aria-haspopup": "dialog",
|
|
@@ -1501,38 +1617,56 @@ function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, cl
|
|
|
1501
1617
|
]
|
|
1502
1618
|
}
|
|
1503
1619
|
),
|
|
1504
|
-
/* @__PURE__ */ jsxs(
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
"
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
"
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1620
|
+
/* @__PURE__ */ jsxs(
|
|
1621
|
+
"div",
|
|
1622
|
+
{
|
|
1623
|
+
ref: gridRef,
|
|
1624
|
+
role: "grid",
|
|
1625
|
+
"aria-label": `${MONTHS[month]} ${year}`,
|
|
1626
|
+
onKeyDown: grid.onKeyDown,
|
|
1627
|
+
className: "flex flex-col gap-ds-0.5 tabular-nums",
|
|
1628
|
+
style: { padding: "var(--ds-space-2) var(--ds-space-3)" },
|
|
1629
|
+
children: [
|
|
1630
|
+
/* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7 gap-ds-0.5 mb-ds-0.5", children: DAYS.map((d, i) => /* @__PURE__ */ jsx("div", { role: "columnheader", "aria-label": DAY_NAMES[i], className: "text-center text-2xs font-medium text-[var(--ds-text-muted)] py-ds-1", children: d }, d)) }),
|
|
1631
|
+
weeks.map((week, w) => /* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7 gap-ds-0.5", onMouseLeave: () => setHover(null), children: week.map((day, i) => {
|
|
1632
|
+
if (day === null) return /* @__PURE__ */ jsx("div", { role: "gridcell" }, `empty-${i}`);
|
|
1633
|
+
const dateObj = new Date(year, month, day);
|
|
1634
|
+
const isSelected = !!value && isSameDay(dateObj, value);
|
|
1635
|
+
const isOtherEnd = !!otherEnd && isSameDay(dateObj, otherEnd);
|
|
1636
|
+
const isToday2 = isSameDay(dateObj, today);
|
|
1637
|
+
const between = inBand(dateObj);
|
|
1638
|
+
const dis = isDisabledDay(dateObj);
|
|
1639
|
+
return /* @__PURE__ */ jsx(
|
|
1640
|
+
"button",
|
|
1641
|
+
{
|
|
1642
|
+
type: "button",
|
|
1643
|
+
role: "gridcell",
|
|
1644
|
+
"data-grid-key": dayKey(dateObj),
|
|
1645
|
+
tabIndex: grid.tabIndexOf(dateObj),
|
|
1646
|
+
"aria-disabled": dis || void 0,
|
|
1647
|
+
onClick: () => selectDay(day),
|
|
1648
|
+
onFocus: () => {
|
|
1649
|
+
if (!isSameDay(dateObj, focusDate)) setFocusDate(dateObj);
|
|
1650
|
+
},
|
|
1651
|
+
onMouseEnter: () => setHover(dateObj),
|
|
1652
|
+
"aria-selected": isSelected,
|
|
1653
|
+
"aria-current": isToday2 ? "date" : void 0,
|
|
1654
|
+
"aria-label": formatDate(dateObj),
|
|
1655
|
+
className: cn(
|
|
1656
|
+
"w-full aspect-square flex items-center justify-center text-xs",
|
|
1657
|
+
"transition-colors cursor-pointer",
|
|
1658
|
+
"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
1659
|
+
isSelected ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)] font-bold rounded-[var(--ds-radius-sm)]" : isOtherEnd ? "bg-[var(--ds-accent-muted)] text-[var(--ds-accent-subtle-text)] font-semibold rounded-[var(--ds-radius-sm)]" : between ? "bg-[var(--ds-accent-subtle)] text-[var(--ds-accent-subtle-text)] rounded-none" : isToday2 ? "border-[length:var(--ds-border-width)] border-[var(--ds-accent-primary)] text-[var(--ds-accent-primary)] font-medium rounded-[var(--ds-radius-sm)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-emphasis)] rounded-[var(--ds-radius-sm)]",
|
|
1660
|
+
dis && "opacity-disabled cursor-not-allowed hover:bg-transparent"
|
|
1661
|
+
),
|
|
1662
|
+
children: day
|
|
1663
|
+
},
|
|
1664
|
+
day
|
|
1665
|
+
);
|
|
1666
|
+
}) }, w))
|
|
1667
|
+
]
|
|
1668
|
+
}
|
|
1669
|
+
),
|
|
1536
1670
|
/* @__PURE__ */ jsxs(
|
|
1537
1671
|
"div",
|
|
1538
1672
|
{
|
|
@@ -1547,8 +1681,7 @@ function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, cl
|
|
|
1547
1681
|
onClick: () => {
|
|
1548
1682
|
const now = /* @__PURE__ */ new Date();
|
|
1549
1683
|
setViewDate(now);
|
|
1550
|
-
|
|
1551
|
-
closeAndRefocus();
|
|
1684
|
+
choose(now);
|
|
1552
1685
|
},
|
|
1553
1686
|
children: "Today"
|
|
1554
1687
|
}
|
|
@@ -1558,10 +1691,7 @@ function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, cl
|
|
|
1558
1691
|
{
|
|
1559
1692
|
variant: "ghost",
|
|
1560
1693
|
size: "sm",
|
|
1561
|
-
onClick: () =>
|
|
1562
|
-
onChange(null);
|
|
1563
|
-
closeAndRefocus();
|
|
1564
|
-
},
|
|
1694
|
+
onClick: () => choose(null),
|
|
1565
1695
|
children: "Clear"
|
|
1566
1696
|
}
|
|
1567
1697
|
)
|
|
@@ -1645,7 +1775,7 @@ function endOfWeek(d, weekStartsOn = 0) {
|
|
|
1645
1775
|
end.setHours(23, 59, 59, 999);
|
|
1646
1776
|
return end;
|
|
1647
1777
|
}
|
|
1648
|
-
function
|
|
1778
|
+
function addDays2(d, n) {
|
|
1649
1779
|
const result = new Date(d);
|
|
1650
1780
|
result.setDate(result.getDate() + n);
|
|
1651
1781
|
return result;
|
|
@@ -1674,7 +1804,7 @@ function getWeekDays(date, weekStartsOn = 0) {
|
|
|
1674
1804
|
const start = startOfWeek(date, weekStartsOn);
|
|
1675
1805
|
const days = [];
|
|
1676
1806
|
for (let i = 0; i < 7; i++) {
|
|
1677
|
-
days.push(
|
|
1807
|
+
days.push(addDays2(start, i));
|
|
1678
1808
|
}
|
|
1679
1809
|
return days;
|
|
1680
1810
|
}
|
|
@@ -1764,11 +1894,11 @@ var DEFAULT_DATE_RANGE_PRESETS = [
|
|
|
1764
1894
|
} },
|
|
1765
1895
|
{ label: "Last 7 days", range: () => {
|
|
1766
1896
|
const t = startOfDay(/* @__PURE__ */ new Date());
|
|
1767
|
-
return { start:
|
|
1897
|
+
return { start: addDays2(t, -6), end: t };
|
|
1768
1898
|
} },
|
|
1769
1899
|
{ label: "Last 30 days", range: () => {
|
|
1770
1900
|
const t = startOfDay(/* @__PURE__ */ new Date());
|
|
1771
|
-
return { start:
|
|
1901
|
+
return { start: addDays2(t, -29), end: t };
|
|
1772
1902
|
} },
|
|
1773
1903
|
{ label: "This month", range: () => {
|
|
1774
1904
|
const t = /* @__PURE__ */ new Date();
|
|
@@ -1808,11 +1938,42 @@ function DateRangePicker({
|
|
|
1808
1938
|
const pos = usePosition(triggerRef, panelRef, open, { side: "bottom", align: "start", offset: 4, flip: true });
|
|
1809
1939
|
const today = useMemo(() => startOfDay(/* @__PURE__ */ new Date()), []);
|
|
1810
1940
|
const dayNames = getOrderedDayNamesShort(weekStartsOn);
|
|
1941
|
+
const gridRef = useRef(null);
|
|
1942
|
+
const [focusDate, setFocusDate] = useState(() => startOfDay(value.start ?? /* @__PURE__ */ new Date()));
|
|
1943
|
+
const [prevOpen, setPrevOpen] = useState(open);
|
|
1944
|
+
if (open !== prevOpen) {
|
|
1945
|
+
setPrevOpen(open);
|
|
1946
|
+
if (open) {
|
|
1947
|
+
const start = startOfDay(value.start ?? today);
|
|
1948
|
+
setFocusDate(start);
|
|
1949
|
+
setViewDate(new Date(start.getFullYear(), start.getMonth(), 1));
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
const showDay = (d) => {
|
|
1953
|
+
setFocusDate(d);
|
|
1954
|
+
const monthIndex = (x) => x.getFullYear() * 12 + x.getMonth();
|
|
1955
|
+
const offset = monthIndex(d) - monthIndex(viewDate);
|
|
1956
|
+
if (offset < 0) setViewDate(new Date(d.getFullYear(), d.getMonth(), 1));
|
|
1957
|
+
else if (offset > 1) setViewDate(new Date(d.getFullYear(), d.getMonth() - 1, 1));
|
|
1958
|
+
};
|
|
1959
|
+
const grid = useGridKeyboard({
|
|
1960
|
+
container: gridRef,
|
|
1961
|
+
active: focusDate,
|
|
1962
|
+
setActive: showDay,
|
|
1963
|
+
keyOf: dayKey,
|
|
1964
|
+
move: (from, e) => moveDay(from, e.key, e.shiftKey, weekStartsOn)
|
|
1965
|
+
});
|
|
1966
|
+
const pageMonths = (n) => {
|
|
1967
|
+
setViewDate(addMonths(viewDate, n));
|
|
1968
|
+
setFocusDate(addMonthsClamped(focusDate, n));
|
|
1969
|
+
};
|
|
1970
|
+
const { isTop: isTopLayer, returnFocus } = usePopupFocus(open, { trigger: triggerRef, panel: panelRef, close: () => setOpen(false), tabExits: "edges" });
|
|
1971
|
+
const focusActiveDay = useLatest(grid.focusActive);
|
|
1811
1972
|
useEffect(() => {
|
|
1812
|
-
if (open)
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1973
|
+
if (!open) return;
|
|
1974
|
+
const raf = requestAnimationFrame(() => focusActiveDay.current());
|
|
1975
|
+
return () => cancelAnimationFrame(raf);
|
|
1976
|
+
}, [open, focusActiveDay]);
|
|
1816
1977
|
useEffect(() => {
|
|
1817
1978
|
if (!open) return;
|
|
1818
1979
|
const onMouse = (e) => {
|
|
@@ -1821,10 +1982,10 @@ function DateRangePicker({
|
|
|
1821
1982
|
setOpen(false);
|
|
1822
1983
|
};
|
|
1823
1984
|
const onKey = (e) => {
|
|
1824
|
-
if (e.key
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1985
|
+
if (e.key !== "Escape" || e.defaultPrevented || !isTopLayer()) return;
|
|
1986
|
+
e.preventDefault();
|
|
1987
|
+
returnFocus();
|
|
1988
|
+
setOpen(false);
|
|
1828
1989
|
};
|
|
1829
1990
|
document.addEventListener("mousedown", onMouse);
|
|
1830
1991
|
document.addEventListener("keydown", onKey);
|
|
@@ -1832,7 +1993,7 @@ function DateRangePicker({
|
|
|
1832
1993
|
document.removeEventListener("mousedown", onMouse);
|
|
1833
1994
|
document.removeEventListener("keydown", onKey);
|
|
1834
1995
|
};
|
|
1835
|
-
}, [open, isTopLayer]);
|
|
1996
|
+
}, [open, isTopLayer, returnFocus]);
|
|
1836
1997
|
const isDisabledDay = (d) => min && d < startOfDay(min) || max && d > startOfDay(max) || false;
|
|
1837
1998
|
const selectDay = (d) => {
|
|
1838
1999
|
if (isDisabledDay(d)) return;
|
|
@@ -1844,9 +2005,9 @@ function DateRangePicker({
|
|
|
1844
2005
|
onChange({ start: d, end: null });
|
|
1845
2006
|
return;
|
|
1846
2007
|
}
|
|
2008
|
+
returnFocus();
|
|
1847
2009
|
onChange({ start: value.start, end: d });
|
|
1848
2010
|
setOpen(false);
|
|
1849
|
-
triggerRef.current?.focus();
|
|
1850
2011
|
};
|
|
1851
2012
|
const previewEnd = value.start && !value.end && hover && hover >= value.start ? hover : null;
|
|
1852
2013
|
const rangeStart = value.start;
|
|
@@ -1908,14 +2069,14 @@ function DateRangePicker({
|
|
|
1908
2069
|
children: [
|
|
1909
2070
|
presets.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-ds-0.5 p-ds-2 border-r-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] min-w-[140px]", children: presets.map((p) => /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", className: "justify-start", onClick: () => {
|
|
1910
2071
|
const r = p.range();
|
|
2072
|
+
returnFocus();
|
|
1911
2073
|
onChange(r);
|
|
1912
2074
|
setViewDate(r.start ?? /* @__PURE__ */ new Date());
|
|
1913
2075
|
setOpen(false);
|
|
1914
|
-
triggerRef.current?.focus();
|
|
1915
2076
|
}, children: p.label }, p.label)) }),
|
|
1916
2077
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
|
|
1917
2078
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between bg-[var(--ds-bg-muted)] rounded-tr-[var(--ds-radius-md)] px-ds-3 py-ds-2", children: [
|
|
1918
|
-
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", onClick: () =>
|
|
2079
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", onClick: () => pageMonths(-1), "aria-label": "Previous month", children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14, className: "rotate-180" }) }),
|
|
1919
2080
|
/* @__PURE__ */ jsxs("span", { className: "text-sm font-medium text-[var(--ds-text-primary)]", children: [
|
|
1920
2081
|
MONTHS2[months[0].getMonth()],
|
|
1921
2082
|
" ",
|
|
@@ -1925,12 +2086,12 @@ function DateRangePicker({
|
|
|
1925
2086
|
" ",
|
|
1926
2087
|
months[1].getFullYear()
|
|
1927
2088
|
] }),
|
|
1928
|
-
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", onClick: () =>
|
|
2089
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", onClick: () => pageMonths(1), "aria-label": "Next month", children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14 }) })
|
|
1929
2090
|
] }),
|
|
1930
|
-
/* @__PURE__ */ jsx("div", { className: "flex gap-ds-4 px-ds-3 py-ds-2", onMouseLeave: () => setHover(null), children: months.map((m) => /* @__PURE__ */ jsxs("div", { className: "w-[224px]", children: [
|
|
1931
|
-
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-ds-0.5 mb-ds-
|
|
1932
|
-
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-ds-0.5", children:
|
|
1933
|
-
if (!isSameMonth(d, m)) return /* @__PURE__ */ jsx("div", {}, d.toISOString());
|
|
2091
|
+
/* @__PURE__ */ jsx("div", { ref: gridRef, onKeyDown: grid.onKeyDown, className: "flex gap-ds-4 px-ds-3 py-ds-2", onMouseLeave: () => setHover(null), children: months.map((m) => /* @__PURE__ */ jsxs("div", { role: "grid", "aria-label": `${MONTHS2[m.getMonth()]} ${m.getFullYear()}`, className: "w-[224px] flex flex-col gap-ds-0.5", children: [
|
|
2092
|
+
/* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7 gap-ds-0.5 mb-ds-0.5", children: dayNames.map((d) => /* @__PURE__ */ jsx("div", { role: "columnheader", className: "text-center text-2xs font-medium text-[var(--ds-text-muted)] py-ds-1", children: d }, d)) }),
|
|
2093
|
+
getMonthGrid(m.getFullYear(), m.getMonth(), weekStartsOn).map((week, w) => /* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7 gap-ds-0.5", children: week.map((d) => {
|
|
2094
|
+
if (!isSameMonth(d, m)) return /* @__PURE__ */ jsx("div", { role: "gridcell" }, d.toISOString());
|
|
1934
2095
|
const isStart = !!rangeStart && isSameDay2(d, rangeStart);
|
|
1935
2096
|
const isEnd = !!rangeEnd && isSameDay2(d, rangeEnd);
|
|
1936
2097
|
const between = inRange(d);
|
|
@@ -1939,10 +2100,17 @@ function DateRangePicker({
|
|
|
1939
2100
|
"button",
|
|
1940
2101
|
{
|
|
1941
2102
|
type: "button",
|
|
1942
|
-
|
|
2103
|
+
role: "gridcell",
|
|
2104
|
+
"data-grid-key": dayKey(d),
|
|
2105
|
+
tabIndex: grid.tabIndexOf(d),
|
|
2106
|
+
"aria-disabled": dis || void 0,
|
|
1943
2107
|
onClick: () => selectDay(d),
|
|
2108
|
+
onFocus: () => {
|
|
2109
|
+
if (!isSameDay2(d, focusDate)) setFocusDate(d);
|
|
2110
|
+
},
|
|
1944
2111
|
onMouseEnter: () => setHover(d),
|
|
1945
|
-
"aria-
|
|
2112
|
+
"aria-selected": isStart || isEnd || between,
|
|
2113
|
+
"aria-current": isSameDay2(d, today) ? "date" : void 0,
|
|
1946
2114
|
"aria-label": fmt(d),
|
|
1947
2115
|
className: cn(
|
|
1948
2116
|
"w-full aspect-square flex items-center justify-center text-xs",
|
|
@@ -1955,7 +2123,7 @@ function DateRangePicker({
|
|
|
1955
2123
|
},
|
|
1956
2124
|
d.toISOString()
|
|
1957
2125
|
);
|
|
1958
|
-
}) })
|
|
2126
|
+
}) }, w))
|
|
1959
2127
|
] }, `${m.getFullYear()}-${m.getMonth()}`)) }),
|
|
1960
2128
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center bg-[var(--ds-bg-muted)] border-t-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] rounded-br-[var(--ds-radius-md)] px-ds-3 py-ds-2", children: [
|
|
1961
2129
|
/* @__PURE__ */ jsx("span", { className: "text-xs text-[var(--ds-text-muted)]", children: value.start && !value.end ? "Now pick an end date" : summary ?? "Pick a start date" }),
|
|
@@ -1972,6 +2140,96 @@ function DateRangePicker({
|
|
|
1972
2140
|
)
|
|
1973
2141
|
] });
|
|
1974
2142
|
}
|
|
2143
|
+
|
|
2144
|
+
// ../../showcase/src/lib/file-accept.ts
|
|
2145
|
+
var MIME_NAMES = {
|
|
2146
|
+
"text/plain": "TXT",
|
|
2147
|
+
"audio/mpeg": "MP3",
|
|
2148
|
+
"video/quicktime": "MOV",
|
|
2149
|
+
"application/msword": "DOC",
|
|
2150
|
+
"application/vnd.ms-excel": "XLS",
|
|
2151
|
+
"application/vnd.ms-powerpoint": "PPT",
|
|
2152
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "DOCX",
|
|
2153
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "XLSX",
|
|
2154
|
+
"application/vnd.openxmlformats-officedocument.presentationml.presentation": "PPTX"
|
|
2155
|
+
};
|
|
2156
|
+
var EXT_NAMES = { jpeg: "JPG", tif: "TIFF", htm: "HTML", yml: "YAML" };
|
|
2157
|
+
var FAMILIES = {
|
|
2158
|
+
image: { one: "an image", many: "images" },
|
|
2159
|
+
video: { one: "a video", many: "videos" },
|
|
2160
|
+
audio: { one: "an audio file", many: "audio files" },
|
|
2161
|
+
text: { one: "a text file", many: "text files" }
|
|
2162
|
+
};
|
|
2163
|
+
var READ_AS_WORD = /* @__PURE__ */ new Set(["FLAC", "HEIC", "HEIF", "LOG", "MIDI", "MOV", "RAR", "RAW"]);
|
|
2164
|
+
var extName = (ext) => EXT_NAMES[ext] ?? ext.toUpperCase();
|
|
2165
|
+
function mimeName(mime) {
|
|
2166
|
+
if (MIME_NAMES[mime]) return MIME_NAMES[mime];
|
|
2167
|
+
const subtype = mime.slice(mime.indexOf("/") + 1).replace(/\+.*$/, "").replace(/^(?:x-|vnd\.)/, "");
|
|
2168
|
+
return extName(subtype.slice(subtype.lastIndexOf(".") + 1));
|
|
2169
|
+
}
|
|
2170
|
+
function parseAccept(accept) {
|
|
2171
|
+
return (accept ?? "").split(",").map((t) => t.trim().toLowerCase()).filter(Boolean).map((t) => {
|
|
2172
|
+
if (t === "*" || t === "*/*") return { kind: "any" };
|
|
2173
|
+
if (t.startsWith(".")) return { kind: "format", name: extName(t.slice(1)), suffix: t };
|
|
2174
|
+
if (t.endsWith("/*")) return { kind: "family", family: t.slice(0, -2) };
|
|
2175
|
+
return { kind: "format", name: mimeName(t), mime: t };
|
|
2176
|
+
});
|
|
2177
|
+
}
|
|
2178
|
+
function fileFormat(file) {
|
|
2179
|
+
const dot = file.name.lastIndexOf(".");
|
|
2180
|
+
return dot > 0 ? extName(file.name.slice(dot + 1).toLowerCase()) : null;
|
|
2181
|
+
}
|
|
2182
|
+
function matches(file, tokens) {
|
|
2183
|
+
if (tokens.length === 0 || tokens.some((t) => t.kind === "any")) return true;
|
|
2184
|
+
const name = file.name.toLowerCase();
|
|
2185
|
+
const format = fileFormat(file);
|
|
2186
|
+
const type = file.type.toLowerCase();
|
|
2187
|
+
return tokens.some((t) => {
|
|
2188
|
+
if (t.kind === "family") return type === "" || type.startsWith(`${t.family}/`);
|
|
2189
|
+
if (t.kind !== "format") return false;
|
|
2190
|
+
return t.name === format || t.suffix != null && name.endsWith(t.suffix) || t.mime != null && t.mime === type;
|
|
2191
|
+
});
|
|
2192
|
+
}
|
|
2193
|
+
var joinOr = (items) => items.length < 2 ? items.join("") : `${items.slice(0, -1).join(", ")} or ${items[items.length - 1]}`;
|
|
2194
|
+
var article = (name) => {
|
|
2195
|
+
const asWord = name.replace(/[^A-Z]/g, "").length >= 5 || READ_AS_WORD.has(name);
|
|
2196
|
+
return (asWord ? /^[AEIOU]/ : /^[AEFHILMNORSX]/).test(name) ? "an" : "a";
|
|
2197
|
+
};
|
|
2198
|
+
function typeWords(accept) {
|
|
2199
|
+
const tokens = parseAccept(accept);
|
|
2200
|
+
if (tokens.length === 0 || tokens.some((t) => t.kind === "any" || t.kind === "family" && !FAMILIES[t.family])) return null;
|
|
2201
|
+
const families = [...new Set(tokens.flatMap((t) => t.kind === "family" ? [t.family] : []))].map((f) => FAMILIES[f]);
|
|
2202
|
+
const formats = [...new Set(tokens.flatMap((t) => t.kind === "format" ? [t.name] : []))];
|
|
2203
|
+
const many = `${joinOr([...families.map((f) => f.many), ...formats])}${formats.length ? " files" : ""}`;
|
|
2204
|
+
const one = families.length === 0 ? `${article(formats[0])} ${joinOr(formats)}` : joinOr([...families.map((f) => f.one), ...formats.map((f) => `${article(f)} ${f}`)]);
|
|
2205
|
+
return { one, many };
|
|
2206
|
+
}
|
|
2207
|
+
function sizeWords(bytes) {
|
|
2208
|
+
const units = [["GB", 1024 ** 3], ["MB", 1024 ** 2], ["KB", 1024]];
|
|
2209
|
+
for (const [unit, size] of units) if (bytes >= size) return `${Math.round(bytes / size * 10) / 10} ${unit}`;
|
|
2210
|
+
return `${bytes} bytes`;
|
|
2211
|
+
}
|
|
2212
|
+
var capitalise = (s) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
2213
|
+
function fileConstraints(accept, maxSize, multiple) {
|
|
2214
|
+
const types = typeWords(accept)?.many;
|
|
2215
|
+
const size = maxSize != null ? `up to ${sizeWords(maxSize)}${multiple ? " each" : ""}` : null;
|
|
2216
|
+
const line = [types, size].filter(Boolean).join(" ");
|
|
2217
|
+
return line ? capitalise(line) : null;
|
|
2218
|
+
}
|
|
2219
|
+
function checkFiles(files, { accept, maxSize, multiple }) {
|
|
2220
|
+
if (!multiple && files.length > 1) return { accepted: [], message: "You can only select one file" };
|
|
2221
|
+
const tokens = parseAccept(accept);
|
|
2222
|
+
const types = typeWords(accept);
|
|
2223
|
+
const accepted = [];
|
|
2224
|
+
const reasons = [];
|
|
2225
|
+
for (const file of files) {
|
|
2226
|
+
const subject = multiple ? file.name : "The selected file";
|
|
2227
|
+
if (!matches(file, tokens)) reasons.push(types ? `${subject} must be ${types.one}` : `${subject} is not a file type that can be added here`);
|
|
2228
|
+
else if (maxSize != null && file.size > maxSize) reasons.push(`${subject} must be smaller than ${sizeWords(maxSize)}`);
|
|
2229
|
+
else accepted.push(file);
|
|
2230
|
+
}
|
|
2231
|
+
return { accepted, message: reasons.length ? reasons.join("; ") : null };
|
|
2232
|
+
}
|
|
1975
2233
|
var variantFills = {
|
|
1976
2234
|
default: "bg-[var(--ds-accent-primary)] [background-image:var(--ds-gradient)]",
|
|
1977
2235
|
success: "bg-[var(--ds-status-success)]",
|
|
@@ -2019,6 +2277,66 @@ function Progress({ value, max = 100, variant = "default", size = "md", indeterm
|
|
|
2019
2277
|
] })
|
|
2020
2278
|
] });
|
|
2021
2279
|
}
|
|
2280
|
+
function InlineFieldError({ message, id, className }) {
|
|
2281
|
+
return /* @__PURE__ */ jsxs(
|
|
2282
|
+
"p",
|
|
2283
|
+
{
|
|
2284
|
+
id,
|
|
2285
|
+
role: "alert",
|
|
2286
|
+
className: cn(
|
|
2287
|
+
"flex items-center gap-ds-1.5 text-xs text-[var(--ds-status-error)]",
|
|
2288
|
+
"mt-ds-1.5",
|
|
2289
|
+
className
|
|
2290
|
+
),
|
|
2291
|
+
children: [
|
|
2292
|
+
/* @__PURE__ */ jsx(Icon, { name: "error", size: 14, className: "shrink-0" }),
|
|
2293
|
+
/* @__PURE__ */ jsx("span", { children: message })
|
|
2294
|
+
]
|
|
2295
|
+
}
|
|
2296
|
+
);
|
|
2297
|
+
}
|
|
2298
|
+
var FieldContext = createContext(null);
|
|
2299
|
+
function useField() {
|
|
2300
|
+
return useContext(FieldContext);
|
|
2301
|
+
}
|
|
2302
|
+
function Field({ label, children, hint, error, required, labelAction, id: idProp, className }) {
|
|
2303
|
+
const generated = useId();
|
|
2304
|
+
const id = idProp ?? `field-${generated}`;
|
|
2305
|
+
const hintId = `${id}-hint`;
|
|
2306
|
+
const errorId = `${id}-error`;
|
|
2307
|
+
const hasError = typeof error === "string" && error.length > 0;
|
|
2308
|
+
const describedBy = [hint ? hintId : null, hasError ? errorId : null].filter(Boolean).join(" ") || void 0;
|
|
2309
|
+
const labelId = `${id}-label`;
|
|
2310
|
+
const fieldContext = useMemo(() => ({ controlId: id, labelId, describedBy }), [id, labelId, describedBy]);
|
|
2311
|
+
const controlProps = {
|
|
2312
|
+
id,
|
|
2313
|
+
"aria-describedby": describedBy,
|
|
2314
|
+
...hasError ? { "aria-invalid": true, error: true } : {},
|
|
2315
|
+
...required ? { "aria-required": true, required: true } : {}
|
|
2316
|
+
};
|
|
2317
|
+
let control;
|
|
2318
|
+
if (typeof children === "function") {
|
|
2319
|
+
control = children(controlProps);
|
|
2320
|
+
} else {
|
|
2321
|
+
const child = Children.only(children);
|
|
2322
|
+
if (!isValidElement(child)) throw new Error("Field expects a single form control as its child");
|
|
2323
|
+
const isNative = typeof child.type === "string";
|
|
2324
|
+
const { error: errorFlag, ...ariaOnly } = controlProps;
|
|
2325
|
+
control = cloneElement(child, isNative ? ariaOnly : { ...ariaOnly, ...errorFlag ? { error: true } : {} });
|
|
2326
|
+
}
|
|
2327
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-ds-1.5", className), children: [
|
|
2328
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-ds-2", children: [
|
|
2329
|
+
/* @__PURE__ */ jsxs(Label, { id: labelId, htmlFor: id, children: [
|
|
2330
|
+
label,
|
|
2331
|
+
required && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "ml-ds-0.5 text-[var(--ds-status-error)]", children: "*" })
|
|
2332
|
+
] }),
|
|
2333
|
+
labelAction
|
|
2334
|
+
] }),
|
|
2335
|
+
/* @__PURE__ */ jsx(FieldContext.Provider, { value: fieldContext, children: control }),
|
|
2336
|
+
hint && /* @__PURE__ */ jsx("p", { id: hintId, className: "text-xs text-[var(--ds-text-muted)]", children: hint }),
|
|
2337
|
+
hasError && /* @__PURE__ */ jsx(InlineFieldError, { id: errorId, message: error, className: "mt-0" })
|
|
2338
|
+
] });
|
|
2339
|
+
}
|
|
2022
2340
|
function TruncFileName({ children, className }) {
|
|
2023
2341
|
const { ref, isTruncated } = useTextOverflow({ lines: 1 });
|
|
2024
2342
|
const el = /* @__PURE__ */ jsx("p", { ref, className: cn("truncate", className), children });
|
|
@@ -2030,37 +2348,57 @@ function formatSize(bytes) {
|
|
|
2030
2348
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
2031
2349
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
2032
2350
|
}
|
|
2033
|
-
function FileUpload({ onFiles, accept, multiple = true, maxSize, className, error = false, label }) {
|
|
2351
|
+
function FileUpload({ onFiles, accept, multiple = true, maxSize, className, error = false, label, id }) {
|
|
2034
2352
|
const [files, setFiles] = useState([]);
|
|
2035
2353
|
const [dragOver, setDragOver] = useState(false);
|
|
2036
|
-
const
|
|
2354
|
+
const [rejected, setRejected] = useState(null);
|
|
2037
2355
|
const inputRef = useRef(null);
|
|
2356
|
+
const nextEntryId = useRef(0);
|
|
2357
|
+
const timers = useRef(/* @__PURE__ */ new Map());
|
|
2358
|
+
useEffect(() => {
|
|
2359
|
+
const running = timers.current;
|
|
2360
|
+
return () => running.forEach(clearInterval);
|
|
2361
|
+
}, []);
|
|
2362
|
+
const field = useField();
|
|
2363
|
+
const ownId = useId();
|
|
2364
|
+
const inputId = id ?? `${ownId}-input`;
|
|
2365
|
+
const constraintsId = `${ownId}-constraints`;
|
|
2366
|
+
const rejectedId = `${ownId}-rejected`;
|
|
2367
|
+
const showLabel = label != null && !field;
|
|
2368
|
+
const constraints = fileConstraints(accept, maxSize, multiple);
|
|
2369
|
+
const invalid = error || rejected != null;
|
|
2370
|
+
const describedBy = [constraints ? constraintsId : null, field?.describedBy, rejected ? rejectedId : null].filter(Boolean).join(" ") || void 0;
|
|
2371
|
+
const stopTimer = (id2) => {
|
|
2372
|
+
clearInterval(timers.current.get(id2));
|
|
2373
|
+
timers.current.delete(id2);
|
|
2374
|
+
};
|
|
2038
2375
|
const addFiles = useCallback(
|
|
2039
2376
|
(fileList) => {
|
|
2040
|
-
const
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2377
|
+
const { accepted, message } = checkFiles(Array.from(fileList), { accept, maxSize, multiple });
|
|
2378
|
+
setRejected(message);
|
|
2379
|
+
if (accepted.length === 0) return;
|
|
2380
|
+
const entries = accepted.map((file) => ({ id: nextEntryId.current++, file, progress: 0, status: "uploading" }));
|
|
2381
|
+
if (!multiple) {
|
|
2382
|
+
timers.current.forEach(clearInterval);
|
|
2383
|
+
timers.current.clear();
|
|
2384
|
+
}
|
|
2385
|
+
setFiles((prev) => multiple ? [...prev, ...entries] : entries);
|
|
2386
|
+
onFiles(accepted);
|
|
2387
|
+
for (const { id: id2 } of entries) {
|
|
2046
2388
|
let progress = 0;
|
|
2047
|
-
const
|
|
2048
|
-
progress
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
clearInterval(
|
|
2052
|
-
|
|
2053
|
-
(prev) => prev.map((f, fi) => fi === prev.length - entries.length + i ? { ...f, progress: 100, status: "complete" } : f)
|
|
2054
|
-
);
|
|
2055
|
-
} else {
|
|
2056
|
-
setFiles(
|
|
2057
|
-
(prev) => prev.map((f, fi) => fi === prev.length - entries.length + i ? { ...f, progress } : f)
|
|
2058
|
-
);
|
|
2389
|
+
const timer = setInterval(() => {
|
|
2390
|
+
progress = Math.min(100, progress + Math.random() * 30 + 10);
|
|
2391
|
+
const done = progress >= 100;
|
|
2392
|
+
if (done) {
|
|
2393
|
+
clearInterval(timer);
|
|
2394
|
+
timers.current.delete(id2);
|
|
2059
2395
|
}
|
|
2396
|
+
setFiles((prev) => prev.map((f) => f.id === id2 ? { ...f, progress, status: done ? "complete" : "uploading" } : f));
|
|
2060
2397
|
}, 300);
|
|
2061
|
-
|
|
2398
|
+
timers.current.set(id2, timer);
|
|
2399
|
+
}
|
|
2062
2400
|
},
|
|
2063
|
-
[maxSize, onFiles]
|
|
2401
|
+
[accept, maxSize, multiple, onFiles]
|
|
2064
2402
|
);
|
|
2065
2403
|
const handleDrop = useCallback(
|
|
2066
2404
|
(e) => {
|
|
@@ -2070,63 +2408,66 @@ function FileUpload({ onFiles, accept, multiple = true, maxSize, className, erro
|
|
|
2070
2408
|
},
|
|
2071
2409
|
[addFiles]
|
|
2072
2410
|
);
|
|
2073
|
-
const removeFile = (
|
|
2074
|
-
|
|
2411
|
+
const removeFile = (id2) => {
|
|
2412
|
+
stopTimer(id2);
|
|
2413
|
+
setFiles((prev) => prev.filter((f) => f.id !== id2));
|
|
2075
2414
|
};
|
|
2076
2415
|
return /* @__PURE__ */ jsxs("div", { className: cn("space-y-ds-3", className), children: [
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
"
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2416
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-ds-1.5", children: [
|
|
2417
|
+
showLabel && /* @__PURE__ */ jsx(Label, { htmlFor: inputId, children: label }),
|
|
2418
|
+
/* @__PURE__ */ jsxs(
|
|
2419
|
+
"div",
|
|
2420
|
+
{
|
|
2421
|
+
onDragOver: (e) => {
|
|
2422
|
+
e.preventDefault();
|
|
2423
|
+
setDragOver(true);
|
|
2424
|
+
},
|
|
2425
|
+
onDragLeave: () => setDragOver(false),
|
|
2426
|
+
onDrop: handleDrop,
|
|
2427
|
+
onClick: () => inputRef.current?.click(),
|
|
2428
|
+
className: cn(
|
|
2429
|
+
"flex flex-col items-center justify-center gap-ds-2 cursor-pointer group",
|
|
2430
|
+
"border-2 border-dashed rounded-[var(--ds-radius-md)]",
|
|
2431
|
+
"transition-colors",
|
|
2432
|
+
// The real file input is visually hidden inside; Tab lands on it and
|
|
2433
|
+
// Enter/Space open the picker natively, so the zone shows its focus.
|
|
2434
|
+
invalid ? ERROR_HAS_FOCUS_RING : HAS_FOCUS_RING,
|
|
2435
|
+
dragOver ? `${ACTIVE_RING} bg-[var(--ds-accent-whisper)]` : invalid ? "border-[var(--ds-status-error)]" : "border-[var(--ds-border-default)] hover:border-[var(--ds-accent-primary)] hover:bg-[var(--ds-accent-whisper)]"
|
|
2436
|
+
),
|
|
2437
|
+
style: { padding: "var(--ds-space-8) var(--ds-space-4)" },
|
|
2438
|
+
children: [
|
|
2439
|
+
/* @__PURE__ */ jsx("div", { className: cn(
|
|
2440
|
+
"flex items-center justify-center w-10 h-10 rounded-[var(--ds-radius-full)] transition-colors",
|
|
2441
|
+
"bg-[var(--ds-bg-muted)] group-hover:bg-[var(--ds-accent-subtle)]"
|
|
2442
|
+
), children: /* @__PURE__ */ jsx(Icon, { name: "plus", size: 20, className: "text-[var(--ds-text-muted)] group-hover:text-[var(--ds-accent-primary)] transition-colors" }) }),
|
|
2443
|
+
/* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
2444
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-[var(--ds-text-primary)]", children: multiple ? "Drop files here or browse" : "Drop a file here or browse" }),
|
|
2445
|
+
constraints && /* @__PURE__ */ jsx("p", { id: constraintsId, className: "text-xs text-[var(--ds-text-muted)] mt-ds-1", children: constraints })
|
|
2446
|
+
] }),
|
|
2447
|
+
/* @__PURE__ */ jsx(
|
|
2448
|
+
"input",
|
|
2449
|
+
{
|
|
2450
|
+
ref: inputRef,
|
|
2451
|
+
id: inputId,
|
|
2452
|
+
type: "file",
|
|
2453
|
+
accept,
|
|
2454
|
+
multiple,
|
|
2455
|
+
className: "sr-only",
|
|
2456
|
+
"aria-labelledby": field ? field.labelId : void 0,
|
|
2457
|
+
"aria-describedby": describedBy,
|
|
2458
|
+
"aria-invalid": invalid || void 0,
|
|
2459
|
+
onChange: (e) => {
|
|
2460
|
+
if (e.target.files?.length) addFiles(e.target.files);
|
|
2461
|
+
e.target.value = "";
|
|
2462
|
+
}
|
|
2123
2463
|
}
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2464
|
+
)
|
|
2465
|
+
]
|
|
2466
|
+
}
|
|
2467
|
+
),
|
|
2468
|
+
rejected && /* @__PURE__ */ jsx(InlineFieldError, { id: rejectedId, message: rejected, className: "mt-0" })
|
|
2469
|
+
] }),
|
|
2470
|
+
files.length > 0 && /* @__PURE__ */ jsx("ul", { className: "space-y-ds-2", children: files.map((entry) => /* @__PURE__ */ jsxs(
|
|
2130
2471
|
"li",
|
|
2131
2472
|
{
|
|
2132
2473
|
className: cn(
|
|
@@ -2143,10 +2484,10 @@ function FileUpload({ onFiles, accept, multiple = true, maxSize, className, erro
|
|
|
2143
2484
|
entry.status === "uploading" && /* @__PURE__ */ jsx(Progress, { value: entry.progress, size: "sm", className: "mt-ds-1" })
|
|
2144
2485
|
] }),
|
|
2145
2486
|
entry.status === "complete" && /* @__PURE__ */ jsx(Icon, { name: "check", size: 16, className: "text-[var(--ds-status-success)] shrink-0" }),
|
|
2146
|
-
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", onClick: () => removeFile(
|
|
2487
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", onClick: () => removeFile(entry.id), "aria-label": "Remove file", children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 14 }) })
|
|
2147
2488
|
]
|
|
2148
2489
|
},
|
|
2149
|
-
|
|
2490
|
+
entry.id
|
|
2150
2491
|
)) })
|
|
2151
2492
|
] });
|
|
2152
2493
|
}
|
|
@@ -2161,9 +2502,17 @@ function SliderRange({
|
|
|
2161
2502
|
className,
|
|
2162
2503
|
ref,
|
|
2163
2504
|
error = false,
|
|
2164
|
-
label
|
|
2505
|
+
label,
|
|
2506
|
+
"aria-label": ariaLabel,
|
|
2507
|
+
"aria-describedby": describedByProp,
|
|
2165
2508
|
trackStyle
|
|
2166
2509
|
}) {
|
|
2510
|
+
const field = useField();
|
|
2511
|
+
const ownId = useId();
|
|
2512
|
+
const showLabel = label != null && !field;
|
|
2513
|
+
const nameId = field ? field.labelId : showLabel ? `${ownId}-label` : void 0;
|
|
2514
|
+
const describedBy = [...new Set([describedByProp, field?.describedBy].join(" ").split(" ").filter(Boolean))].join(" ") || void 0;
|
|
2515
|
+
const thumbName = (part) => nameId ? { "aria-labelledby": part ? `${nameId} ${ownId}-${part}` : nameId } : { "aria-label": ariaLabel ? part ? `${ariaLabel} ${part}` : ariaLabel : void 0 };
|
|
2167
2516
|
const isRange = Array.isArray(value);
|
|
2168
2517
|
const low = isRange ? value[0] : value;
|
|
2169
2518
|
const high = isRange ? value[1] : value;
|
|
@@ -2219,7 +2568,14 @@ function SliderRange({
|
|
|
2219
2568
|
[disabled, min, max, handleChange]
|
|
2220
2569
|
);
|
|
2221
2570
|
return /* @__PURE__ */ jsxs("div", { ref, className: cn("space-y-ds-1", disabled && "opacity-disabled", className), children: [
|
|
2222
|
-
showValue && /* @__PURE__ */
|
|
2571
|
+
(showLabel || showValue) && /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-ds-2", showLabel ? "justify-between" : "justify-end"), children: [
|
|
2572
|
+
showLabel && /* @__PURE__ */ jsx("span", { id: `${ownId}-label`, className: "text-sm font-medium leading-none text-[var(--ds-text-secondary)]", children: label }),
|
|
2573
|
+
showValue && /* @__PURE__ */ jsx("span", { className: "text-xs font-mono tabular-nums text-[var(--ds-text-muted)]", children: isRange ? `${low} \u2013 ${high}` : low })
|
|
2574
|
+
] }),
|
|
2575
|
+
isRange && nameId && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2576
|
+
/* @__PURE__ */ jsx("span", { id: `${ownId}-minimum`, hidden: true, children: "minimum" }),
|
|
2577
|
+
/* @__PURE__ */ jsx("span", { id: `${ownId}-maximum`, hidden: true, children: "maximum" })
|
|
2578
|
+
] }),
|
|
2223
2579
|
/* @__PURE__ */ jsxs(
|
|
2224
2580
|
"div",
|
|
2225
2581
|
{
|
|
@@ -2242,7 +2598,8 @@ function SliderRange({
|
|
|
2242
2598
|
{
|
|
2243
2599
|
role: "slider",
|
|
2244
2600
|
tabIndex: disabled ? -1 : 0,
|
|
2245
|
-
"
|
|
2601
|
+
...thumbName("minimum"),
|
|
2602
|
+
"aria-describedby": describedBy,
|
|
2246
2603
|
"aria-valuemin": min,
|
|
2247
2604
|
"aria-valuemax": high,
|
|
2248
2605
|
"aria-valuenow": low,
|
|
@@ -2266,7 +2623,8 @@ function SliderRange({
|
|
|
2266
2623
|
{
|
|
2267
2624
|
role: "slider",
|
|
2268
2625
|
tabIndex: disabled ? -1 : 0,
|
|
2269
|
-
|
|
2626
|
+
...thumbName(isRange ? "maximum" : void 0),
|
|
2627
|
+
"aria-describedby": describedBy,
|
|
2270
2628
|
"aria-valuemin": isRange ? low : min,
|
|
2271
2629
|
"aria-valuemax": max,
|
|
2272
2630
|
"aria-valuenow": high,
|
|
@@ -2365,14 +2723,25 @@ function TimePicker({
|
|
|
2365
2723
|
const size = sizeProp ?? contextSize ?? "md";
|
|
2366
2724
|
const [open, setOpen] = useState(false);
|
|
2367
2725
|
const triggerRef = useRef(null);
|
|
2726
|
+
const buttonRef = useRef(null);
|
|
2368
2727
|
const panelRef = useRef(null);
|
|
2369
2728
|
const listboxId = useId();
|
|
2370
2729
|
const pos = usePosition(triggerRef, panelRef, open, { side: "bottom", align: "start", offset: 4, flip: true });
|
|
2371
2730
|
const parsed = parseTime(value);
|
|
2372
2731
|
const hours = generateHours(use24Hour);
|
|
2373
2732
|
const minutes = generateMinutes(minuteStep);
|
|
2374
|
-
const isTopLayer =
|
|
2375
|
-
|
|
2733
|
+
const { isTop: isTopLayer, returnFocus } = usePopupFocus(open, { trigger: buttonRef, panel: panelRef, close: () => setOpen(false), tabExits: "edges" });
|
|
2734
|
+
const [columnStop, setColumnStop] = useState({});
|
|
2735
|
+
const [prevOpen, setPrevOpen] = useState(open);
|
|
2736
|
+
if (open !== prevOpen) {
|
|
2737
|
+
setPrevOpen(open);
|
|
2738
|
+
if (open) setColumnStop({});
|
|
2739
|
+
}
|
|
2740
|
+
const stopOf = (column, chosen) => columnStop[column] ?? Math.max(0, chosen);
|
|
2741
|
+
const holdStop = (column, index) => setColumnStop((s) => s[column] === index ? s : { ...s, [column]: index });
|
|
2742
|
+
const chosenHour = hours.findIndex((h) => use24Hour ? h === parseInt(value) : h === parsed.hour);
|
|
2743
|
+
const chosenMinute = minutes.findIndex((m) => m === parsed.minute);
|
|
2744
|
+
const chosenPeriod = parsed.period === "PM" ? 1 : 0;
|
|
2376
2745
|
useEffect(() => {
|
|
2377
2746
|
if (!open) return;
|
|
2378
2747
|
const id2 = requestAnimationFrame(() => {
|
|
@@ -2424,7 +2793,6 @@ function TimePicker({
|
|
|
2424
2793
|
const el = segmentRefs.current[Math.max(0, Math.min(segmentCount - 1, i))];
|
|
2425
2794
|
el?.focus();
|
|
2426
2795
|
};
|
|
2427
|
-
const focusSegmentRef = useLatest(focusSegment);
|
|
2428
2796
|
useEffect(() => {
|
|
2429
2797
|
if (!open) return;
|
|
2430
2798
|
const handler = (e) => {
|
|
@@ -2432,10 +2800,10 @@ function TimePicker({
|
|
|
2432
2800
|
setOpen(false);
|
|
2433
2801
|
};
|
|
2434
2802
|
const keyHandler = (e) => {
|
|
2435
|
-
if (e.key
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2803
|
+
if (e.key !== "Escape" || e.defaultPrevented || !isTopLayer()) return;
|
|
2804
|
+
e.preventDefault();
|
|
2805
|
+
returnFocus();
|
|
2806
|
+
setOpen(false);
|
|
2439
2807
|
};
|
|
2440
2808
|
document.addEventListener("mousedown", handler);
|
|
2441
2809
|
document.addEventListener("keydown", keyHandler);
|
|
@@ -2443,7 +2811,7 @@ function TimePicker({
|
|
|
2443
2811
|
document.removeEventListener("mousedown", handler);
|
|
2444
2812
|
document.removeEventListener("keydown", keyHandler);
|
|
2445
2813
|
};
|
|
2446
|
-
}, [open, isTopLayer,
|
|
2814
|
+
}, [open, isTopLayer, returnFocus]);
|
|
2447
2815
|
const commitIfComplete = (next) => {
|
|
2448
2816
|
if (next.hour === null || next.minute === null) return;
|
|
2449
2817
|
let h24 = next.hour;
|
|
@@ -2619,6 +2987,7 @@ function TimePicker({
|
|
|
2619
2987
|
/* @__PURE__ */ jsx(
|
|
2620
2988
|
"button",
|
|
2621
2989
|
{
|
|
2990
|
+
ref: buttonRef,
|
|
2622
2991
|
type: "button",
|
|
2623
2992
|
"aria-label": "Choose a time",
|
|
2624
2993
|
"aria-haspopup": "dialog",
|
|
@@ -2651,10 +3020,12 @@ function TimePicker({
|
|
|
2651
3020
|
),
|
|
2652
3021
|
style: { top: pos.top, left: pos.left },
|
|
2653
3022
|
children: /* @__PURE__ */ jsxs("div", { className: "inline-flex p-ds-1 gap-ds-1 tabular-nums", children: [
|
|
2654
|
-
/* @__PURE__ */ jsx("div", { "data-column": true, className: "max-h-48 overflow-y-auto w-ds-10", children: hours.map((h) => /* @__PURE__ */ jsx(
|
|
3023
|
+
/* @__PURE__ */ jsx("div", { "data-column": true, className: "max-h-48 overflow-y-auto w-ds-10", children: hours.map((h, i) => /* @__PURE__ */ jsx(
|
|
2655
3024
|
"button",
|
|
2656
3025
|
{
|
|
2657
3026
|
type: "button",
|
|
3027
|
+
tabIndex: i === stopOf("hour", chosenHour) ? 0 : -1,
|
|
3028
|
+
onFocus: () => holdStop("hour", i),
|
|
2658
3029
|
"data-selected": use24Hour ? h === parseInt(value) : h === parsed.hour,
|
|
2659
3030
|
onMouseDown: (e) => e.preventDefault(),
|
|
2660
3031
|
onClick: () => emitChange(h, parsed.minute, parsed.period),
|
|
@@ -2668,10 +3039,12 @@ function TimePicker({
|
|
|
2668
3039
|
h
|
|
2669
3040
|
)) }),
|
|
2670
3041
|
/* @__PURE__ */ jsx("div", { className: "w-px bg-[var(--ds-border-subtle)]" }),
|
|
2671
|
-
/* @__PURE__ */ jsx("div", { "data-column": true, className: "max-h-48 overflow-y-auto w-ds-10", children: minutes.map((m) => /* @__PURE__ */ jsx(
|
|
3042
|
+
/* @__PURE__ */ jsx("div", { "data-column": true, className: "max-h-48 overflow-y-auto w-ds-10", children: minutes.map((m, i) => /* @__PURE__ */ jsx(
|
|
2672
3043
|
"button",
|
|
2673
3044
|
{
|
|
2674
3045
|
type: "button",
|
|
3046
|
+
tabIndex: i === stopOf("minute", chosenMinute) ? 0 : -1,
|
|
3047
|
+
onFocus: () => holdStop("minute", i),
|
|
2675
3048
|
"data-selected": m === parsed.minute,
|
|
2676
3049
|
onMouseDown: (e) => e.preventDefault(),
|
|
2677
3050
|
onClick: () => emitChange(parsed.hour, m, parsed.period),
|
|
@@ -2686,10 +3059,12 @@ function TimePicker({
|
|
|
2686
3059
|
)) }),
|
|
2687
3060
|
!use24Hour && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2688
3061
|
/* @__PURE__ */ jsx("div", { className: "w-px bg-[var(--ds-border-subtle)]" }),
|
|
2689
|
-
/* @__PURE__ */ jsx("div", { "data-column": true, className: "flex flex-col gap-ds-1 w-ds-10", children: ["AM", "PM"].map((p) => /* @__PURE__ */ jsx(
|
|
3062
|
+
/* @__PURE__ */ jsx("div", { "data-column": true, className: "flex flex-col gap-ds-1 w-ds-10", children: ["AM", "PM"].map((p, i) => /* @__PURE__ */ jsx(
|
|
2690
3063
|
"button",
|
|
2691
3064
|
{
|
|
2692
3065
|
type: "button",
|
|
3066
|
+
tabIndex: i === stopOf("period", chosenPeriod) ? 0 : -1,
|
|
3067
|
+
onFocus: () => holdStop("period", i),
|
|
2693
3068
|
"data-selected": p === parsed.period,
|
|
2694
3069
|
onMouseDown: (e) => e.preventDefault(),
|
|
2695
3070
|
onClick: () => emitChange(parsed.hour, parsed.minute, p),
|
|
@@ -3016,7 +3391,8 @@ var Tag = forwardRef(function Tag2({
|
|
|
3016
3391
|
{
|
|
3017
3392
|
type: "button",
|
|
3018
3393
|
onClick: handleRemove,
|
|
3019
|
-
"
|
|
3394
|
+
"data-tag-remove": "",
|
|
3395
|
+
"aria-label": typeof children === "string" ? `Remove ${children}` : "Remove",
|
|
3020
3396
|
className: cn(
|
|
3021
3397
|
"inline-flex items-center justify-center shrink-0",
|
|
3022
3398
|
"rounded-[var(--ds-radius-sm)]",
|
|
@@ -3063,6 +3439,16 @@ function TagInput({
|
|
|
3063
3439
|
},
|
|
3064
3440
|
[value, onChange]
|
|
3065
3441
|
);
|
|
3442
|
+
const containerRef = useRef(null);
|
|
3443
|
+
const pendingFocus = useRef(null);
|
|
3444
|
+
useLayoutEffect(() => {
|
|
3445
|
+
const pending = pendingFocus.current;
|
|
3446
|
+
if (pending === null) return;
|
|
3447
|
+
pendingFocus.current = null;
|
|
3448
|
+
if (value.includes(pending.tag)) return;
|
|
3449
|
+
const buttons = Array.from(containerRef.current?.querySelectorAll("[data-tag-remove]") ?? []);
|
|
3450
|
+
focusAfterRemoval(buttons, pending.index, inputRef.current);
|
|
3451
|
+
});
|
|
3066
3452
|
const handleKeyDown = useCallback(
|
|
3067
3453
|
(e) => {
|
|
3068
3454
|
if ((e.key === "Enter" || e.key === ",") && input.trim()) {
|
|
@@ -3095,7 +3481,10 @@ function TagInput({
|
|
|
3095
3481
|
return /* @__PURE__ */ jsxs(
|
|
3096
3482
|
"div",
|
|
3097
3483
|
{
|
|
3098
|
-
|
|
3484
|
+
ref: containerRef,
|
|
3485
|
+
onClick: (e) => {
|
|
3486
|
+
if (!(e.target instanceof Element && e.target.closest("button"))) inputRef.current?.focus();
|
|
3487
|
+
},
|
|
3099
3488
|
className: cn(
|
|
3100
3489
|
"flex flex-wrap items-center gap-[calc(var(--ds-space-1)*1.5)] min-h-[calc(var(--ds-space-1)*10.5)] px-ds-2 py-[calc(var(--ds-space-1)*1.5)]",
|
|
3101
3490
|
"bg-[var(--ds-input-bg)] text-[var(--ds-text-primary)]",
|
|
@@ -3110,10 +3499,13 @@ function TagInput({
|
|
|
3110
3499
|
className
|
|
3111
3500
|
),
|
|
3112
3501
|
children: [
|
|
3113
|
-
value.map((tag) => /* @__PURE__ */ jsx(
|
|
3502
|
+
value.map((tag, i) => /* @__PURE__ */ jsx(
|
|
3114
3503
|
Tag,
|
|
3115
3504
|
{
|
|
3116
|
-
onRemove: disabled ? void 0 : () =>
|
|
3505
|
+
onRemove: disabled ? void 0 : () => {
|
|
3506
|
+
pendingFocus.current = { index: i, tag };
|
|
3507
|
+
removeTag(tag);
|
|
3508
|
+
},
|
|
3117
3509
|
disabled,
|
|
3118
3510
|
children: tag
|
|
3119
3511
|
},
|
|
@@ -3640,60 +4032,6 @@ function ColorPicker({
|
|
|
3640
4032
|
}
|
|
3641
4033
|
);
|
|
3642
4034
|
}
|
|
3643
|
-
function InlineFieldError({ message, id, className }) {
|
|
3644
|
-
return /* @__PURE__ */ jsxs(
|
|
3645
|
-
"p",
|
|
3646
|
-
{
|
|
3647
|
-
id,
|
|
3648
|
-
role: "alert",
|
|
3649
|
-
className: cn(
|
|
3650
|
-
"flex items-center gap-ds-1.5 text-xs text-[var(--ds-status-error)]",
|
|
3651
|
-
"mt-ds-1.5",
|
|
3652
|
-
className
|
|
3653
|
-
),
|
|
3654
|
-
children: [
|
|
3655
|
-
/* @__PURE__ */ jsx(Icon, { name: "error", size: 14, className: "shrink-0" }),
|
|
3656
|
-
/* @__PURE__ */ jsx("span", { children: message })
|
|
3657
|
-
]
|
|
3658
|
-
}
|
|
3659
|
-
);
|
|
3660
|
-
}
|
|
3661
|
-
function Field({ label, children, hint, error, required, labelAction, id: idProp, className }) {
|
|
3662
|
-
const generated = useId();
|
|
3663
|
-
const id = idProp ?? `field-${generated}`;
|
|
3664
|
-
const hintId = `${id}-hint`;
|
|
3665
|
-
const errorId = `${id}-error`;
|
|
3666
|
-
const hasError = typeof error === "string" && error.length > 0;
|
|
3667
|
-
const describedBy = [hint ? hintId : null, hasError ? errorId : null].filter(Boolean).join(" ") || void 0;
|
|
3668
|
-
const controlProps = {
|
|
3669
|
-
id,
|
|
3670
|
-
"aria-describedby": describedBy,
|
|
3671
|
-
...hasError ? { "aria-invalid": true, error: true } : {},
|
|
3672
|
-
...required ? { "aria-required": true, required: true } : {}
|
|
3673
|
-
};
|
|
3674
|
-
let control;
|
|
3675
|
-
if (typeof children === "function") {
|
|
3676
|
-
control = children(controlProps);
|
|
3677
|
-
} else {
|
|
3678
|
-
const child = Children.only(children);
|
|
3679
|
-
if (!isValidElement(child)) throw new Error("Field expects a single form control as its child");
|
|
3680
|
-
const isNative = typeof child.type === "string";
|
|
3681
|
-
const { error: errorFlag, ...ariaOnly } = controlProps;
|
|
3682
|
-
control = cloneElement(child, isNative ? ariaOnly : { ...ariaOnly, ...errorFlag ? { error: true } : {} });
|
|
3683
|
-
}
|
|
3684
|
-
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-ds-1.5", className), children: [
|
|
3685
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-ds-2", children: [
|
|
3686
|
-
/* @__PURE__ */ jsxs(Label, { htmlFor: id, children: [
|
|
3687
|
-
label,
|
|
3688
|
-
required && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "ml-ds-0.5 text-[var(--ds-status-error)]", children: "*" })
|
|
3689
|
-
] }),
|
|
3690
|
-
labelAction
|
|
3691
|
-
] }),
|
|
3692
|
-
control,
|
|
3693
|
-
hint && /* @__PURE__ */ jsx("p", { id: hintId, className: "text-xs text-[var(--ds-text-muted)]", children: hint }),
|
|
3694
|
-
hasError && /* @__PURE__ */ jsx(InlineFieldError, { id: errorId, message: error, className: "mt-0" })
|
|
3695
|
-
] });
|
|
3696
|
-
}
|
|
3697
4035
|
var variantStyles2 = {
|
|
3698
4036
|
info: "border-[var(--ds-accent-primary)] bg-[var(--ds-accent-subtle)]",
|
|
3699
4037
|
success: "border-[var(--ds-status-success)] bg-[var(--ds-status-success-bg)]",
|
|
@@ -4369,7 +4707,6 @@ function MentionInput({
|
|
|
4369
4707
|
const value = controlledValue ?? internalValue;
|
|
4370
4708
|
const [query, setQuery] = useState("");
|
|
4371
4709
|
const [showPopup, setShowPopup] = useState(false);
|
|
4372
|
-
useOverlayLayer(showPopup);
|
|
4373
4710
|
const [activeIndex, setActiveIndex] = useState(0);
|
|
4374
4711
|
const [triggerStart, setTriggerStart] = useState(-1);
|
|
4375
4712
|
const [popupPos, setPopupPos] = useState({ top: 0, left: 0 });
|
|
@@ -4379,6 +4716,7 @@ function MentionInput({
|
|
|
4379
4716
|
const filtered = suggestions.filter(
|
|
4380
4717
|
(s) => s.label.toLowerCase().includes(query.toLowerCase()) || s.description?.toLowerCase().includes(query.toLowerCase())
|
|
4381
4718
|
);
|
|
4719
|
+
useOverlayLayer(showPopup && filtered.length > 0);
|
|
4382
4720
|
const updateValue = useCallback(
|
|
4383
4721
|
(v) => {
|
|
4384
4722
|
if (controlledValue === void 0) setInternalValue(v);
|
|
@@ -4457,6 +4795,7 @@ function MentionInput({
|
|
|
4457
4795
|
e.preventDefault();
|
|
4458
4796
|
insertMention(filtered[activeIndex]);
|
|
4459
4797
|
} else if (e.key === "Escape") {
|
|
4798
|
+
e.preventDefault();
|
|
4460
4799
|
setShowPopup(false);
|
|
4461
4800
|
}
|
|
4462
4801
|
};
|
|
@@ -4560,6 +4899,8 @@ function MentionInput({
|
|
|
4560
4899
|
] });
|
|
4561
4900
|
}
|
|
4562
4901
|
var CardCtx = createContext(false);
|
|
4902
|
+
var CardActionCtx = createContext(null);
|
|
4903
|
+
var CARD_ACTION_ATTR = "data-card-action";
|
|
4563
4904
|
var CardSurfaceCtx = createContext(false);
|
|
4564
4905
|
var variantStyles3 = {
|
|
4565
4906
|
default: `bg-[var(--ds-bg-surface)] border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] ${GLASS_SURFACE}`,
|
|
@@ -4679,21 +5020,57 @@ var Card = forwardRef(function Card2({
|
|
|
4679
5020
|
const isSelectable = selectable || !!selectType;
|
|
4680
5021
|
const isToggle = selectType === "toggle";
|
|
4681
5022
|
const hasSelectType = !!selectType;
|
|
5023
|
+
const isAction = !isSelectable && variant === "interactive" && !!onClick;
|
|
5024
|
+
const rootRef = useRef(null);
|
|
5025
|
+
const setRoot = useCallback((node) => {
|
|
5026
|
+
rootRef.current = node;
|
|
5027
|
+
if (typeof ref === "function") ref(node);
|
|
5028
|
+
else if (ref) ref.current = node;
|
|
5029
|
+
}, [ref]);
|
|
5030
|
+
const [inner, setInner] = useState({ controls: false, titleId: null });
|
|
5031
|
+
useLayoutEffect(() => {
|
|
5032
|
+
const root = rootRef.current;
|
|
5033
|
+
if (!root || !isAction && !checkable) return;
|
|
5034
|
+
const controls = Array.from(root.querySelectorAll(FOCUSABLE)).some((el) => !el.hasAttribute(CARD_ACTION_ATTR));
|
|
5035
|
+
const titleId = root.querySelector("[data-card-title]")?.id || null;
|
|
5036
|
+
setInner((cur) => cur.controls === controls && cur.titleId === titleId ? cur : { controls, titleId });
|
|
5037
|
+
}, [isAction, checkable, loading, children]);
|
|
5038
|
+
const holdsControls = isAction && inner.controls;
|
|
5039
|
+
const action = useMemo(() => holdsControls ? { activate: () => rootRef.current?.click(), disabled } : null, [holdsControls, disabled]);
|
|
4682
5040
|
const handleClick = isSelectable && !disabled ? (e) => {
|
|
4683
5041
|
onSelectedChange?.(!selected);
|
|
4684
5042
|
onClick?.(e);
|
|
4685
|
-
} : onClick;
|
|
5043
|
+
} : isAction && disabled ? void 0 : onClick;
|
|
5044
|
+
const handleCardClick = (e) => {
|
|
5045
|
+
if (disabled || !(e.target instanceof Element) || !e.currentTarget.contains(e.target)) return;
|
|
5046
|
+
const control = e.target.closest(FOCUSABLE);
|
|
5047
|
+
if (control && control !== e.currentTarget && e.currentTarget.contains(control)) return;
|
|
5048
|
+
onClick?.(e);
|
|
5049
|
+
};
|
|
4686
5050
|
const handleKeyDown = isSelectable && !disabled ? (e) => {
|
|
4687
5051
|
if (e.key === "Enter" || e.key === " ") {
|
|
4688
5052
|
e.preventDefault();
|
|
4689
5053
|
onSelectedChange?.(!selected);
|
|
4690
5054
|
}
|
|
5055
|
+
} : isAction && !disabled ? (e) => {
|
|
5056
|
+
if (e.target !== e.currentTarget) return;
|
|
5057
|
+
if (e.key === "Enter") {
|
|
5058
|
+
e.preventDefault();
|
|
5059
|
+
e.currentTarget.click();
|
|
5060
|
+
} else if (e.key === " ") e.preventDefault();
|
|
5061
|
+
} : void 0;
|
|
5062
|
+
const handleKeyUp = isAction && !disabled ? (e) => {
|
|
5063
|
+
if (e.target === e.currentTarget && e.key === " ") {
|
|
5064
|
+
e.preventDefault();
|
|
5065
|
+
e.currentTarget.click();
|
|
5066
|
+
}
|
|
4691
5067
|
} : void 0;
|
|
4692
5068
|
const handleCheckableClick = (e) => {
|
|
4693
5069
|
e.stopPropagation();
|
|
4694
5070
|
onSelectedChange?.(!selected);
|
|
4695
5071
|
};
|
|
4696
|
-
const
|
|
5072
|
+
const isButton = isSelectable || isAction && !holdsControls;
|
|
5073
|
+
const role = selectType === "radio" ? "radio" : selectType === "checkbox" ? "checkbox" : selectType === "toggle" ? "switch" : isButton ? "button" : void 0;
|
|
4697
5074
|
const ariaAttr = selectType === "radio" || selectType === "checkbox" || selectType === "toggle" ? { "aria-checked": !!selected } : isSelectable ? { "aria-pressed": !!selected } : {};
|
|
4698
5075
|
const showRing = isSelectable && !isToggle && !hasSelectType && selected;
|
|
4699
5076
|
const indicator = selectType === "radio" ? /* @__PURE__ */ jsx(RadioIndicator, { checked: !!selected, disabled }) : selectType === "checkbox" ? /* @__PURE__ */ jsx(CheckboxIndicator, { checked: !!selected, indeterminate, disabled }) : selectType === "toggle" ? /* @__PURE__ */ jsx(ToggleIndicator, { checked: !!selected, disabled }) : null;
|
|
@@ -4701,11 +5078,11 @@ var Card = forwardRef(function Card2({
|
|
|
4701
5078
|
return /* @__PURE__ */ jsxs(
|
|
4702
5079
|
"div",
|
|
4703
5080
|
{
|
|
4704
|
-
ref,
|
|
5081
|
+
ref: setRoot,
|
|
4705
5082
|
"data-card": "",
|
|
4706
5083
|
role,
|
|
4707
|
-
tabIndex: isSelectable ? 0 : void 0,
|
|
4708
|
-
"aria-disabled":
|
|
5084
|
+
tabIndex: isSelectable || isButton && !disabled ? 0 : void 0,
|
|
5085
|
+
"aria-disabled": isButton && disabled ? true : void 0,
|
|
4709
5086
|
...name && selectType === "radio" ? { "data-radio-group": name } : {},
|
|
4710
5087
|
style: variant === "interactive" ? { ...INTERACTIVE_SCALE_CAP, ...style } : style,
|
|
4711
5088
|
className: cn(
|
|
@@ -4713,14 +5090,15 @@ var Card = forwardRef(function Card2({
|
|
|
4713
5090
|
variantStyles3[variant],
|
|
4714
5091
|
isSelectable && !disabled && "cursor-pointer select-none transition-all duration-[var(--ds-transition-speed)] ease-[var(--ds-transition-ease)]",
|
|
4715
5092
|
isSelectable && !disabled && !selected && "hover:border-[var(--ds-accent-primary)]",
|
|
4716
|
-
|
|
5093
|
+
isButton && "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
4717
5094
|
(showRing || hasSelectType && selected) && ACTIVE_RING,
|
|
4718
5095
|
hasSelectType && selected && "bg-[var(--ds-accent-subtle)]",
|
|
4719
5096
|
disabled && "opacity-disabled cursor-not-allowed",
|
|
4720
5097
|
className
|
|
4721
5098
|
),
|
|
4722
|
-
onClick: handleClick,
|
|
4723
|
-
onKeyDown: handleKeyDown,
|
|
5099
|
+
onClick: holdsControls ? handleCardClick : handleClick,
|
|
5100
|
+
onKeyDown: holdsControls ? void 0 : handleKeyDown,
|
|
5101
|
+
onKeyUp: holdsControls ? void 0 : handleKeyUp,
|
|
4724
5102
|
...ariaAttr,
|
|
4725
5103
|
...props,
|
|
4726
5104
|
children: [
|
|
@@ -4733,6 +5111,7 @@ var Card = forwardRef(function Card2({
|
|
|
4733
5111
|
onClick: handleCheckableClick,
|
|
4734
5112
|
role: "checkbox",
|
|
4735
5113
|
"aria-checked": !!selected,
|
|
5114
|
+
...inner.titleId ? { "aria-labelledby": inner.titleId } : { "aria-label": "Select" },
|
|
4736
5115
|
tabIndex: 0,
|
|
4737
5116
|
onKeyDown: (e) => {
|
|
4738
5117
|
if (e.key === "Enter" || e.key === " ") {
|
|
@@ -4744,7 +5123,7 @@ var Card = forwardRef(function Card2({
|
|
|
4744
5123
|
children: /* @__PURE__ */ jsx(CheckboxIndicator, { checked: !!selected })
|
|
4745
5124
|
}
|
|
4746
5125
|
),
|
|
4747
|
-
/* @__PURE__ */ jsx(CardSurfaceCtx, { value: true, children: /* @__PURE__ */ jsx(CardCtx, { value: checkable, children: loading ? (
|
|
5126
|
+
/* @__PURE__ */ jsx(CardSurfaceCtx, { value: true, children: /* @__PURE__ */ jsx(CardActionCtx, { value: action, children: /* @__PURE__ */ jsx(CardCtx, { value: checkable, children: loading ? (
|
|
4748
5127
|
// Round 15 (the owner's 52.1): a placeholder stands where the content will stand — inside the card's
|
|
4749
5128
|
// content inset (CardContent's padding), a title-height line then two body lines — never flush against the border.
|
|
4750
5129
|
/* @__PURE__ */ jsx("div", { "data-card-loading": "", "aria-busy": "true", className: cn("pr-ds-5 py-ds-4", checkable ? "pl-ds-10" : "pl-ds-5"), children: /* @__PURE__ */ jsxs("div", { className: "space-y-ds-3", children: [
|
|
@@ -4752,7 +5131,7 @@ var Card = forwardRef(function Card2({
|
|
|
4752
5131
|
/* @__PURE__ */ jsx(Skeleton, { variant: "custom", className: "h-3 w-full" }),
|
|
4753
5132
|
/* @__PURE__ */ jsx(Skeleton, { variant: "custom", className: "h-3 w-2/3" })
|
|
4754
5133
|
] }) })
|
|
4755
|
-
) : children }) })
|
|
5134
|
+
) : children }) }) })
|
|
4756
5135
|
]
|
|
4757
5136
|
}
|
|
4758
5137
|
);
|
|
@@ -4770,6 +5149,7 @@ var CardHeader = forwardRef(function CardHeader2({ className, children, actions,
|
|
|
4770
5149
|
"button",
|
|
4771
5150
|
{
|
|
4772
5151
|
type: "button",
|
|
5152
|
+
"aria-label": "More actions",
|
|
4773
5153
|
className: cn(
|
|
4774
5154
|
"inline-flex items-center justify-center h-8 w-8 rounded-[var(--ds-radius-md)]",
|
|
4775
5155
|
"text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]",
|
|
@@ -4806,20 +5186,42 @@ var cardLineClampClasses = {
|
|
|
4806
5186
|
5: "line-clamp-5",
|
|
4807
5187
|
6: "line-clamp-6"
|
|
4808
5188
|
};
|
|
4809
|
-
var CardTitle = forwardRef(function CardTitle2({ className, children, lines = 2, ...props }, forwardedRef) {
|
|
5189
|
+
var CardTitle = forwardRef(function CardTitle2({ className, children, lines = 2, id, ...props }, forwardedRef) {
|
|
5190
|
+
const action = useContext(CardActionCtx);
|
|
5191
|
+
const generatedId = useId();
|
|
4810
5192
|
const { ref: overflowRef, isTruncated } = useTextOverflow({ lines, disabled: lines === 0 });
|
|
4811
5193
|
const lineClampClass = lines > 0 ? cardLineClampClasses[lines] || `line-clamp-[${lines}]` : "";
|
|
4812
5194
|
const heading = /* @__PURE__ */ jsx(
|
|
4813
5195
|
"h3",
|
|
4814
5196
|
{
|
|
4815
5197
|
ref: (node) => {
|
|
4816
|
-
overflowRef(lines > 0 ? node : null);
|
|
5198
|
+
if (!action) overflowRef(lines > 0 ? node : null);
|
|
4817
5199
|
if (typeof forwardedRef === "function") forwardedRef(node);
|
|
4818
5200
|
else if (forwardedRef) forwardedRef.current = node;
|
|
4819
5201
|
},
|
|
4820
|
-
|
|
5202
|
+
id: id ?? generatedId,
|
|
5203
|
+
"data-card-title": "",
|
|
5204
|
+
className: cn("font-[family-name:var(--ds-font-display)] text-lg font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)]", !action && lines > 0 && lineClampClass, className),
|
|
4821
5205
|
...props,
|
|
4822
|
-
children
|
|
5206
|
+
children: action ? (
|
|
5207
|
+
// The card's action when the card holds controls of its own (Sprint 25.7): a real button, which a click
|
|
5208
|
+
// elsewhere on the card also runs. Its ::after spans the card to draw the card's focus ring, taking no clicks.
|
|
5209
|
+
// The clamp moves inside, since a button lays out its own lines.
|
|
5210
|
+
/* @__PURE__ */ jsx(
|
|
5211
|
+
"button",
|
|
5212
|
+
{
|
|
5213
|
+
type: "button",
|
|
5214
|
+
...{ [CARD_ACTION_ATTR]: "" },
|
|
5215
|
+
disabled: action.disabled,
|
|
5216
|
+
onClick: action.activate,
|
|
5217
|
+
className: cn(
|
|
5218
|
+
"block w-full text-left cursor-pointer [text-overflow:inherit] focus-visible:outline-none disabled:cursor-not-allowed",
|
|
5219
|
+
"after:absolute after:inset-0 after:rounded-[var(--ds-radius-md)] after:pointer-events-none focus-visible:after:shadow-[var(--ds-shadow-focus)]"
|
|
5220
|
+
),
|
|
5221
|
+
children: /* @__PURE__ */ jsx("span", { ref: (node) => overflowRef(lines > 0 ? node : null), className: cn("block [text-overflow:inherit]", lines > 0 && lineClampClass), children })
|
|
5222
|
+
}
|
|
5223
|
+
)
|
|
5224
|
+
) : children
|
|
4823
5225
|
}
|
|
4824
5226
|
);
|
|
4825
5227
|
if (!isTruncated || lines === 0) return heading;
|
|
@@ -5278,6 +5680,7 @@ function Table({
|
|
|
5278
5680
|
return /* @__PURE__ */ jsxs(
|
|
5279
5681
|
"div",
|
|
5280
5682
|
{
|
|
5683
|
+
"data-row": "",
|
|
5281
5684
|
className: cn(
|
|
5282
5685
|
"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
|
|
5283
5686
|
"rounded-[var(--ds-radius-md)] bg-[var(--ds-bg-surface)]",
|
|
@@ -5830,11 +6233,34 @@ function OverflowPopover({
|
|
|
5830
6233
|
offset: 4,
|
|
5831
6234
|
flip: true
|
|
5832
6235
|
});
|
|
6236
|
+
const { isTop, returnFocus } = usePopupFocus(open, { trigger: triggerRef, panel: floatingRef, close: () => setOpen(false), tabExits: "edges" });
|
|
6237
|
+
useEffect(() => {
|
|
6238
|
+
if (!open) return;
|
|
6239
|
+
const raf = requestAnimationFrame(() => focusInitial(floatingRef.current));
|
|
6240
|
+
const onKey = (e) => {
|
|
6241
|
+
if (e.key !== "Escape" || e.defaultPrevented || !isTop()) return;
|
|
6242
|
+
e.preventDefault();
|
|
6243
|
+
returnFocus();
|
|
6244
|
+
setOpen(false);
|
|
6245
|
+
};
|
|
6246
|
+
const onDown = (e) => {
|
|
6247
|
+
if (!triggerRef.current?.contains(e.target)) setOpen(false);
|
|
6248
|
+
};
|
|
6249
|
+
document.addEventListener("keydown", onKey);
|
|
6250
|
+
document.addEventListener("mousedown", onDown);
|
|
6251
|
+
return () => {
|
|
6252
|
+
cancelAnimationFrame(raf);
|
|
6253
|
+
document.removeEventListener("keydown", onKey);
|
|
6254
|
+
document.removeEventListener("mousedown", onDown);
|
|
6255
|
+
};
|
|
6256
|
+
}, [open, isTop, returnFocus]);
|
|
5833
6257
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5834
6258
|
/* @__PURE__ */ jsxs(
|
|
5835
6259
|
"button",
|
|
5836
6260
|
{
|
|
5837
6261
|
ref: triggerRef,
|
|
6262
|
+
"aria-haspopup": "dialog",
|
|
6263
|
+
"aria-expanded": open,
|
|
5838
6264
|
className: "text-2xs text-[var(--ds-accent-primary)] font-medium cursor-pointer hover:underline px-ds-1.5",
|
|
5839
6265
|
onClick: (e) => {
|
|
5840
6266
|
e.stopPropagation();
|
|
@@ -5852,6 +6278,8 @@ function OverflowPopover({
|
|
|
5852
6278
|
"div",
|
|
5853
6279
|
{
|
|
5854
6280
|
ref: floatingRef,
|
|
6281
|
+
role: "dialog",
|
|
6282
|
+
"aria-label": date.toLocaleDateString(void 0, { weekday: "long", month: "long", day: "numeric" }),
|
|
5855
6283
|
className: cn(
|
|
5856
6284
|
"fixed z-[var(--ds-z-popover)] w-56 max-h-48 overflow-y-auto",
|
|
5857
6285
|
"bg-[var(--ds-bg-surface-elevated)]",
|
|
@@ -6468,6 +6896,9 @@ function CompactDayCell({
|
|
|
6468
6896
|
const today = isCurrentMonth && isToday(day);
|
|
6469
6897
|
const selected = isCurrentMonth && selectedDate && isSameDay2(day, selectedDate);
|
|
6470
6898
|
const hasEvents = dayEvents.length > 0;
|
|
6899
|
+
const shown = open && hasEvents;
|
|
6900
|
+
const isTop = useOverlayLayer(shown);
|
|
6901
|
+
useCloseOnFocusOut(shown, cellRef, floatingRef, () => setOpen(false), isTop);
|
|
6471
6902
|
const eventColors = dayEvents.slice(0, 3).map((e) => categories[e.category ?? ""]?.color ?? "var(--ds-accent-primary)");
|
|
6472
6903
|
const handleMouseEnter = () => {
|
|
6473
6904
|
if (!hasEvents) return;
|
|
@@ -6486,7 +6917,9 @@ function CompactDayCell({
|
|
|
6486
6917
|
useEffect(() => {
|
|
6487
6918
|
if (!open) return;
|
|
6488
6919
|
const onKey = (e) => {
|
|
6489
|
-
if (e.key
|
|
6920
|
+
if (e.key !== "Escape" || e.defaultPrevented || !isTop()) return;
|
|
6921
|
+
e.preventDefault();
|
|
6922
|
+
setOpen(false);
|
|
6490
6923
|
};
|
|
6491
6924
|
const onClick = (e) => {
|
|
6492
6925
|
const t = e.target;
|
|
@@ -6499,7 +6932,7 @@ function CompactDayCell({
|
|
|
6499
6932
|
document.removeEventListener("keydown", onKey);
|
|
6500
6933
|
document.removeEventListener("mousedown", onClick);
|
|
6501
6934
|
};
|
|
6502
|
-
}, [open]);
|
|
6935
|
+
}, [open, isTop]);
|
|
6503
6936
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6504
6937
|
/* @__PURE__ */ jsxs(
|
|
6505
6938
|
"button",
|
|
@@ -6663,10 +7096,18 @@ function MonthDropdown({
|
|
|
6663
7096
|
setPrevBrowseSyncKey(browseSyncKey);
|
|
6664
7097
|
if (open) setBrowseYear(currentDate.getFullYear());
|
|
6665
7098
|
}
|
|
7099
|
+
const { isTop, returnFocus } = usePopupFocus(open, { trigger: triggerRef, panel: floatingRef, close: () => setOpen(false), tabExits: "edges" });
|
|
6666
7100
|
useEffect(() => {
|
|
6667
7101
|
if (!open) return;
|
|
7102
|
+
const raf = requestAnimationFrame(() => {
|
|
7103
|
+
const panel = floatingRef.current;
|
|
7104
|
+
(panel?.querySelector("[data-current]") ?? panel?.querySelector("button"))?.focus();
|
|
7105
|
+
});
|
|
6668
7106
|
const onKey = (e) => {
|
|
6669
|
-
if (e.key
|
|
7107
|
+
if (e.key !== "Escape" || e.defaultPrevented || !isTop()) return;
|
|
7108
|
+
e.preventDefault();
|
|
7109
|
+
returnFocus();
|
|
7110
|
+
setOpen(false);
|
|
6670
7111
|
};
|
|
6671
7112
|
const onClick = (e) => {
|
|
6672
7113
|
const t = e.target;
|
|
@@ -6676,10 +7117,11 @@ function MonthDropdown({
|
|
|
6676
7117
|
document.addEventListener("keydown", onKey);
|
|
6677
7118
|
document.addEventListener("mousedown", onClick);
|
|
6678
7119
|
return () => {
|
|
7120
|
+
cancelAnimationFrame(raf);
|
|
6679
7121
|
document.removeEventListener("keydown", onKey);
|
|
6680
7122
|
document.removeEventListener("mousedown", onClick);
|
|
6681
7123
|
};
|
|
6682
|
-
}, [open]);
|
|
7124
|
+
}, [open, isTop, returnFocus]);
|
|
6683
7125
|
const currentMonth = currentDate.getMonth();
|
|
6684
7126
|
const currentYear = currentDate.getFullYear();
|
|
6685
7127
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -6749,7 +7191,9 @@ function MonthDropdown({
|
|
|
6749
7191
|
"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
6750
7192
|
isActive ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-emphasis)] hover:text-[var(--ds-text-primary)]"
|
|
6751
7193
|
),
|
|
7194
|
+
"data-current": isActive || void 0,
|
|
6752
7195
|
onClick: () => {
|
|
7196
|
+
returnFocus();
|
|
6753
7197
|
onSelect(new Date(browseYear, i, 1));
|
|
6754
7198
|
setOpen(false);
|
|
6755
7199
|
},
|
|
@@ -6786,10 +7230,18 @@ function YearDropdown({
|
|
|
6786
7230
|
setPrevRangeSyncKey(rangeSyncKey);
|
|
6787
7231
|
if (open) setRangeStart(currentYear - 4);
|
|
6788
7232
|
}
|
|
7233
|
+
const { isTop, returnFocus } = usePopupFocus(open, { trigger: triggerRef, panel: floatingRef, close: () => setOpen(false), tabExits: "edges" });
|
|
6789
7234
|
useEffect(() => {
|
|
6790
7235
|
if (!open) return;
|
|
7236
|
+
const raf = requestAnimationFrame(() => {
|
|
7237
|
+
const panel = floatingRef.current;
|
|
7238
|
+
(panel?.querySelector("[data-current]") ?? panel?.querySelector("button"))?.focus();
|
|
7239
|
+
});
|
|
6791
7240
|
const onKey = (e) => {
|
|
6792
|
-
if (e.key
|
|
7241
|
+
if (e.key !== "Escape" || e.defaultPrevented || !isTop()) return;
|
|
7242
|
+
e.preventDefault();
|
|
7243
|
+
returnFocus();
|
|
7244
|
+
setOpen(false);
|
|
6793
7245
|
};
|
|
6794
7246
|
const onClick = (e) => {
|
|
6795
7247
|
const t = e.target;
|
|
@@ -6799,10 +7251,11 @@ function YearDropdown({
|
|
|
6799
7251
|
document.addEventListener("keydown", onKey);
|
|
6800
7252
|
document.addEventListener("mousedown", onClick);
|
|
6801
7253
|
return () => {
|
|
7254
|
+
cancelAnimationFrame(raf);
|
|
6802
7255
|
document.removeEventListener("keydown", onKey);
|
|
6803
7256
|
document.removeEventListener("mousedown", onClick);
|
|
6804
7257
|
};
|
|
6805
|
-
}, [open]);
|
|
7258
|
+
}, [open, isTop, returnFocus]);
|
|
6806
7259
|
const years = Array.from({ length: 9 }, (_, i) => rangeStart + i);
|
|
6807
7260
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6808
7261
|
/* @__PURE__ */ jsxs(
|
|
@@ -6871,7 +7324,9 @@ function YearDropdown({
|
|
|
6871
7324
|
"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
6872
7325
|
y === currentYear ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-emphasis)] hover:text-[var(--ds-text-primary)]"
|
|
6873
7326
|
),
|
|
7327
|
+
"data-current": y === currentYear || void 0,
|
|
6874
7328
|
onClick: () => {
|
|
7329
|
+
returnFocus();
|
|
6875
7330
|
onSelect(new Date(y, currentDate.getMonth(), 1));
|
|
6876
7331
|
setOpen(false);
|
|
6877
7332
|
},
|
|
@@ -6947,7 +7402,7 @@ function Calendar({
|
|
|
6947
7402
|
if (currentView === "month") {
|
|
6948
7403
|
setCurrentDate(addMonths(currentDate, direction));
|
|
6949
7404
|
} else if (currentView === "week") {
|
|
6950
|
-
setCurrentDate(
|
|
7405
|
+
setCurrentDate(addDays2(currentDate, direction * 7));
|
|
6951
7406
|
} else {
|
|
6952
7407
|
setCurrentDate(new Date(currentDate.getFullYear() + direction, currentDate.getMonth(), 1));
|
|
6953
7408
|
}
|
|
@@ -9600,8 +10055,11 @@ var Breadcrumbs = forwardRef(function Breadcrumbs2({
|
|
|
9600
10055
|
container
|
|
9601
10056
|
}, ref) {
|
|
9602
10057
|
const [dropdownOpen, setDropdownOpen] = useState(false);
|
|
10058
|
+
const [activeIdx, setActiveIdx] = useState(0);
|
|
9603
10059
|
const ellipsisBtnRef = useRef(null);
|
|
9604
10060
|
const dropdownRef = useRef(null);
|
|
10061
|
+
const closeDropdown = useCallback(() => setDropdownOpen(false), []);
|
|
10062
|
+
const { isTop, returnFocus } = usePopupFocus(dropdownOpen, { trigger: ellipsisBtnRef, panel: dropdownRef, close: closeDropdown, tabExits: "any" });
|
|
9605
10063
|
const pos = usePosition(ellipsisBtnRef, dropdownRef, dropdownOpen, { side: "bottom", align: "start", offset: 4, flip: true });
|
|
9606
10064
|
const effectiveMaxItems = maxItems ? Math.max(maxItems, 2) : void 0;
|
|
9607
10065
|
const shouldCollapse = effectiveMaxItems && items.length > effectiveMaxItems;
|
|
@@ -9614,9 +10072,31 @@ var Breadcrumbs = forwardRef(function Breadcrumbs2({
|
|
|
9614
10072
|
if (ellipsisBtnRef.current?.contains(target) || dropdownRef.current?.contains(target)) return;
|
|
9615
10073
|
setDropdownOpen(false);
|
|
9616
10074
|
};
|
|
10075
|
+
const onKeyDown = (e) => {
|
|
10076
|
+
if (e.key !== "Escape" || e.defaultPrevented || !isTop()) return;
|
|
10077
|
+
e.preventDefault();
|
|
10078
|
+
returnFocus();
|
|
10079
|
+
setDropdownOpen(false);
|
|
10080
|
+
};
|
|
9617
10081
|
document.addEventListener("mousedown", handler);
|
|
9618
|
-
|
|
9619
|
-
|
|
10082
|
+
document.addEventListener("keydown", onKeyDown);
|
|
10083
|
+
return () => {
|
|
10084
|
+
document.removeEventListener("mousedown", handler);
|
|
10085
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
10086
|
+
};
|
|
10087
|
+
}, [dropdownOpen, isTop, returnFocus]);
|
|
10088
|
+
useEffect(() => {
|
|
10089
|
+
if (!dropdownOpen) return;
|
|
10090
|
+
const id = requestAnimationFrame(() => dropdownRef.current?.querySelector(`[data-index="${activeIdx}"]`)?.focus());
|
|
10091
|
+
return () => cancelAnimationFrame(id);
|
|
10092
|
+
}, [dropdownOpen, activeIdx]);
|
|
10093
|
+
function onMenuKeyDown(e) {
|
|
10094
|
+
const last = collapsedItems.length - 1;
|
|
10095
|
+
const next = e.key === "ArrowDown" ? activeIdx >= last ? 0 : activeIdx + 1 : e.key === "ArrowUp" ? activeIdx <= 0 ? last : activeIdx - 1 : e.key === "Home" ? 0 : e.key === "End" ? last : null;
|
|
10096
|
+
if (next === null) return;
|
|
10097
|
+
e.preventDefault();
|
|
10098
|
+
setActiveIdx(next);
|
|
10099
|
+
}
|
|
9620
10100
|
const textClass = size === "sm" ? "text-xs" : "text-sm";
|
|
9621
10101
|
const gapClass = size === "sm" ? "gap-ds-1" : "gap-ds-1.5";
|
|
9622
10102
|
const iconSize = size === "sm" ? 12 : 14;
|
|
@@ -9681,7 +10161,10 @@ var Breadcrumbs = forwardRef(function Breadcrumbs2({
|
|
|
9681
10161
|
"button",
|
|
9682
10162
|
{
|
|
9683
10163
|
ref: ellipsisBtnRef,
|
|
9684
|
-
onClick: () =>
|
|
10164
|
+
onClick: () => {
|
|
10165
|
+
if (!dropdownOpen) setActiveIdx(0);
|
|
10166
|
+
setDropdownOpen(!dropdownOpen);
|
|
10167
|
+
},
|
|
9685
10168
|
"aria-label": "Show hidden breadcrumbs",
|
|
9686
10169
|
"aria-expanded": dropdownOpen,
|
|
9687
10170
|
"aria-haspopup": "menu",
|
|
@@ -9712,6 +10195,8 @@ var Breadcrumbs = forwardRef(function Breadcrumbs2({
|
|
|
9712
10195
|
{
|
|
9713
10196
|
ref: dropdownRef,
|
|
9714
10197
|
role: "menu",
|
|
10198
|
+
"aria-label": "Hidden breadcrumbs",
|
|
10199
|
+
onKeyDown: onMenuKeyDown,
|
|
9715
10200
|
className: cn(
|
|
9716
10201
|
"fixed z-[var(--ds-z-popover)] min-w-[160px] max-h-60 overflow-auto",
|
|
9717
10202
|
"bg-[var(--ds-bg-surface-elevated)]",
|
|
@@ -9725,12 +10210,15 @@ var Breadcrumbs = forwardRef(function Breadcrumbs2({
|
|
|
9725
10210
|
children: collapsedItems.map((ci, idx) => /* @__PURE__ */ jsxs(
|
|
9726
10211
|
"button",
|
|
9727
10212
|
{
|
|
10213
|
+
"data-index": idx,
|
|
9728
10214
|
role: "menuitem",
|
|
10215
|
+
tabIndex: idx === activeIdx ? 0 : -1,
|
|
9729
10216
|
className: cn(
|
|
9730
10217
|
"flex items-center w-full text-left text-sm cursor-pointer",
|
|
9731
10218
|
"px-ds-3 py-ds-1.5 transition-colors",
|
|
9732
10219
|
"text-[var(--ds-text-secondary)]",
|
|
9733
10220
|
"hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]",
|
|
10221
|
+
"focus-visible:outline-none focus-visible:bg-[var(--ds-bg-muted)] focus-visible:text-[var(--ds-text-primary)] focus-visible:shadow-[inset_var(--ds-shadow-focus)]",
|
|
9734
10222
|
gapClass
|
|
9735
10223
|
),
|
|
9736
10224
|
onClick: () => {
|
|
@@ -9788,28 +10276,31 @@ function Popover({ open, onOpenChange, trigger, children, side = "bottom", align
|
|
|
9788
10276
|
setTriggerWidth(node?.offsetWidth);
|
|
9789
10277
|
}, []);
|
|
9790
10278
|
const pos = usePosition(triggerRef, floatingRef, open, { side, align, offset: 8, flip: true });
|
|
9791
|
-
const
|
|
9792
|
-
|
|
10279
|
+
const onOpenChangeRef = useLatest(onOpenChange);
|
|
10280
|
+
const { props: pressMarks, marked } = usePressMarks();
|
|
10281
|
+
const { isTop: isTopLayer, returnFocus } = usePopupFocus(open, { trigger: triggerRef, panel: floatingRef, close: () => onOpenChangeRef.current(false), tabExits: "edges", marked });
|
|
9793
10282
|
useEffect(() => {
|
|
9794
10283
|
if (!open) return;
|
|
9795
10284
|
const onKeyDown = (e) => {
|
|
9796
|
-
if (e.key
|
|
9797
|
-
|
|
9798
|
-
|
|
9799
|
-
|
|
10285
|
+
if (e.key !== "Escape" || e.defaultPrevented || !isTopLayer()) return;
|
|
10286
|
+
const active = document.activeElement;
|
|
10287
|
+
if (active && active !== document.body && !triggerRef.current?.contains(active) && !floatingRef.current?.contains(active)) return;
|
|
10288
|
+
e.preventDefault();
|
|
10289
|
+
returnFocus();
|
|
10290
|
+
onOpenChangeRef.current(false);
|
|
9800
10291
|
};
|
|
9801
|
-
const
|
|
10292
|
+
const onPress = (e) => {
|
|
9802
10293
|
const target = e.target;
|
|
9803
|
-
if (triggerRef.current?.contains(target) || floatingRef.current?.contains(target)) return;
|
|
9804
|
-
|
|
10294
|
+
if (marked(e) || triggerRef.current?.contains(target) || floatingRef.current?.contains(target)) return;
|
|
10295
|
+
onOpenChangeRef.current(false);
|
|
9805
10296
|
};
|
|
9806
10297
|
document.addEventListener("keydown", onKeyDown);
|
|
9807
|
-
document.addEventListener("mousedown",
|
|
10298
|
+
document.addEventListener("mousedown", onPress);
|
|
9808
10299
|
return () => {
|
|
9809
10300
|
document.removeEventListener("keydown", onKeyDown);
|
|
9810
|
-
document.removeEventListener("mousedown",
|
|
10301
|
+
document.removeEventListener("mousedown", onPress);
|
|
9811
10302
|
};
|
|
9812
|
-
}, [open,
|
|
10303
|
+
}, [open, onOpenChangeRef, isTopLayer, returnFocus, marked]);
|
|
9813
10304
|
useEffect(() => {
|
|
9814
10305
|
if (open) focusInitial(floatingRef.current);
|
|
9815
10306
|
}, [open]);
|
|
@@ -9831,6 +10322,8 @@ function Popover({ open, onOpenChange, trigger, children, side = "bottom", align
|
|
|
9831
10322
|
{
|
|
9832
10323
|
ref: floatingRef,
|
|
9833
10324
|
"data-gs": "popover",
|
|
10325
|
+
...pressMarks,
|
|
10326
|
+
onClick: (e) => e.stopPropagation(),
|
|
9834
10327
|
className: cn(
|
|
9835
10328
|
"fixed z-[var(--ds-z-popover)]",
|
|
9836
10329
|
"bg-[var(--ds-bg-surface-elevated)]",
|
|
@@ -10045,10 +10538,87 @@ function EllipsisJumper({ totalPages, onPageChange }) {
|
|
|
10045
10538
|
}
|
|
10046
10539
|
);
|
|
10047
10540
|
}
|
|
10541
|
+
var HeaderTabRowContext = createContext(null);
|
|
10542
|
+
function useHeaderTabRow() {
|
|
10543
|
+
return useContext(HeaderTabRowContext);
|
|
10544
|
+
}
|
|
10545
|
+
function useNarrowRow(row) {
|
|
10546
|
+
const [narrow, setNarrow] = useState(false);
|
|
10547
|
+
useLayoutEffect(() => {
|
|
10548
|
+
if (!row) return;
|
|
10549
|
+
const limit = readBreakpointPx("sm");
|
|
10550
|
+
const measure = () => setNarrow(row.clientWidth < limit);
|
|
10551
|
+
measure();
|
|
10552
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
10553
|
+
const ro = new ResizeObserver(measure);
|
|
10554
|
+
ro.observe(row);
|
|
10555
|
+
return () => ro.disconnect();
|
|
10556
|
+
}, [row]);
|
|
10557
|
+
return narrow;
|
|
10558
|
+
}
|
|
10048
10559
|
function Stepper({ steps, currentStep, onStepChange, orientation = "horizontal", className }) {
|
|
10049
10560
|
const isHorizontal = orientation === "horizontal";
|
|
10561
|
+
const tabRow = useHeaderTabRow();
|
|
10562
|
+
const narrow = useNarrowRow(tabRow?.row ?? null);
|
|
10563
|
+
const inHeader = isHorizontal && tabRow != null;
|
|
10564
|
+
if (inHeader && narrow) {
|
|
10565
|
+
const current = steps[currentStep];
|
|
10566
|
+
const where = `Step ${Math.min(currentStep + 1, steps.length)} of ${steps.length}`;
|
|
10567
|
+
return /* @__PURE__ */ jsxs("nav", { "data-gs": "stepper", "aria-label": "Progress", className: cn("mx-ds-1", className), children: [
|
|
10568
|
+
/* @__PURE__ */ jsxs("p", { className: cn("mb-ds-2 text-sm font-medium text-[var(--ds-text-secondary)]", tabRow.hasCaption && "sr-only"), children: [
|
|
10569
|
+
where,
|
|
10570
|
+
current ? /* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
|
|
10571
|
+
": ",
|
|
10572
|
+
current.label
|
|
10573
|
+
] }) : null
|
|
10574
|
+
] }),
|
|
10575
|
+
/* @__PURE__ */ jsx("div", { "aria-hidden": "true", className: "flex gap-ds-1", children: steps.map((step, i) => /* @__PURE__ */ jsx(
|
|
10576
|
+
"div",
|
|
10577
|
+
{
|
|
10578
|
+
className: cn(
|
|
10579
|
+
"h-1.5 flex-1 rounded-[var(--ds-radius-full)] transition-colors",
|
|
10580
|
+
step.status === "error" ? "bg-[var(--ds-status-error)]" : i <= currentStep ? "bg-[var(--ds-accent-primary)]" : "bg-[var(--ds-border-subtle)]"
|
|
10581
|
+
)
|
|
10582
|
+
},
|
|
10583
|
+
i
|
|
10584
|
+
)) })
|
|
10585
|
+
] });
|
|
10586
|
+
}
|
|
10587
|
+
if (inHeader) {
|
|
10588
|
+
return /* @__PURE__ */ jsx("nav", { "data-gs": "stepper", "aria-label": "Progress", className: cn("flex items-start mx-ds-1", className), children: steps.map((step, i) => {
|
|
10589
|
+
const status = step.status ?? (i < currentStep ? "complete" : i === currentStep ? "current" : "upcoming");
|
|
10590
|
+
const isLast = i === steps.length - 1;
|
|
10591
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col items-start min-w-0", isLast ? "flex-none" : "flex-1"), children: [
|
|
10592
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center w-full", children: [
|
|
10593
|
+
/* @__PURE__ */ jsx(StepCircle, { status, index: i, onClick: onStepChange ? () => onStepChange(i) : void 0, clickable: !!onStepChange }),
|
|
10594
|
+
!isLast && /* @__PURE__ */ jsx(
|
|
10595
|
+
"div",
|
|
10596
|
+
{
|
|
10597
|
+
className: cn(
|
|
10598
|
+
"flex-1 h-0.5 mx-ds-2 transition-colors",
|
|
10599
|
+
i < currentStep ? "bg-[var(--ds-accent-primary)]" : "bg-[var(--ds-border-subtle)]"
|
|
10600
|
+
)
|
|
10601
|
+
}
|
|
10602
|
+
)
|
|
10603
|
+
] }),
|
|
10604
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-ds-2 pr-ds-2", children: [
|
|
10605
|
+
/* @__PURE__ */ jsx(
|
|
10606
|
+
"p",
|
|
10607
|
+
{
|
|
10608
|
+
className: cn(
|
|
10609
|
+
"text-xs font-medium",
|
|
10610
|
+
status === "current" ? "text-[var(--ds-accent-primary)]" : "text-[var(--ds-text-primary)]"
|
|
10611
|
+
),
|
|
10612
|
+
children: step.label
|
|
10613
|
+
}
|
|
10614
|
+
),
|
|
10615
|
+
step.description && /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--ds-text-muted)] mt-ds-0.5", children: step.description })
|
|
10616
|
+
] })
|
|
10617
|
+
] }, i);
|
|
10618
|
+
}) });
|
|
10619
|
+
}
|
|
10050
10620
|
if (!isHorizontal) {
|
|
10051
|
-
return /* @__PURE__ */ jsx("nav", { "aria-label": "Progress", className: cn("flex flex-col", className), children: steps.map((step, i) => {
|
|
10621
|
+
return /* @__PURE__ */ jsx("nav", { "data-gs": "stepper", "aria-label": "Progress", className: cn("flex flex-col", className), children: steps.map((step, i) => {
|
|
10052
10622
|
const status = step.status ?? (i < currentStep ? "complete" : i === currentStep ? "current" : "upcoming");
|
|
10053
10623
|
const isLast = i === steps.length - 1;
|
|
10054
10624
|
return /* @__PURE__ */ jsxs("div", { className: "flex gap-ds-3", children: [
|
|
@@ -10083,6 +10653,7 @@ function Stepper({ steps, currentStep, onStepChange, orientation = "horizontal",
|
|
|
10083
10653
|
return /* @__PURE__ */ jsx(
|
|
10084
10654
|
"nav",
|
|
10085
10655
|
{
|
|
10656
|
+
"data-gs": "stepper",
|
|
10086
10657
|
"aria-label": "Progress",
|
|
10087
10658
|
className: cn("flex items-start", className),
|
|
10088
10659
|
children: steps.map((step, i) => {
|
|
@@ -10503,6 +11074,7 @@ function computeCompactFlyoutPos(anchorEl, itemsLength) {
|
|
|
10503
11074
|
return { top: Math.max(8, top), left: rect.right - (FLYOUT_BRIDGE_PX - 4) };
|
|
10504
11075
|
}
|
|
10505
11076
|
function CompactFlyout({
|
|
11077
|
+
id,
|
|
10506
11078
|
parentLabel,
|
|
10507
11079
|
items,
|
|
10508
11080
|
anchorEl,
|
|
@@ -10510,17 +11082,40 @@ function CompactFlyout({
|
|
|
10510
11082
|
onItemClick,
|
|
10511
11083
|
onClose,
|
|
10512
11084
|
onMouseEnter,
|
|
10513
|
-
onMouseLeave
|
|
11085
|
+
onMouseLeave,
|
|
11086
|
+
focusIn = false
|
|
10514
11087
|
}) {
|
|
10515
11088
|
const pos = useMemo(() => computeCompactFlyoutPos(anchorEl, items.length), [anchorEl, items.length]);
|
|
10516
|
-
const
|
|
11089
|
+
const anchorRef = useRef(anchorEl);
|
|
11090
|
+
const panelRef = useRef(null);
|
|
11091
|
+
const headingId = useId();
|
|
11092
|
+
const { isTop: isTopLayer, returnFocus } = usePopupFocus(true, { trigger: anchorRef, panel: panelRef, close: onClose, tabExits: "edges" });
|
|
11093
|
+
useEffect(() => {
|
|
11094
|
+
if (!focusIn) return;
|
|
11095
|
+
const raf = requestAnimationFrame(() => panelRef.current?.querySelector("a[href]")?.focus());
|
|
11096
|
+
return () => cancelAnimationFrame(raf);
|
|
11097
|
+
}, [focusIn]);
|
|
10517
11098
|
useEffect(() => {
|
|
10518
11099
|
function handler(e) {
|
|
10519
|
-
if (e.
|
|
11100
|
+
if (e.defaultPrevented || !isTopLayer()) return;
|
|
11101
|
+
const inside = !!panelRef.current?.contains(document.activeElement);
|
|
11102
|
+
if (e.key === "Escape" || e.key === "ArrowLeft" && inside) {
|
|
11103
|
+
e.preventDefault();
|
|
11104
|
+
if (inside) returnFocus();
|
|
11105
|
+
onClose();
|
|
11106
|
+
} else if (inside && (e.key === "ArrowDown" || e.key === "ArrowUp")) {
|
|
11107
|
+
const links = Array.from(panelRef.current?.querySelectorAll("a[href]") ?? []);
|
|
11108
|
+
const at = links.indexOf(document.activeElement);
|
|
11109
|
+
const next = links[(at + (e.key === "ArrowDown" ? 1 : -1) + links.length) % links.length];
|
|
11110
|
+
if (next) {
|
|
11111
|
+
e.preventDefault();
|
|
11112
|
+
next.focus();
|
|
11113
|
+
}
|
|
11114
|
+
}
|
|
10520
11115
|
}
|
|
10521
11116
|
document.addEventListener("keydown", handler);
|
|
10522
11117
|
return () => document.removeEventListener("keydown", handler);
|
|
10523
|
-
}, [onClose, isTopLayer]);
|
|
11118
|
+
}, [onClose, isTopLayer, returnFocus]);
|
|
10524
11119
|
const content = /* @__PURE__ */ jsx(
|
|
10525
11120
|
"div",
|
|
10526
11121
|
{
|
|
@@ -10531,7 +11126,8 @@ function CompactFlyout({
|
|
|
10531
11126
|
children: /* @__PURE__ */ jsxs(
|
|
10532
11127
|
"div",
|
|
10533
11128
|
{
|
|
10534
|
-
|
|
11129
|
+
ref: panelRef,
|
|
11130
|
+
id,
|
|
10535
11131
|
className: cn(
|
|
10536
11132
|
"min-w-[160px] py-ds-1",
|
|
10537
11133
|
"bg-[var(--ds-sidebar-bg)] rounded-[var(--ds-radius-md)]",
|
|
@@ -10539,12 +11135,11 @@ function CompactFlyout({
|
|
|
10539
11135
|
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]"
|
|
10540
11136
|
),
|
|
10541
11137
|
children: [
|
|
10542
|
-
/* @__PURE__ */ jsx("p", { className: "px-ds-2 pt-ds-1 pb-ds-1.5 text-2xs font-semibold uppercase tracking-wider text-[var(--ds-sidebar-text-muted)]", children: parentLabel }),
|
|
10543
|
-
/* @__PURE__ */ jsx("
|
|
11138
|
+
/* @__PURE__ */ jsx("p", { id: headingId, className: "px-ds-2 pt-ds-1 pb-ds-1.5 text-2xs font-semibold uppercase tracking-wider text-[var(--ds-sidebar-text-muted)]", children: parentLabel }),
|
|
11139
|
+
/* @__PURE__ */ jsx("ul", { "aria-labelledby": headingId, className: "flex flex-col px-ds-1", style: { gap: "var(--ds-space-0\\.5)" }, children: items.map((child, i) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
|
|
10544
11140
|
"a",
|
|
10545
11141
|
{
|
|
10546
11142
|
href: child.href ?? "#",
|
|
10547
|
-
role: "menuitem",
|
|
10548
11143
|
onClick: (e) => {
|
|
10549
11144
|
e.preventDefault();
|
|
10550
11145
|
onItemClick?.(child, i);
|
|
@@ -10559,9 +11154,8 @@ function CompactFlyout({
|
|
|
10559
11154
|
/* @__PURE__ */ jsx(TruncLabel3, { children: child.label }),
|
|
10560
11155
|
child.badge && /* @__PURE__ */ jsx("span", { className: "shrink-0", children: child.badge })
|
|
10561
11156
|
]
|
|
10562
|
-
}
|
|
10563
|
-
|
|
10564
|
-
)) })
|
|
11157
|
+
}
|
|
11158
|
+
) }, child.label)) })
|
|
10565
11159
|
]
|
|
10566
11160
|
}
|
|
10567
11161
|
)
|
|
@@ -10908,6 +11502,9 @@ function CompactNavItem({
|
|
|
10908
11502
|
onToggleExpand
|
|
10909
11503
|
}) {
|
|
10910
11504
|
const [triggerEl, setTriggerEl] = useState(null);
|
|
11505
|
+
const flyoutId = useId();
|
|
11506
|
+
const [keyboardOpen, setKeyboardOpen] = useState(false);
|
|
11507
|
+
if (!isOpen && keyboardOpen) setKeyboardOpen(false);
|
|
10911
11508
|
const handleMouseEnter = useCallback(() => {
|
|
10912
11509
|
onCancelClose();
|
|
10913
11510
|
if (hasChildren && !isOpen) onOpen(flyoutKey);
|
|
@@ -10930,7 +11527,15 @@ function CompactNavItem({
|
|
|
10930
11527
|
onMouseEnter: !mobile && hasChildren ? handleMouseEnter : void 0,
|
|
10931
11528
|
onMouseLeave: !mobile && hasChildren && isOpen ? handleMouseLeave : void 0,
|
|
10932
11529
|
onClick: handleClick,
|
|
11530
|
+
onKeyDown: !mobile && hasChildren ? (e) => {
|
|
11531
|
+
if (e.key !== "ArrowRight") return;
|
|
11532
|
+
e.preventDefault();
|
|
11533
|
+
onCancelClose();
|
|
11534
|
+
setKeyboardOpen(true);
|
|
11535
|
+
onOpen(flyoutKey);
|
|
11536
|
+
} : void 0,
|
|
10933
11537
|
"aria-expanded": hasChildren ? mobile ? expanded : isOpen : void 0,
|
|
11538
|
+
"aria-controls": !mobile && hasChildren && isOpen ? flyoutId : void 0,
|
|
10934
11539
|
className: cn(
|
|
10935
11540
|
"relative flex flex-col items-center justify-center gap-[3px] w-full py-ds-3 px-ds-1 rounded-[var(--ds-radius-md)] transition-colors cursor-pointer",
|
|
10936
11541
|
// Compact tiles have no edge to stroke: they read the fill and text
|
|
@@ -10965,6 +11570,7 @@ function CompactNavItem({
|
|
|
10965
11570
|
!mobile && isOpen && hasChildren && item.children && triggerEl && /* @__PURE__ */ jsx(
|
|
10966
11571
|
CompactFlyout,
|
|
10967
11572
|
{
|
|
11573
|
+
id: flyoutId,
|
|
10968
11574
|
parentLabel: item.label,
|
|
10969
11575
|
items: item.children,
|
|
10970
11576
|
anchorEl: triggerEl,
|
|
@@ -10972,7 +11578,8 @@ function CompactNavItem({
|
|
|
10972
11578
|
onItemClick,
|
|
10973
11579
|
onClose,
|
|
10974
11580
|
onMouseEnter: onCancelClose,
|
|
10975
|
-
onMouseLeave: handleMouseLeave
|
|
11581
|
+
onMouseLeave: handleMouseLeave,
|
|
11582
|
+
focusIn: keyboardOpen
|
|
10976
11583
|
}
|
|
10977
11584
|
),
|
|
10978
11585
|
mobile && expanded && hasChildren && item.children && /* @__PURE__ */ jsx("div", { className: "w-full flex flex-col gap-ds-1 pb-ds-1", children: item.children.map((child, ci) => /* @__PURE__ */ jsxs(
|
|
@@ -11439,6 +12046,35 @@ function BackButton({ onLight, onClick }) {
|
|
|
11439
12046
|
}
|
|
11440
12047
|
);
|
|
11441
12048
|
}
|
|
12049
|
+
function BackLink({ onClick, onLight }) {
|
|
12050
|
+
return /* @__PURE__ */ jsxs(
|
|
12051
|
+
"button",
|
|
12052
|
+
{
|
|
12053
|
+
type: "button",
|
|
12054
|
+
onClick,
|
|
12055
|
+
className: cn(
|
|
12056
|
+
"inline-flex items-center gap-ds-1 mb-ds-3 text-sm underline underline-offset-4 cursor-pointer",
|
|
12057
|
+
"rounded-[var(--ds-radius-sm)] focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
12058
|
+
onLight ? "text-[var(--ds-text-on-primary)]" : "text-[var(--ds-text-primary)] hover:text-[var(--ds-accent-primary)]"
|
|
12059
|
+
),
|
|
12060
|
+
children: [
|
|
12061
|
+
/* @__PURE__ */ jsx(Icon, { name: "chevron-left", size: 14 }),
|
|
12062
|
+
"Back"
|
|
12063
|
+
]
|
|
12064
|
+
}
|
|
12065
|
+
);
|
|
12066
|
+
}
|
|
12067
|
+
function Caption({ children, onLight, onTint }) {
|
|
12068
|
+
return /* @__PURE__ */ jsx("p", { className: cn(
|
|
12069
|
+
"mb-ds-1 text-sm font-medium",
|
|
12070
|
+
onLight ? "text-[var(--ds-text-on-primary)]/80" : onTint ? "text-[var(--ds-text-muted-on-tint)]" : "text-[var(--ds-text-secondary)]"
|
|
12071
|
+
), children });
|
|
12072
|
+
}
|
|
12073
|
+
function TabRow({ children, hasCaption, className, onBand }) {
|
|
12074
|
+
const [row, setRow] = useState(null);
|
|
12075
|
+
const value = useMemo(() => ({ row, hasCaption }), [row, hasCaption]);
|
|
12076
|
+
return /* @__PURE__ */ jsx("div", { ref: setRow, className: cn(className, onBand && "mx-0 rounded-[var(--ds-radius-md)] bg-[var(--ds-bg-surface)] px-ds-3 py-ds-2"), children: /* @__PURE__ */ jsx(HeaderTabRowContext.Provider, { value, children }) });
|
|
12077
|
+
}
|
|
11442
12078
|
var FLOATING_HEADER = cn(
|
|
11443
12079
|
"rounded-[var(--ds-radius-md)]",
|
|
11444
12080
|
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
@@ -11456,9 +12092,10 @@ function computeFloatingPadding(navbarFloating, sidebarFloating, overlapActive,
|
|
|
11456
12092
|
var PageHeader = forwardRef(function PageHeader2({
|
|
11457
12093
|
title,
|
|
11458
12094
|
description,
|
|
12095
|
+
caption,
|
|
11459
12096
|
badge,
|
|
11460
12097
|
breadcrumbs,
|
|
11461
|
-
onBack,
|
|
12098
|
+
onBack: onBackProp,
|
|
11462
12099
|
actions,
|
|
11463
12100
|
avatar,
|
|
11464
12101
|
filters,
|
|
@@ -11517,12 +12154,16 @@ var PageHeader = forwardRef(function PageHeader2({
|
|
|
11517
12154
|
const containedBreadcrumbs = containedBreadcrumbsProp ?? (container?.breadcrumbsInsideHeader && breadcrumbs?.length ? /* @__PURE__ */ jsx(Breadcrumbs, { variant: "contained", itemVariant: r.breadcrumbStyle, bleed: true, contentMaxWidth: gutterWidth, separator: bcSep, items: [...breadcrumbs, { label: title }] }) : void 0);
|
|
11518
12155
|
const noBottomMargin = noBottomMarginProp ?? container?.noBottomMargin;
|
|
11519
12156
|
const overlapActive = container?.overlap ?? false;
|
|
12157
|
+
const focusBack = shell?.focus ? onBackProp : void 0;
|
|
12158
|
+
const onBack = focusBack ? void 0 : onBackProp;
|
|
11520
12159
|
if (behavior === "snapping") {
|
|
11521
12160
|
return /* @__PURE__ */ jsx(
|
|
11522
12161
|
SnappingHeader,
|
|
11523
12162
|
{
|
|
11524
12163
|
title,
|
|
11525
12164
|
description,
|
|
12165
|
+
caption,
|
|
12166
|
+
focusBack,
|
|
11526
12167
|
badge,
|
|
11527
12168
|
breadcrumbs: inlineBreadcrumbs,
|
|
11528
12169
|
onBack,
|
|
@@ -11554,13 +12195,15 @@ var PageHeader = forwardRef(function PageHeader2({
|
|
|
11554
12195
|
}
|
|
11555
12196
|
let header;
|
|
11556
12197
|
if (variant === "minimal") {
|
|
11557
|
-
header = /* @__PURE__ */ jsx(MinimalHeader, { title, badge, breadcrumbs: inlineBreadcrumbs, actions, breadcrumbPill: bcPill, breadcrumbSeparator: bcSep, as: Heading, className, headerRef: floating ? void 0 : ref, isFloating: floating, contentMaxWidth: gutterWidth });
|
|
12198
|
+
header = /* @__PURE__ */ jsx(MinimalHeader, { title, caption, focusBack, badge, breadcrumbs: inlineBreadcrumbs, actions, tabs, breadcrumbPill: bcPill, breadcrumbSeparator: bcSep, as: Heading, className, headerRef: floating ? void 0 : ref, isFloating: floating, contentMaxWidth: gutterWidth });
|
|
11558
12199
|
} else if (variant === "tabs-integrated") {
|
|
11559
12200
|
header = /* @__PURE__ */ jsx(
|
|
11560
12201
|
TabsIntegratedHeader,
|
|
11561
12202
|
{
|
|
11562
12203
|
title,
|
|
11563
12204
|
description,
|
|
12205
|
+
caption,
|
|
12206
|
+
focusBack,
|
|
11564
12207
|
badge,
|
|
11565
12208
|
breadcrumbs: inlineBreadcrumbs,
|
|
11566
12209
|
onBack,
|
|
@@ -11583,6 +12226,9 @@ var PageHeader = forwardRef(function PageHeader2({
|
|
|
11583
12226
|
gutter: !insidePaddedColumn,
|
|
11584
12227
|
title,
|
|
11585
12228
|
description,
|
|
12229
|
+
caption,
|
|
12230
|
+
focusBack,
|
|
12231
|
+
tabs,
|
|
11586
12232
|
badge,
|
|
11587
12233
|
breadcrumbs: inlineBreadcrumbs,
|
|
11588
12234
|
onBack,
|
|
@@ -11608,6 +12254,9 @@ var PageHeader = forwardRef(function PageHeader2({
|
|
|
11608
12254
|
{
|
|
11609
12255
|
title,
|
|
11610
12256
|
description,
|
|
12257
|
+
caption,
|
|
12258
|
+
focusBack,
|
|
12259
|
+
tabs,
|
|
11611
12260
|
badge,
|
|
11612
12261
|
breadcrumbs: inlineBreadcrumbs,
|
|
11613
12262
|
onBack,
|
|
@@ -11648,6 +12297,9 @@ function floatingContentProps(isFloating, contentMaxWidth, extraClassName) {
|
|
|
11648
12297
|
function DefaultHeader({
|
|
11649
12298
|
title,
|
|
11650
12299
|
description,
|
|
12300
|
+
caption,
|
|
12301
|
+
focusBack,
|
|
12302
|
+
tabs,
|
|
11651
12303
|
badge,
|
|
11652
12304
|
breadcrumbs,
|
|
11653
12305
|
onBack,
|
|
@@ -11670,6 +12322,7 @@ function DefaultHeader({
|
|
|
11670
12322
|
return /* @__PURE__ */ jsxs(
|
|
11671
12323
|
"header",
|
|
11672
12324
|
{
|
|
12325
|
+
"data-gs": "page-header",
|
|
11673
12326
|
ref: headerRef,
|
|
11674
12327
|
className: cn(
|
|
11675
12328
|
!hasBanner && (hasBreadcrumbs ? "pt-ds-3 pb-ds-6" : "py-ds-6"),
|
|
@@ -11688,6 +12341,7 @@ function DefaultHeader({
|
|
|
11688
12341
|
children: [
|
|
11689
12342
|
hasBanner && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-[var(--ds-bg-canvas)]/85" }),
|
|
11690
12343
|
/* @__PURE__ */ jsxs("div", { className: inner.className, style: inner.style, children: [
|
|
12344
|
+
focusBack && /* @__PURE__ */ jsx(BackLink, { onClick: focusBack }),
|
|
11691
12345
|
hasBreadcrumbs && /* @__PURE__ */ jsx(Breadcrumbs3, { items: breadcrumbs, pill: breadcrumbPill, separator: breadcrumbSeparator }),
|
|
11692
12346
|
/* @__PURE__ */ jsxs("div", { className: cn(
|
|
11693
12347
|
"flex flex-col @sm:flex-row @sm:items-center justify-between gap-ds-4",
|
|
@@ -11697,6 +12351,7 @@ function DefaultHeader({
|
|
|
11697
12351
|
onBack && /* @__PURE__ */ jsx(BackButton, { onClick: onBack }),
|
|
11698
12352
|
avatar && /* @__PURE__ */ jsx("div", { className: "shrink-0", children: avatar }),
|
|
11699
12353
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
12354
|
+
caption && /* @__PURE__ */ jsx(Caption, { children: caption }),
|
|
11700
12355
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-2", children: [
|
|
11701
12356
|
/* @__PURE__ */ jsx(TruncHeading, { as: Heading, className: "font-[family-name:var(--ds-font-display)] text-3xl font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)]", children: title }),
|
|
11702
12357
|
badge
|
|
@@ -11706,7 +12361,8 @@ function DefaultHeader({
|
|
|
11706
12361
|
] }),
|
|
11707
12362
|
actions && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-ds-2 shrink-0", children: actions })
|
|
11708
12363
|
] }),
|
|
11709
|
-
filters && /* @__PURE__ */ jsx(ControlSizeContext.Provider, { value: "sm", children: /* @__PURE__ */ jsx("div", { className: "flex items-center flex-wrap gap-ds-3 mt-ds-4", children: filters }) })
|
|
12364
|
+
filters && /* @__PURE__ */ jsx(ControlSizeContext.Provider, { value: "sm", children: /* @__PURE__ */ jsx("div", { className: "flex items-center flex-wrap gap-ds-3 mt-ds-4", children: filters }) }),
|
|
12365
|
+
tabs && /* @__PURE__ */ jsx(TabRow, { hasCaption: !!caption, className: "mt-ds-4 -mx-ds-1", children: tabs })
|
|
11710
12366
|
] })
|
|
11711
12367
|
]
|
|
11712
12368
|
}
|
|
@@ -11714,9 +12370,12 @@ function DefaultHeader({
|
|
|
11714
12370
|
}
|
|
11715
12371
|
function MinimalHeader({
|
|
11716
12372
|
title,
|
|
12373
|
+
caption,
|
|
12374
|
+
focusBack,
|
|
11717
12375
|
badge,
|
|
11718
12376
|
breadcrumbs,
|
|
11719
12377
|
actions,
|
|
12378
|
+
tabs,
|
|
11720
12379
|
breadcrumbPill,
|
|
11721
12380
|
breadcrumbSeparator,
|
|
11722
12381
|
as: Heading = "h1",
|
|
@@ -11727,20 +12386,26 @@ function MinimalHeader({
|
|
|
11727
12386
|
}) {
|
|
11728
12387
|
const hasBreadcrumbs = !!(breadcrumbs && breadcrumbs.length > 0);
|
|
11729
12388
|
const inner = floatingContentProps(isFloating, contentMaxWidth);
|
|
11730
|
-
return /* @__PURE__ */ jsx("header", { ref: headerRef, className: cn("py-ds-2", hasBreadcrumbs && "pt-ds-1", isFloating && FLOATING_HEADER, className), children: /* @__PURE__ */ jsxs("div", { className: inner.className, style: inner.style, children: [
|
|
12389
|
+
return /* @__PURE__ */ jsx("header", { "data-gs": "page-header", ref: headerRef, className: cn("py-ds-2", hasBreadcrumbs && "pt-ds-1", tabs && "pb-ds-4", isFloating && FLOATING_HEADER, className), children: /* @__PURE__ */ jsxs("div", { className: inner.className, style: inner.style, children: [
|
|
12390
|
+
focusBack && /* @__PURE__ */ jsx(BackLink, { onClick: focusBack }),
|
|
11731
12391
|
hasBreadcrumbs && /* @__PURE__ */ jsx(Breadcrumbs3, { items: breadcrumbs, pill: breadcrumbPill, separator: breadcrumbSeparator }),
|
|
12392
|
+
caption && /* @__PURE__ */ jsx(Caption, { children: caption }),
|
|
11732
12393
|
/* @__PURE__ */ jsxs("div", { className: cn("flex items-center justify-between gap-ds-4", hasBreadcrumbs && "mt-ds-0.5"), children: [
|
|
11733
12394
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-2 min-w-0", children: [
|
|
11734
12395
|
/* @__PURE__ */ jsx(TruncHeading, { as: Heading, lines: 1, className: "font-[family-name:var(--ds-font-display)] text-xl font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)]", children: title }),
|
|
11735
12396
|
badge
|
|
11736
12397
|
] }),
|
|
11737
12398
|
actions && /* @__PURE__ */ jsx(ControlSizeContext.Provider, { value: "sm", children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-ds-2 shrink-0", children: actions }) })
|
|
11738
|
-
] })
|
|
12399
|
+
] }),
|
|
12400
|
+
tabs && /* @__PURE__ */ jsx(TabRow, { hasCaption: !!caption, className: "mt-ds-3 -mx-ds-1", children: tabs })
|
|
11739
12401
|
] }) });
|
|
11740
12402
|
}
|
|
11741
12403
|
function ColourfulHeader({
|
|
11742
12404
|
title,
|
|
11743
12405
|
description,
|
|
12406
|
+
caption,
|
|
12407
|
+
focusBack,
|
|
12408
|
+
tabs,
|
|
11744
12409
|
badge,
|
|
11745
12410
|
breadcrumbs,
|
|
11746
12411
|
onBack,
|
|
@@ -11765,6 +12430,7 @@ function ColourfulHeader({
|
|
|
11765
12430
|
return /* @__PURE__ */ jsxs(
|
|
11766
12431
|
"header",
|
|
11767
12432
|
{
|
|
12433
|
+
"data-gs": "page-header",
|
|
11768
12434
|
ref: headerRef,
|
|
11769
12435
|
className: cn(
|
|
11770
12436
|
"relative overflow-hidden w-full",
|
|
@@ -11808,6 +12474,7 @@ function ColourfulHeader({
|
|
|
11808
12474
|
...overlapActive ? { paddingBottom: `calc(var(--ds-space-6) + var(--ds-overlap, 0px))` } : {}
|
|
11809
12475
|
},
|
|
11810
12476
|
children: [
|
|
12477
|
+
focusBack && /* @__PURE__ */ jsx(BackLink, { onClick: focusBack, onLight: isBold }),
|
|
11811
12478
|
hasBreadcrumbs && /* @__PURE__ */ jsx(Breadcrumbs3, { items: breadcrumbs, onLight: isBold, onTint: !isBold, pill: breadcrumbPill, separator: breadcrumbSeparator }),
|
|
11812
12479
|
/* @__PURE__ */ jsxs("div", { className: cn(
|
|
11813
12480
|
"flex flex-col @sm:flex-row @sm:items-center justify-between gap-ds-4",
|
|
@@ -11817,6 +12484,7 @@ function ColourfulHeader({
|
|
|
11817
12484
|
onBack && /* @__PURE__ */ jsx(BackButton, { onClick: onBack, onLight: isBold }),
|
|
11818
12485
|
avatar && /* @__PURE__ */ jsx("div", { className: "shrink-0", children: avatar }),
|
|
11819
12486
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
12487
|
+
caption && /* @__PURE__ */ jsx(Caption, { onLight: isBold, onTint: !isBold, children: caption }),
|
|
11820
12488
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-2", children: [
|
|
11821
12489
|
/* @__PURE__ */ jsx(TruncHeading, { as: Heading, className: cn(
|
|
11822
12490
|
"font-[family-name:var(--ds-font-display)] text-3xl font-[var(--ds-weight-heading)]",
|
|
@@ -11832,7 +12500,8 @@ function ColourfulHeader({
|
|
|
11832
12500
|
] }),
|
|
11833
12501
|
actions && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-ds-2 shrink-0", children: actions })
|
|
11834
12502
|
] }),
|
|
11835
|
-
filters && /* @__PURE__ */ jsx(ControlSizeContext.Provider, { value: "sm", children: /* @__PURE__ */ jsx("div", { className: "flex items-center flex-wrap gap-ds-3 mt-ds-4", children: filters }) })
|
|
12503
|
+
filters && /* @__PURE__ */ jsx(ControlSizeContext.Provider, { value: "sm", children: /* @__PURE__ */ jsx("div", { className: "flex items-center flex-wrap gap-ds-3 mt-ds-4", children: filters }) }),
|
|
12504
|
+
tabs && /* @__PURE__ */ jsx(TabRow, { hasCaption: !!caption, className: "mt-ds-4 -mx-ds-1", onBand: isBold, children: tabs })
|
|
11836
12505
|
]
|
|
11837
12506
|
}
|
|
11838
12507
|
)
|
|
@@ -11843,6 +12512,8 @@ function ColourfulHeader({
|
|
|
11843
12512
|
function SnappingHeader({
|
|
11844
12513
|
title,
|
|
11845
12514
|
description,
|
|
12515
|
+
caption,
|
|
12516
|
+
focusBack,
|
|
11846
12517
|
badge,
|
|
11847
12518
|
breadcrumbs,
|
|
11848
12519
|
onBack,
|
|
@@ -11966,6 +12637,7 @@ function SnappingHeader({
|
|
|
11966
12637
|
const headerEl = /* @__PURE__ */ jsxs(
|
|
11967
12638
|
"header",
|
|
11968
12639
|
{
|
|
12640
|
+
"data-gs": "page-header",
|
|
11969
12641
|
ref: !isFloating ? mergedRef : void 0,
|
|
11970
12642
|
className: cn(
|
|
11971
12643
|
"transition-all duration-[var(--ds-transition-speed)] ease-[var(--ds-transition-ease)]",
|
|
@@ -12002,8 +12674,10 @@ function SnappingHeader({
|
|
|
12002
12674
|
onTint && !backgroundImage && /* @__PURE__ */ jsx(TintWash, {}),
|
|
12003
12675
|
(() => {
|
|
12004
12676
|
const hasBreadcrumbs = !!(breadcrumbs && breadcrumbs.length > 0);
|
|
12005
|
-
const innerContent = isMinimal && !collapsed ? /* @__PURE__ */ jsxs("div", { className: cn("py-ds-2", hasBreadcrumbs && !hideExpandedBreadcrumbs && "pt-ds-1"), children: [
|
|
12677
|
+
const innerContent = isMinimal && !collapsed ? /* @__PURE__ */ jsxs("div", { className: cn("py-ds-2", hasBreadcrumbs && !hideExpandedBreadcrumbs && "pt-ds-1", tabs && "pb-ds-4"), children: [
|
|
12678
|
+
focusBack && /* @__PURE__ */ jsx(BackLink, { onClick: focusBack }),
|
|
12006
12679
|
hasBreadcrumbs && !hideExpandedBreadcrumbs && /* @__PURE__ */ jsx(Breadcrumbs3, { items: breadcrumbs, pill: breadcrumbPill, separator: breadcrumbSeparator }),
|
|
12680
|
+
caption && /* @__PURE__ */ jsx(Caption, { children: caption }),
|
|
12007
12681
|
/* @__PURE__ */ jsxs("div", { className: cn("flex items-center justify-between gap-ds-4", hasBreadcrumbs && !hideExpandedBreadcrumbs && "mt-ds-0.5"), children: [
|
|
12008
12682
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-2 min-w-0", children: [
|
|
12009
12683
|
/* @__PURE__ */ jsx(TruncHeading, { as: Heading, className: "font-[family-name:var(--ds-font-display)] text-xl font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)]", children: title }),
|
|
@@ -12013,7 +12687,7 @@ function SnappingHeader({
|
|
|
12013
12687
|
] }),
|
|
12014
12688
|
filters && /* @__PURE__ */ jsx(ControlSizeContext.Provider, { value: "sm", children: /* @__PURE__ */ jsx("div", { className: "flex items-center flex-wrap gap-ds-3 mt-ds-3", children: filters }) }),
|
|
12015
12689
|
expandedContent && /* @__PURE__ */ jsx("div", { className: "mt-ds-3", children: expandedContent }),
|
|
12016
|
-
tabs && /* @__PURE__ */ jsx(
|
|
12690
|
+
tabs && /* @__PURE__ */ jsx(TabRow, { hasCaption: !!caption, className: "mt-ds-3 -mx-ds-1", children: tabs })
|
|
12017
12691
|
] }) : /* @__PURE__ */ jsxs(
|
|
12018
12692
|
"div",
|
|
12019
12693
|
{
|
|
@@ -12027,6 +12701,7 @@ function SnappingHeader({
|
|
|
12027
12701
|
),
|
|
12028
12702
|
style: !collapsed && isColourful && overlapActive ? { paddingBottom: `calc(var(--ds-space-6) + var(--ds-overlap, 0px))` } : void 0,
|
|
12029
12703
|
children: [
|
|
12704
|
+
!collapsed && focusBack && /* @__PURE__ */ jsx(BackLink, { onClick: focusBack, onLight }),
|
|
12030
12705
|
!collapsed && hasBreadcrumbs && !hideExpandedBreadcrumbs && /* @__PURE__ */ jsx(Breadcrumbs3, { items: breadcrumbs, onLight, onTint, pill: breadcrumbPill, separator: breadcrumbSeparator }),
|
|
12031
12706
|
/* @__PURE__ */ jsxs("div", { className: cn(
|
|
12032
12707
|
"flex justify-between gap-ds-4",
|
|
@@ -12038,6 +12713,7 @@ function SnappingHeader({
|
|
|
12038
12713
|
onBack && !collapsed && /* @__PURE__ */ jsx(BackButton, { onClick: onBack, onLight }),
|
|
12039
12714
|
avatar && !collapsed && /* @__PURE__ */ jsx("div", { className: "shrink-0", children: avatar }),
|
|
12040
12715
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
12716
|
+
!collapsed && caption && /* @__PURE__ */ jsx(Caption, { onLight, onTint, children: caption }),
|
|
12041
12717
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-2", children: [
|
|
12042
12718
|
collapsed && hasBreadcrumbs && (() => {
|
|
12043
12719
|
const lastCrumb = breadcrumbs[breadcrumbs.length - 1];
|
|
@@ -12080,7 +12756,7 @@ function SnappingHeader({
|
|
|
12080
12756
|
] }),
|
|
12081
12757
|
!collapsed && filters && /* @__PURE__ */ jsx(ControlSizeContext.Provider, { value: "sm", children: /* @__PURE__ */ jsx("div", { className: "flex items-center flex-wrap gap-ds-3 mt-ds-4", children: filters }) }),
|
|
12082
12758
|
!collapsed && expandedContent && /* @__PURE__ */ jsx("div", { className: "mt-ds-4", children: expandedContent }),
|
|
12083
|
-
!collapsed && tabs && /* @__PURE__ */ jsx(
|
|
12759
|
+
!collapsed && tabs && /* @__PURE__ */ jsx(TabRow, { hasCaption: !!caption, className: "mt-ds-4 -mx-ds-1", onBand: isBoldColourful, children: tabs })
|
|
12084
12760
|
]
|
|
12085
12761
|
}
|
|
12086
12762
|
);
|
|
@@ -12128,6 +12804,8 @@ function SnappingHeader({
|
|
|
12128
12804
|
function TabsIntegratedHeader({
|
|
12129
12805
|
title,
|
|
12130
12806
|
description,
|
|
12807
|
+
caption,
|
|
12808
|
+
focusBack,
|
|
12131
12809
|
badge,
|
|
12132
12810
|
breadcrumbs,
|
|
12133
12811
|
onBack,
|
|
@@ -12144,7 +12822,8 @@ function TabsIntegratedHeader({
|
|
|
12144
12822
|
}) {
|
|
12145
12823
|
const hasBreadcrumbs = !!(breadcrumbs && breadcrumbs.length > 0);
|
|
12146
12824
|
const inner = floatingContentProps(isFloating, contentMaxWidth);
|
|
12147
|
-
return /* @__PURE__ */ jsx("header", { ref: headerRef, className: cn(hasBreadcrumbs ? "pt-ds-3" : "pt-ds-6", "pb-ds-4", isFloating && cn(FLOATING_HEADER, "overflow-hidden"), className), children: /* @__PURE__ */ jsxs("div", { className: inner.className, style: inner.style, children: [
|
|
12825
|
+
return /* @__PURE__ */ jsx("header", { "data-gs": "page-header", ref: headerRef, className: cn(hasBreadcrumbs ? "pt-ds-3" : "pt-ds-6", "pb-ds-4", isFloating && cn(FLOATING_HEADER, "overflow-hidden"), className), children: /* @__PURE__ */ jsxs("div", { className: inner.className, style: inner.style, children: [
|
|
12826
|
+
focusBack && /* @__PURE__ */ jsx(BackLink, { onClick: focusBack }),
|
|
12148
12827
|
hasBreadcrumbs && /* @__PURE__ */ jsx(Breadcrumbs3, { items: breadcrumbs, pill: breadcrumbPill, separator: breadcrumbSeparator }),
|
|
12149
12828
|
/* @__PURE__ */ jsxs("div", { className: cn(
|
|
12150
12829
|
"flex flex-col @sm:flex-row @sm:items-center justify-between gap-ds-4",
|
|
@@ -12154,6 +12833,7 @@ function TabsIntegratedHeader({
|
|
|
12154
12833
|
onBack && /* @__PURE__ */ jsx(BackButton, { onClick: onBack }),
|
|
12155
12834
|
avatar && /* @__PURE__ */ jsx("div", { className: "shrink-0", children: avatar }),
|
|
12156
12835
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
12836
|
+
caption && /* @__PURE__ */ jsx(Caption, { children: caption }),
|
|
12157
12837
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-2", children: [
|
|
12158
12838
|
/* @__PURE__ */ jsx(TruncHeading, { as: Heading, className: "font-[family-name:var(--ds-font-display)] text-3xl font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)]", children: title }),
|
|
12159
12839
|
badge
|
|
@@ -12163,7 +12843,7 @@ function TabsIntegratedHeader({
|
|
|
12163
12843
|
] }),
|
|
12164
12844
|
actions && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-ds-2 shrink-0", children: actions })
|
|
12165
12845
|
] }),
|
|
12166
|
-
tabs && /* @__PURE__ */ jsx(
|
|
12846
|
+
tabs && /* @__PURE__ */ jsx(TabRow, { hasCaption: !!caption, className: "mt-ds-4 -mx-ds-1", children: tabs })
|
|
12167
12847
|
] }) });
|
|
12168
12848
|
}
|
|
12169
12849
|
var DEFAULT_BASE = 48;
|
|
@@ -12326,12 +13006,12 @@ function NavMenu({
|
|
|
12326
13006
|
className
|
|
12327
13007
|
}) {
|
|
12328
13008
|
const [open, setOpen] = useState(false);
|
|
12329
|
-
const isTopLayer = useOverlayLayer(open);
|
|
12330
13009
|
const triggerRef = useRef(null);
|
|
12331
13010
|
const panelRef = useRef(null);
|
|
13011
|
+
const panelId = useId();
|
|
12332
13012
|
const [pos, setPos] = useState({ top: 0, left: 0, minWidth: 0 });
|
|
12333
13013
|
const close = useCallback(() => setOpen(false), []);
|
|
12334
|
-
|
|
13014
|
+
const { isTop: isTopLayer, returnFocus } = usePopupFocus(open, { trigger: triggerRef, panel: panelRef, close, tabExits: "edges" });
|
|
12335
13015
|
useEffect(() => {
|
|
12336
13016
|
if (!open) return;
|
|
12337
13017
|
const id = requestAnimationFrame(() => focusInitial(panelRef.current));
|
|
@@ -12354,10 +13034,10 @@ function NavMenu({
|
|
|
12354
13034
|
}
|
|
12355
13035
|
}
|
|
12356
13036
|
function handleKey(e) {
|
|
12357
|
-
if (e.key
|
|
12358
|
-
|
|
12359
|
-
|
|
12360
|
-
|
|
13037
|
+
if (e.key !== "Escape" || e.defaultPrevented || !isTopLayer()) return;
|
|
13038
|
+
e.preventDefault();
|
|
13039
|
+
returnFocus();
|
|
13040
|
+
close();
|
|
12361
13041
|
}
|
|
12362
13042
|
document.addEventListener("mousedown", handleClick);
|
|
12363
13043
|
document.addEventListener("keydown", handleKey);
|
|
@@ -12365,7 +13045,7 @@ function NavMenu({
|
|
|
12365
13045
|
document.removeEventListener("mousedown", handleClick);
|
|
12366
13046
|
document.removeEventListener("keydown", handleKey);
|
|
12367
13047
|
};
|
|
12368
|
-
}, [open, close, isTopLayer]);
|
|
13048
|
+
}, [open, close, isTopLayer, returnFocus]);
|
|
12369
13049
|
const hasActiveChild = active || items.some(
|
|
12370
13050
|
(it) => it.active || it.children?.some((c) => c.active)
|
|
12371
13051
|
);
|
|
@@ -12399,7 +13079,7 @@ function NavMenu({
|
|
|
12399
13079
|
ref: triggerRef,
|
|
12400
13080
|
onClick: () => setOpen(!open),
|
|
12401
13081
|
"aria-expanded": open,
|
|
12402
|
-
"aria-
|
|
13082
|
+
"aria-controls": open ? panelId : void 0,
|
|
12403
13083
|
className: triggerClasses,
|
|
12404
13084
|
children: [
|
|
12405
13085
|
label,
|
|
@@ -12419,7 +13099,7 @@ function NavMenu({
|
|
|
12419
13099
|
"div",
|
|
12420
13100
|
{
|
|
12421
13101
|
ref: panelRef,
|
|
12422
|
-
|
|
13102
|
+
id: panelId,
|
|
12423
13103
|
"data-gs": "menu",
|
|
12424
13104
|
className: cn(
|
|
12425
13105
|
"fixed z-[var(--ds-z-popover)] py-ds-1.5",
|
|
@@ -12428,7 +13108,7 @@ function NavMenu({
|
|
|
12428
13108
|
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]"
|
|
12429
13109
|
),
|
|
12430
13110
|
style: { top: pos.top, left: pos.left, minWidth: pos.minWidth },
|
|
12431
|
-
children: items.map((item, i) => {
|
|
13111
|
+
children: /* @__PURE__ */ jsx("ul", { children: items.map((item, i) => {
|
|
12432
13112
|
if (item.children?.length) {
|
|
12433
13113
|
return /* @__PURE__ */ jsx(
|
|
12434
13114
|
NavMenuGroup,
|
|
@@ -12454,7 +13134,7 @@ function NavMenu({
|
|
|
12454
13134
|
},
|
|
12455
13135
|
item.label
|
|
12456
13136
|
);
|
|
12457
|
-
})
|
|
13137
|
+
}) })
|
|
12458
13138
|
}
|
|
12459
13139
|
),
|
|
12460
13140
|
document.body
|
|
@@ -12465,11 +13145,10 @@ function NavMenuItemRow({
|
|
|
12465
13145
|
item,
|
|
12466
13146
|
onClick
|
|
12467
13147
|
}) {
|
|
12468
|
-
return /* @__PURE__ */ jsxs(
|
|
13148
|
+
return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
|
|
12469
13149
|
"a",
|
|
12470
13150
|
{
|
|
12471
13151
|
href: item.href ?? "#",
|
|
12472
|
-
role: "menuitem",
|
|
12473
13152
|
onClick: (e) => {
|
|
12474
13153
|
e.preventDefault();
|
|
12475
13154
|
onClick();
|
|
@@ -12495,14 +13174,15 @@ function NavMenuItemRow({
|
|
|
12495
13174
|
] })
|
|
12496
13175
|
]
|
|
12497
13176
|
}
|
|
12498
|
-
);
|
|
13177
|
+
) });
|
|
12499
13178
|
}
|
|
12500
13179
|
function NavMenuGroup({
|
|
12501
13180
|
group,
|
|
12502
13181
|
isFirst,
|
|
12503
13182
|
onItemClick
|
|
12504
13183
|
}) {
|
|
12505
|
-
|
|
13184
|
+
const headingId = useId();
|
|
13185
|
+
return /* @__PURE__ */ jsxs("li", { children: [
|
|
12506
13186
|
!isFirst && /* @__PURE__ */ jsx(
|
|
12507
13187
|
"div",
|
|
12508
13188
|
{
|
|
@@ -12510,15 +13190,15 @@ function NavMenuGroup({
|
|
|
12510
13190
|
style: { height: "var(--ds-divider-width, 1px)", marginTop: "var(--ds-space-1)", marginBottom: "var(--ds-space-1)" }
|
|
12511
13191
|
}
|
|
12512
13192
|
),
|
|
12513
|
-
/* @__PURE__ */ jsx("p", { className: "px-ds-3 pt-ds-1.5 pb-ds-1 text-2xs font-semibold uppercase tracking-wider text-[var(--ds-text-muted)]", children: group.label }),
|
|
12514
|
-
group.children.map((child) => /* @__PURE__ */ jsx(
|
|
13193
|
+
/* @__PURE__ */ jsx("p", { id: headingId, className: "px-ds-3 pt-ds-1.5 pb-ds-1 text-2xs font-semibold uppercase tracking-wider text-[var(--ds-text-muted)]", children: group.label }),
|
|
13194
|
+
/* @__PURE__ */ jsx("ul", { "aria-labelledby": headingId, children: group.children.map((child) => /* @__PURE__ */ jsx(
|
|
12515
13195
|
NavMenuItemRow,
|
|
12516
13196
|
{
|
|
12517
13197
|
item: child,
|
|
12518
13198
|
onClick: () => onItemClick(child)
|
|
12519
13199
|
},
|
|
12520
13200
|
child.label
|
|
12521
|
-
))
|
|
13201
|
+
)) })
|
|
12522
13202
|
] });
|
|
12523
13203
|
}
|
|
12524
13204
|
function resolveNavItemType(type) {
|
|
@@ -12582,64 +13262,234 @@ function getTypeClasses(type, active) {
|
|
|
12582
13262
|
);
|
|
12583
13263
|
}
|
|
12584
13264
|
}
|
|
12585
|
-
|
|
12586
|
-
|
|
12587
|
-
|
|
12588
|
-
|
|
12589
|
-
|
|
12590
|
-
|
|
12591
|
-
|
|
12592
|
-
|
|
12593
|
-
|
|
12594
|
-
|
|
12595
|
-
|
|
12596
|
-
|
|
12597
|
-
|
|
12598
|
-
|
|
12599
|
-
|
|
12600
|
-
|
|
12601
|
-
|
|
12602
|
-
|
|
12603
|
-
);
|
|
12604
|
-
|
|
12605
|
-
|
|
12606
|
-
const
|
|
12607
|
-
|
|
12608
|
-
|
|
12609
|
-
|
|
12610
|
-
|
|
12611
|
-
|
|
12612
|
-
|
|
12613
|
-
}
|
|
12614
|
-
|
|
12615
|
-
|
|
12616
|
-
|
|
12617
|
-
|
|
12618
|
-
|
|
12619
|
-
|
|
12620
|
-
|
|
12621
|
-
|
|
12622
|
-
|
|
12623
|
-
|
|
12624
|
-
|
|
12625
|
-
|
|
12626
|
-
|
|
12627
|
-
|
|
12628
|
-
|
|
12629
|
-
|
|
12630
|
-
|
|
12631
|
-
|
|
12632
|
-
|
|
12633
|
-
|
|
12634
|
-
|
|
12635
|
-
|
|
12636
|
-
|
|
12637
|
-
|
|
12638
|
-
|
|
13265
|
+
var DEFAULT_BUTTON_ATTR = "data-dialog-default-button";
|
|
13266
|
+
var sizeClasses = {
|
|
13267
|
+
// round 16 (the owner's item 5): the small dialog is 448 px, not 384 — a delete confirmation with a typed field was cramped
|
|
13268
|
+
sm: "max-w-md",
|
|
13269
|
+
md: "max-w-lg",
|
|
13270
|
+
lg: "max-w-2xl",
|
|
13271
|
+
xl: "max-w-4xl",
|
|
13272
|
+
full: "max-w-[calc(100vw-2rem)]"
|
|
13273
|
+
};
|
|
13274
|
+
function Dialog({ open, onClose: onCloseProp, title, description, children, footer, variant = "default", size = "md", alert = false, container, onSubmit, dirty, onDiscard }) {
|
|
13275
|
+
const guard = useDirtyGuard(dirty, onCloseProp, onDiscard);
|
|
13276
|
+
const onClose = guard.requestClose;
|
|
13277
|
+
const titleId = useId();
|
|
13278
|
+
const descriptionId = useId();
|
|
13279
|
+
const isMobile = useBreakpoint("sm");
|
|
13280
|
+
const overlayRef = useRef(null);
|
|
13281
|
+
const dialogRef = useRef(null);
|
|
13282
|
+
const opener = useRef(null);
|
|
13283
|
+
const defaultButtonRef = useRef(null);
|
|
13284
|
+
const onCloseRef = useLatest(onClose);
|
|
13285
|
+
const onSubmitRef = useLatest(onSubmit);
|
|
13286
|
+
const isTopLayer = useOverlayLayer(open);
|
|
13287
|
+
useFocusTrap(dialogRef, open, isTopLayer);
|
|
13288
|
+
const before = useFocusBeforeOpen(open);
|
|
13289
|
+
useEffect(() => {
|
|
13290
|
+
if (!open) return;
|
|
13291
|
+
const active = before.current;
|
|
13292
|
+
opener.current = active instanceof HTMLElement && active !== document.body && active.isConnected ? rememberFocus(active) : null;
|
|
13293
|
+
}, [open, before]);
|
|
13294
|
+
useEffect(() => {
|
|
13295
|
+
if (!open) return;
|
|
13296
|
+
requestAnimationFrame(() => {
|
|
13297
|
+
focusInitial(dialogRef.current, { destructive: variant === "destructive" });
|
|
13298
|
+
});
|
|
13299
|
+
}, [open, variant]);
|
|
13300
|
+
useEffect(() => {
|
|
13301
|
+
if (!open) return;
|
|
13302
|
+
const handler = (e) => {
|
|
13303
|
+
if (e.key !== "Escape" || e.defaultPrevented || !isTopLayer()) return;
|
|
13304
|
+
e.preventDefault();
|
|
13305
|
+
onCloseRef.current();
|
|
13306
|
+
};
|
|
13307
|
+
document.addEventListener("keydown", handler);
|
|
13308
|
+
return () => {
|
|
13309
|
+
document.removeEventListener("keydown", handler);
|
|
13310
|
+
};
|
|
13311
|
+
}, [open, onCloseRef, isTopLayer]);
|
|
13312
|
+
useEffect(() => {
|
|
13313
|
+
if (!open) return;
|
|
13314
|
+
lockBodyScroll();
|
|
13315
|
+
return () => {
|
|
13316
|
+
unlockBodyScroll();
|
|
13317
|
+
const r = opener.current;
|
|
13318
|
+
opener.current = null;
|
|
13319
|
+
const active = document.activeElement;
|
|
13320
|
+
if (!active || active === document.body || !active.isConnected) r?.restore();
|
|
13321
|
+
};
|
|
13322
|
+
}, [open]);
|
|
13323
|
+
if (!open) return null;
|
|
13324
|
+
return createPortal(
|
|
13325
|
+
/* @__PURE__ */ jsxs(
|
|
13326
|
+
"div",
|
|
13327
|
+
{
|
|
13328
|
+
ref: overlayRef,
|
|
13329
|
+
className: "fixed inset-0 z-[var(--ds-z-modal)] flex items-center justify-center p-ds-4",
|
|
13330
|
+
children: [
|
|
13331
|
+
/* @__PURE__ */ jsx(
|
|
13332
|
+
"div",
|
|
13333
|
+
{
|
|
13334
|
+
className: "fixed inset-0 bg-black/50 [backdrop-filter:blur(calc(var(--ds-glass-blur)*0.3))] [-webkit-backdrop-filter:blur(calc(var(--ds-glass-blur)*0.3))]",
|
|
13335
|
+
onClick: alert ? void 0 : onClose,
|
|
13336
|
+
"aria-hidden": "true"
|
|
13337
|
+
}
|
|
13338
|
+
),
|
|
13339
|
+
/* @__PURE__ */ jsxs(
|
|
13340
|
+
"form",
|
|
13341
|
+
{
|
|
13342
|
+
onSubmit: (e) => {
|
|
13343
|
+
e.preventDefault();
|
|
13344
|
+
if (variant === "destructive") return;
|
|
13345
|
+
const submitter = e.nativeEvent.submitter;
|
|
13346
|
+
const implicit = !submitter || submitter === defaultButtonRef.current;
|
|
13347
|
+
if (!implicit && submitter.getAttribute("type") !== "submit") return;
|
|
13348
|
+
if (implicit) {
|
|
13349
|
+
const explicit = e.currentTarget.querySelector(`button[type="submit"]:not([${DEFAULT_BUTTON_ATTR}])`);
|
|
13350
|
+
if (explicit?.disabled) return;
|
|
13351
|
+
}
|
|
13352
|
+
onSubmitRef.current?.();
|
|
13353
|
+
},
|
|
13354
|
+
className: "contents",
|
|
13355
|
+
children: [
|
|
13356
|
+
/* @__PURE__ */ jsx(
|
|
13357
|
+
"button",
|
|
13358
|
+
{
|
|
13359
|
+
ref: defaultButtonRef,
|
|
13360
|
+
type: "submit",
|
|
13361
|
+
tabIndex: -1,
|
|
13362
|
+
"aria-hidden": "true",
|
|
13363
|
+
className: "sr-only",
|
|
13364
|
+
...{ [DEFAULT_BUTTON_ATTR]: "" }
|
|
13365
|
+
}
|
|
13366
|
+
),
|
|
13367
|
+
/* @__PURE__ */ jsxs(
|
|
13368
|
+
"div",
|
|
13369
|
+
{
|
|
13370
|
+
ref: dialogRef,
|
|
13371
|
+
role: alert ? "alertdialog" : "dialog",
|
|
13372
|
+
"aria-modal": "true",
|
|
13373
|
+
"data-gs": "dialog",
|
|
13374
|
+
"aria-labelledby": titleId,
|
|
13375
|
+
"aria-describedby": description ? descriptionId : void 0,
|
|
13376
|
+
style: { containerType: "inline-size" },
|
|
13377
|
+
className: cn(
|
|
13378
|
+
"relative z-10 w-full",
|
|
13379
|
+
isMobile ? "max-w-none h-full" : sizeClasses[size],
|
|
13380
|
+
"bg-[var(--ds-bg-surface)] text-[var(--ds-text-primary)]",
|
|
13381
|
+
GLASS_OVERLAY,
|
|
13382
|
+
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
13383
|
+
isMobile ? "rounded-none" : "rounded-[var(--ds-radius-xl)]",
|
|
13384
|
+
"overflow-hidden",
|
|
13385
|
+
"animate-in fade-in-0 zoom-in-95"
|
|
13386
|
+
),
|
|
13387
|
+
children: [
|
|
13388
|
+
/* @__PURE__ */ jsx(
|
|
13389
|
+
"button",
|
|
13390
|
+
{
|
|
13391
|
+
type: "button",
|
|
13392
|
+
onClick: onClose,
|
|
13393
|
+
...{ [OVERLAY_CLOSE_ATTR]: "" },
|
|
13394
|
+
className: "absolute right-4 top-4 text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer",
|
|
13395
|
+
"aria-label": "Close",
|
|
13396
|
+
children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 18 })
|
|
13397
|
+
}
|
|
13398
|
+
),
|
|
13399
|
+
/* @__PURE__ */ jsx("div", { className: "p-ds-6", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-ds-3", children: [
|
|
13400
|
+
variant === "destructive" && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center shrink-0 w-10 h-10 rounded-[var(--ds-radius-full)] bg-[var(--ds-status-error-bg)]", children: /* @__PURE__ */ jsx(Icon, { name: "warning", size: 20, className: "text-[var(--ds-status-error)]" }) }),
|
|
13401
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
13402
|
+
/* @__PURE__ */ jsx(
|
|
13403
|
+
"h2",
|
|
13404
|
+
{
|
|
13405
|
+
id: titleId,
|
|
13406
|
+
className: "font-[family-name:var(--ds-font-display)] text-lg font-[var(--ds-weight-heading)] leading-none tracking-tight",
|
|
13407
|
+
children: title
|
|
13408
|
+
}
|
|
13409
|
+
),
|
|
13410
|
+
description && /* @__PURE__ */ jsx("p", { id: descriptionId, className: "mt-ds-2 text-sm text-[var(--ds-text-muted)]", children: description }),
|
|
13411
|
+
children && /* @__PURE__ */ jsx("div", { className: "mt-ds-4", children: /* @__PURE__ */ jsx(OverlayCloseCtx, { value: onClose, children }) })
|
|
13412
|
+
] })
|
|
13413
|
+
] }) }),
|
|
13414
|
+
/* @__PURE__ */ jsx(DiscardConfirm, { open: guard.confirming, onKeep: guard.keep, onDiscard: guard.discard }),
|
|
13415
|
+
footer && /* @__PURE__ */ jsx("div", { className: cn(
|
|
13416
|
+
"flex justify-end gap-ds-2 p-ds-4",
|
|
13417
|
+
"border-t-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
|
|
13418
|
+
"bg-[var(--ds-bg-muted)]",
|
|
13419
|
+
"rounded-b-[var(--ds-radius-xl)]"
|
|
13420
|
+
), children: footer })
|
|
13421
|
+
]
|
|
13422
|
+
}
|
|
13423
|
+
)
|
|
13424
|
+
]
|
|
13425
|
+
}
|
|
13426
|
+
)
|
|
13427
|
+
]
|
|
13428
|
+
}
|
|
13429
|
+
),
|
|
13430
|
+
container ?? document.body
|
|
13431
|
+
);
|
|
13432
|
+
}
|
|
13433
|
+
function HamburgerButton({ onClick, open, className: cls }) {
|
|
13434
|
+
return /* @__PURE__ */ jsx(
|
|
13435
|
+
"button",
|
|
13436
|
+
{
|
|
13437
|
+
onClick,
|
|
13438
|
+
"aria-label": open ? "Close navigation menu" : "Open navigation menu",
|
|
13439
|
+
"aria-expanded": open ?? void 0,
|
|
13440
|
+
className: cn(
|
|
13441
|
+
"flex items-center justify-center shrink-0",
|
|
13442
|
+
"w-10 h-10 rounded-[var(--ds-radius-md)]",
|
|
13443
|
+
"text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)]",
|
|
13444
|
+
"hover:bg-[var(--ds-bg-muted)] transition-colors",
|
|
13445
|
+
"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
13446
|
+
"cursor-pointer",
|
|
13447
|
+
cls
|
|
13448
|
+
),
|
|
13449
|
+
children: /* @__PURE__ */ jsx(Icon, { name: open ? "close" : "menu", size: 20 })
|
|
13450
|
+
}
|
|
13451
|
+
);
|
|
13452
|
+
}
|
|
13453
|
+
function flattenLinks(node) {
|
|
13454
|
+
const out = [];
|
|
13455
|
+
Children.forEach(node, (child) => {
|
|
13456
|
+
if (!isValidElement(child)) return;
|
|
13457
|
+
if (child.type === Fragment$1) out.push(...flattenLinks(child.props.children));
|
|
13458
|
+
else out.push(child);
|
|
13459
|
+
});
|
|
13460
|
+
return out;
|
|
13461
|
+
}
|
|
13462
|
+
var Navbar = forwardRef(function Navbar2({
|
|
13463
|
+
logo,
|
|
13464
|
+
navLinks,
|
|
13465
|
+
search,
|
|
13466
|
+
actions,
|
|
13467
|
+
userMenu,
|
|
13468
|
+
variant = "default",
|
|
13469
|
+
type: typeProp = "tint",
|
|
13470
|
+
align = "left",
|
|
13471
|
+
size,
|
|
13472
|
+
position = "flush",
|
|
13473
|
+
bordered,
|
|
13474
|
+
sticky = true,
|
|
13475
|
+
className,
|
|
13476
|
+
onMenuClick
|
|
13477
|
+
}, ref) {
|
|
13478
|
+
const appShell = useAppShell();
|
|
13479
|
+
useLayoutEffect(() => appShell?.registerChrome("navbar", position), [appShell?.registerChrome, position]);
|
|
13480
|
+
const isSmallPhone = appShell?.isMobile && !appShell.isTablet;
|
|
13481
|
+
const headerRef = useRef(null);
|
|
13482
|
+
const navRef = useRef(null);
|
|
13483
|
+
const widthsRef = useRef([]);
|
|
13484
|
+
const moreWidthRef = useRef(88);
|
|
13485
|
+
const [visibleCount, setVisibleCount] = useState(null);
|
|
13486
|
+
const links = useMemo(() => flattenLinks(navLinks), [navLinks]);
|
|
12639
13487
|
const mobileHidesLinks = !!appShell?.isMobile && (appShell.hasMobileMenu || appShell.hasMobileNav);
|
|
13488
|
+
const focus = appShell?.focus ?? null;
|
|
13489
|
+
const [confirmExit, setConfirmExit] = useState(false);
|
|
12640
13490
|
useEffect(() => {
|
|
12641
13491
|
const header = headerRef.current;
|
|
12642
|
-
if (!header || mobileHidesLinks || links.length === 0 || typeof ResizeObserver === "undefined") return;
|
|
13492
|
+
if (!header || mobileHidesLinks || focus || links.length === 0 || typeof ResizeObserver === "undefined") return;
|
|
12643
13493
|
const measure = () => {
|
|
12644
13494
|
const nav = navRef.current;
|
|
12645
13495
|
if (!nav) return;
|
|
@@ -12676,7 +13526,7 @@ var Navbar = forwardRef(function Navbar2({
|
|
|
12676
13526
|
const ro = new ResizeObserver(measure);
|
|
12677
13527
|
ro.observe(header);
|
|
12678
13528
|
return () => ro.disconnect();
|
|
12679
|
-
}, [mobileHidesLinks, links]);
|
|
13529
|
+
}, [mobileHidesLinks, focus, links]);
|
|
12680
13530
|
const [topInset, setTopInset] = useState(null);
|
|
12681
13531
|
const shellEl = appShell?.container ?? null;
|
|
12682
13532
|
useLayoutEffect(() => {
|
|
@@ -12708,7 +13558,40 @@ var Navbar = forwardRef(function Navbar2({
|
|
|
12708
13558
|
}, [visibleCount, links]);
|
|
12709
13559
|
const showHamburger = appShell?.isMobile && appShell.hasMobileMenu && !(isSmallPhone && appShell.hasMobileNav) || !!onMenuClick;
|
|
12710
13560
|
const handleHamburger = () => onMenuClick ? onMenuClick() : appShell?.setSidebarOpen(!appShell.sidebarOpen);
|
|
12711
|
-
const hideNavLinks = mobileHidesLinks;
|
|
13561
|
+
const hideNavLinks = mobileHidesLinks || !!focus;
|
|
13562
|
+
const shownSearch = focus ? null : search;
|
|
13563
|
+
const requestExit = () => {
|
|
13564
|
+
if (!focus) return;
|
|
13565
|
+
if (focus.kind === "in-app" && appShell?.hasUnsavedChanges) {
|
|
13566
|
+
setConfirmExit(true);
|
|
13567
|
+
return;
|
|
13568
|
+
}
|
|
13569
|
+
focus.onExit?.();
|
|
13570
|
+
};
|
|
13571
|
+
const exitControl = focus ? /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "sm", onClick: requestExit, children: focus.exitLabel ?? (focus.kind === "before-app" ? "Save and log out" : "Exit") }) : null;
|
|
13572
|
+
const shownUserMenu = focus?.kind === "before-app" ? null : userMenu;
|
|
13573
|
+
const asking = confirmExit && focus?.kind === "in-app" && !!appShell?.hasUnsavedChanges;
|
|
13574
|
+
if (confirmExit && !asking) setConfirmExit(false);
|
|
13575
|
+
const exitDialog = focus?.kind === "in-app" ? /* @__PURE__ */ jsx(
|
|
13576
|
+
Dialog,
|
|
13577
|
+
{
|
|
13578
|
+
open: asking,
|
|
13579
|
+
onClose: () => setConfirmExit(false),
|
|
13580
|
+
title: "You have unsaved changes",
|
|
13581
|
+
description: "Exit now and your changes are lost.",
|
|
13582
|
+
variant: "destructive",
|
|
13583
|
+
size: "sm",
|
|
13584
|
+
alert: true,
|
|
13585
|
+
container: shellEl ?? void 0,
|
|
13586
|
+
footer: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
13587
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => setConfirmExit(false), children: "Keep editing" }),
|
|
13588
|
+
/* @__PURE__ */ jsx(Button, { variant: "destructive", onClick: () => {
|
|
13589
|
+
setConfirmExit(false);
|
|
13590
|
+
focus.onExit?.();
|
|
13591
|
+
}, children: "Discard changes" })
|
|
13592
|
+
] })
|
|
13593
|
+
}
|
|
13594
|
+
) : null;
|
|
12712
13595
|
const type = resolveNavItemType(typeProp);
|
|
12713
13596
|
const isMinimal = type === "minimal";
|
|
12714
13597
|
const isFloating = position === "floating";
|
|
@@ -12774,9 +13657,10 @@ var Navbar = forwardRef(function Navbar2({
|
|
|
12774
13657
|
] }),
|
|
12775
13658
|
navLinks && !hideNavLinks ? /* @__PURE__ */ jsx(NavbarTypeContext.Provider, { value: type, children: /* @__PURE__ */ jsx("nav", { ref: navRef, className: "flex items-center gap-ds-2 min-w-0 overflow-x-clip justify-center", "data-navbar-type": type, children: linkRow }) }) : /* @__PURE__ */ jsx("div", { "data-navbar-spacer": "" }),
|
|
12776
13659
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-4 justify-end", children: [
|
|
12777
|
-
|
|
13660
|
+
shownSearch && /* @__PURE__ */ jsx("div", { className: "flex items-center shrink-0", children: shownSearch }),
|
|
12778
13661
|
actions && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-ds-2 shrink-0", children: actions }),
|
|
12779
|
-
|
|
13662
|
+
exitControl && /* @__PURE__ */ jsx("div", { className: "flex items-center shrink-0", children: exitControl }),
|
|
13663
|
+
shownUserMenu && /* @__PURE__ */ jsx("div", { className: cn("flex items-center", resolvedSize === "sm" ? "min-w-0 max-w-[180px]" : "shrink-0"), children: shownUserMenu })
|
|
12780
13664
|
] })
|
|
12781
13665
|
]
|
|
12782
13666
|
}
|
|
@@ -12801,15 +13685,16 @@ var Navbar = forwardRef(function Navbar2({
|
|
|
12801
13685
|
align === "right" && /* @__PURE__ */ jsx("div", { "data-navbar-spacer": "", className: "flex-1" }),
|
|
12802
13686
|
navLinks && !hideNavLinks && /* @__PURE__ */ jsx(NavbarTypeContext.Provider, { value: type, children: /* @__PURE__ */ jsx("nav", { ref: navRef, className: cn("flex items-center gap-ds-2 min-w-0 overflow-x-clip", align === "left" && "flex-1"), "data-navbar-type": type, children: linkRow }) }),
|
|
12803
13687
|
(!navLinks || hideNavLinks) && /* @__PURE__ */ jsx("div", { "data-navbar-spacer": "", className: "flex-1" }),
|
|
12804
|
-
|
|
13688
|
+
shownSearch && /* @__PURE__ */ jsx("div", { className: "flex items-center shrink-0", children: shownSearch }),
|
|
12805
13689
|
actions && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-ds-2 shrink-0", children: actions }),
|
|
12806
|
-
|
|
13690
|
+
exitControl && /* @__PURE__ */ jsx("div", { className: "flex items-center shrink-0", children: exitControl }),
|
|
13691
|
+
shownUserMenu && /* @__PURE__ */ jsx("div", { className: cn("flex items-center", resolvedSize === "sm" ? "min-w-0 max-w-[180px]" : "shrink-0"), children: shownUserMenu })
|
|
12807
13692
|
]
|
|
12808
13693
|
}
|
|
12809
13694
|
);
|
|
12810
13695
|
}
|
|
12811
13696
|
if (isFloating) {
|
|
12812
|
-
return /* @__PURE__ */
|
|
13697
|
+
return /* @__PURE__ */ jsxs(
|
|
12813
13698
|
"div",
|
|
12814
13699
|
{
|
|
12815
13700
|
ref,
|
|
@@ -12819,11 +13704,17 @@ var Navbar = forwardRef(function Navbar2({
|
|
|
12819
13704
|
className
|
|
12820
13705
|
),
|
|
12821
13706
|
style: { padding: "var(--ds-space-3)" },
|
|
12822
|
-
children:
|
|
13707
|
+
children: [
|
|
13708
|
+
headerEl,
|
|
13709
|
+
exitDialog
|
|
13710
|
+
]
|
|
12823
13711
|
}
|
|
12824
13712
|
);
|
|
12825
13713
|
}
|
|
12826
|
-
return
|
|
13714
|
+
return exitDialog ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
13715
|
+
headerEl,
|
|
13716
|
+
exitDialog
|
|
13717
|
+
] }) : headerEl;
|
|
12827
13718
|
});
|
|
12828
13719
|
function MobileHeaderMenu({ items, type = "tint", onItemClick, className }) {
|
|
12829
13720
|
return /* @__PURE__ */ jsx("nav", { className: cn("flex flex-col", className), style: { padding: "var(--ds-space-4)" }, children: /* @__PURE__ */ jsx("div", { className: "flex flex-col", style: { gap: type === "underline" ? 0 : "var(--ds-space-1)" }, children: items.map((item, i) => /* @__PURE__ */ jsx(
|
|
@@ -12915,169 +13806,12 @@ function MobileMenuItem({
|
|
|
12915
13806
|
}
|
|
12916
13807
|
);
|
|
12917
13808
|
}
|
|
12918
|
-
var DEFAULT_BUTTON_ATTR = "data-dialog-default-button";
|
|
12919
|
-
var sizeClasses = {
|
|
12920
|
-
// round 16 (the owner's item 5): the small dialog is 448 px, not 384 — a delete confirmation with a typed field was cramped
|
|
12921
|
-
sm: "max-w-md",
|
|
12922
|
-
md: "max-w-lg",
|
|
12923
|
-
lg: "max-w-2xl",
|
|
12924
|
-
xl: "max-w-4xl",
|
|
12925
|
-
full: "max-w-[calc(100vw-2rem)]"
|
|
12926
|
-
};
|
|
12927
|
-
function Dialog({ open, onClose: onCloseProp, title, description, children, footer, variant = "default", size = "md", alert = false, container, onSubmit, dirty, onDiscard }) {
|
|
12928
|
-
const guard = useDirtyGuard(dirty, onCloseProp, onDiscard);
|
|
12929
|
-
const onClose = guard.requestClose;
|
|
12930
|
-
const titleId = useId();
|
|
12931
|
-
const descriptionId = useId();
|
|
12932
|
-
const isMobile = useBreakpoint("sm");
|
|
12933
|
-
const overlayRef = useRef(null);
|
|
12934
|
-
const dialogRef = useRef(null);
|
|
12935
|
-
const triggerRef = useRef(null);
|
|
12936
|
-
const defaultButtonRef = useRef(null);
|
|
12937
|
-
const onCloseRef = useLatest(onClose);
|
|
12938
|
-
const onSubmitRef = useLatest(onSubmit);
|
|
12939
|
-
const isTopLayer = useOverlayLayer(open);
|
|
12940
|
-
useFocusTrap(dialogRef, open, isTopLayer);
|
|
12941
|
-
useEffect(() => {
|
|
12942
|
-
if (!open) return;
|
|
12943
|
-
triggerRef.current = document.activeElement;
|
|
12944
|
-
requestAnimationFrame(() => {
|
|
12945
|
-
focusInitial(dialogRef.current, { destructive: variant === "destructive" });
|
|
12946
|
-
});
|
|
12947
|
-
}, [open, variant]);
|
|
12948
|
-
useEffect(() => {
|
|
12949
|
-
if (!open) return;
|
|
12950
|
-
const handler = (e) => {
|
|
12951
|
-
if (e.key === "Escape" && !alert && isTopLayer()) onCloseRef.current();
|
|
12952
|
-
};
|
|
12953
|
-
document.addEventListener("keydown", handler);
|
|
12954
|
-
return () => {
|
|
12955
|
-
document.removeEventListener("keydown", handler);
|
|
12956
|
-
};
|
|
12957
|
-
}, [open, alert, onCloseRef, isTopLayer]);
|
|
12958
|
-
useEffect(() => {
|
|
12959
|
-
if (!open) return;
|
|
12960
|
-
lockBodyScroll();
|
|
12961
|
-
return () => {
|
|
12962
|
-
unlockBodyScroll();
|
|
12963
|
-
triggerRef.current?.focus();
|
|
12964
|
-
};
|
|
12965
|
-
}, [open]);
|
|
12966
|
-
if (!open) return null;
|
|
12967
|
-
return createPortal(
|
|
12968
|
-
/* @__PURE__ */ jsxs(
|
|
12969
|
-
"div",
|
|
12970
|
-
{
|
|
12971
|
-
ref: overlayRef,
|
|
12972
|
-
className: "fixed inset-0 z-[var(--ds-z-modal)] flex items-center justify-center p-ds-4",
|
|
12973
|
-
children: [
|
|
12974
|
-
/* @__PURE__ */ jsx(
|
|
12975
|
-
"div",
|
|
12976
|
-
{
|
|
12977
|
-
className: "fixed inset-0 bg-black/50 [backdrop-filter:blur(calc(var(--ds-glass-blur)*0.3))] [-webkit-backdrop-filter:blur(calc(var(--ds-glass-blur)*0.3))]",
|
|
12978
|
-
onClick: alert ? void 0 : onClose,
|
|
12979
|
-
"aria-hidden": "true"
|
|
12980
|
-
}
|
|
12981
|
-
),
|
|
12982
|
-
/* @__PURE__ */ jsxs(
|
|
12983
|
-
"form",
|
|
12984
|
-
{
|
|
12985
|
-
onSubmit: (e) => {
|
|
12986
|
-
e.preventDefault();
|
|
12987
|
-
if (variant === "destructive") return;
|
|
12988
|
-
const submitter = e.nativeEvent.submitter;
|
|
12989
|
-
const implicit = !submitter || submitter === defaultButtonRef.current;
|
|
12990
|
-
if (!implicit && submitter.getAttribute("type") !== "submit") return;
|
|
12991
|
-
if (implicit) {
|
|
12992
|
-
const explicit = e.currentTarget.querySelector(`button[type="submit"]:not([${DEFAULT_BUTTON_ATTR}])`);
|
|
12993
|
-
if (explicit?.disabled) return;
|
|
12994
|
-
}
|
|
12995
|
-
onSubmitRef.current?.();
|
|
12996
|
-
},
|
|
12997
|
-
className: "contents",
|
|
12998
|
-
children: [
|
|
12999
|
-
/* @__PURE__ */ jsx(
|
|
13000
|
-
"button",
|
|
13001
|
-
{
|
|
13002
|
-
ref: defaultButtonRef,
|
|
13003
|
-
type: "submit",
|
|
13004
|
-
tabIndex: -1,
|
|
13005
|
-
"aria-hidden": "true",
|
|
13006
|
-
className: "sr-only",
|
|
13007
|
-
...{ [DEFAULT_BUTTON_ATTR]: "" }
|
|
13008
|
-
}
|
|
13009
|
-
),
|
|
13010
|
-
/* @__PURE__ */ jsxs(
|
|
13011
|
-
"div",
|
|
13012
|
-
{
|
|
13013
|
-
ref: dialogRef,
|
|
13014
|
-
role: alert ? "alertdialog" : "dialog",
|
|
13015
|
-
"aria-modal": "true",
|
|
13016
|
-
"data-gs": "dialog",
|
|
13017
|
-
"aria-labelledby": titleId,
|
|
13018
|
-
"aria-describedby": description ? descriptionId : void 0,
|
|
13019
|
-
style: { containerType: "inline-size" },
|
|
13020
|
-
className: cn(
|
|
13021
|
-
"relative z-10 w-full",
|
|
13022
|
-
isMobile ? "max-w-none h-full" : sizeClasses[size],
|
|
13023
|
-
"bg-[var(--ds-bg-surface)] text-[var(--ds-text-primary)]",
|
|
13024
|
-
GLASS_OVERLAY,
|
|
13025
|
-
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
13026
|
-
isMobile ? "rounded-none" : "rounded-[var(--ds-radius-xl)]",
|
|
13027
|
-
"overflow-hidden",
|
|
13028
|
-
"animate-in fade-in-0 zoom-in-95"
|
|
13029
|
-
),
|
|
13030
|
-
children: [
|
|
13031
|
-
/* @__PURE__ */ jsx(
|
|
13032
|
-
"button",
|
|
13033
|
-
{
|
|
13034
|
-
type: "button",
|
|
13035
|
-
onClick: onClose,
|
|
13036
|
-
...{ [OVERLAY_CLOSE_ATTR]: "" },
|
|
13037
|
-
className: "absolute right-4 top-4 text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer",
|
|
13038
|
-
"aria-label": "Close",
|
|
13039
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 18 })
|
|
13040
|
-
}
|
|
13041
|
-
),
|
|
13042
|
-
/* @__PURE__ */ jsx("div", { className: "p-ds-6", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-ds-3", children: [
|
|
13043
|
-
variant === "destructive" && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center shrink-0 w-10 h-10 rounded-[var(--ds-radius-full)] bg-[var(--ds-status-error-bg)]", children: /* @__PURE__ */ jsx(Icon, { name: "warning", size: 20, className: "text-[var(--ds-status-error)]" }) }),
|
|
13044
|
-
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
13045
|
-
/* @__PURE__ */ jsx(
|
|
13046
|
-
"h2",
|
|
13047
|
-
{
|
|
13048
|
-
id: titleId,
|
|
13049
|
-
className: "font-[family-name:var(--ds-font-display)] text-lg font-[var(--ds-weight-heading)] leading-none tracking-tight",
|
|
13050
|
-
children: title
|
|
13051
|
-
}
|
|
13052
|
-
),
|
|
13053
|
-
description && /* @__PURE__ */ jsx("p", { id: descriptionId, className: "mt-ds-2 text-sm text-[var(--ds-text-muted)]", children: description }),
|
|
13054
|
-
children && /* @__PURE__ */ jsx("div", { className: "mt-ds-4", children: /* @__PURE__ */ jsx(OverlayCloseCtx, { value: onClose, children }) })
|
|
13055
|
-
] })
|
|
13056
|
-
] }) }),
|
|
13057
|
-
/* @__PURE__ */ jsx(DiscardConfirm, { open: guard.confirming, onKeep: guard.keep, onDiscard: guard.discard }),
|
|
13058
|
-
footer && /* @__PURE__ */ jsx("div", { className: cn(
|
|
13059
|
-
"flex justify-end gap-ds-2 p-ds-4",
|
|
13060
|
-
"border-t-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
|
|
13061
|
-
"bg-[var(--ds-bg-muted)]",
|
|
13062
|
-
"rounded-b-[var(--ds-radius-xl)]"
|
|
13063
|
-
), children: footer })
|
|
13064
|
-
]
|
|
13065
|
-
}
|
|
13066
|
-
)
|
|
13067
|
-
]
|
|
13068
|
-
}
|
|
13069
|
-
)
|
|
13070
|
-
]
|
|
13071
|
-
}
|
|
13072
|
-
),
|
|
13073
|
-
container ?? document.body
|
|
13074
|
-
);
|
|
13075
|
-
}
|
|
13076
13809
|
function CommandPalette({ open, onOpenChange, commands, placeholder = "Type a command\u2026", loading = false, container }) {
|
|
13077
13810
|
const [query, setQuery] = useState("");
|
|
13078
13811
|
const [selectedIdx, setSelectedIdx] = useState(0);
|
|
13079
13812
|
const inputRef = useRef(null);
|
|
13080
13813
|
const listRef = useRef(null);
|
|
13814
|
+
const dialogRef = useRef(null);
|
|
13081
13815
|
const listboxId = useId();
|
|
13082
13816
|
const filtered = commands.filter(
|
|
13083
13817
|
(c) => c.label.toLowerCase().includes(query.toLowerCase()) || c.group?.toLowerCase().includes(query.toLowerCase())
|
|
@@ -13106,20 +13840,26 @@ function CommandPalette({ open, onOpenChange, commands, placeholder = "Type a co
|
|
|
13106
13840
|
if (open) requestAnimationFrame(() => inputRef.current?.focus());
|
|
13107
13841
|
}, [open]);
|
|
13108
13842
|
const isTopLayer = useOverlayLayer(open);
|
|
13843
|
+
useFocusTrap(dialogRef, open, isTopLayer);
|
|
13844
|
+
const returnFocus = useReturnFocus(open, dialogRef);
|
|
13845
|
+
const onOpenChangeRef = useLatest(onOpenChange);
|
|
13109
13846
|
useEffect(() => {
|
|
13110
13847
|
if (!open) return;
|
|
13111
13848
|
const handler = (e) => {
|
|
13112
|
-
if (e.key
|
|
13849
|
+
if (e.key !== "Escape" || e.defaultPrevented || !isTopLayer()) return;
|
|
13850
|
+
e.preventDefault();
|
|
13851
|
+
onOpenChangeRef.current(false);
|
|
13113
13852
|
};
|
|
13114
13853
|
document.addEventListener("keydown", handler);
|
|
13115
13854
|
return () => document.removeEventListener("keydown", handler);
|
|
13116
|
-
}, [open,
|
|
13855
|
+
}, [open, onOpenChangeRef, isTopLayer]);
|
|
13117
13856
|
const handleSelect = useCallback(
|
|
13118
13857
|
(cmd) => {
|
|
13858
|
+
returnFocus();
|
|
13119
13859
|
cmd.onSelect();
|
|
13120
13860
|
onOpenChange(false);
|
|
13121
13861
|
},
|
|
13122
|
-
[onOpenChange]
|
|
13862
|
+
[onOpenChange, returnFocus]
|
|
13123
13863
|
);
|
|
13124
13864
|
const handleKeyDown = (e) => {
|
|
13125
13865
|
if (e.key === "ArrowDown") {
|
|
@@ -13150,8 +13890,10 @@ function CommandPalette({ open, onOpenChange, commands, placeholder = "Type a co
|
|
|
13150
13890
|
/* @__PURE__ */ jsxs(
|
|
13151
13891
|
"div",
|
|
13152
13892
|
{
|
|
13893
|
+
ref: dialogRef,
|
|
13153
13894
|
role: "dialog",
|
|
13154
13895
|
"aria-modal": "true",
|
|
13896
|
+
"aria-label": "Command palette",
|
|
13155
13897
|
className: cn(
|
|
13156
13898
|
"relative z-10 w-full max-w-lg",
|
|
13157
13899
|
"bg-[var(--ds-bg-surface)] text-[var(--ds-text-primary)]",
|
|
@@ -13177,6 +13919,7 @@ function CommandPalette({ open, onOpenChange, commands, placeholder = "Type a co
|
|
|
13177
13919
|
"aria-expanded": true,
|
|
13178
13920
|
"aria-controls": listboxId,
|
|
13179
13921
|
"aria-autocomplete": "list",
|
|
13922
|
+
"aria-activedescendant": flatFiltered[selectedIdx] ? `${listboxId}-opt-${selectedIdx}` : void 0,
|
|
13180
13923
|
value: query,
|
|
13181
13924
|
onChange: (e) => setQuery(e.target.value),
|
|
13182
13925
|
onKeyDown: handleKeyDown,
|
|
@@ -13210,7 +13953,9 @@ function CommandPalette({ open, onOpenChange, commands, placeholder = "Type a co
|
|
|
13210
13953
|
return /* @__PURE__ */ jsxs(
|
|
13211
13954
|
"button",
|
|
13212
13955
|
{
|
|
13956
|
+
id: `${listboxId}-opt-${myIdx}`,
|
|
13213
13957
|
role: "option",
|
|
13958
|
+
tabIndex: -1,
|
|
13214
13959
|
"aria-selected": myIdx === selectedIdx,
|
|
13215
13960
|
onClick: () => handleSelect(cmd),
|
|
13216
13961
|
onMouseEnter: () => setSelectedIdx(myIdx),
|
|
@@ -13321,7 +14066,9 @@ function ContextMenu({ items, children, className, ref, container }) {
|
|
|
13321
14066
|
};
|
|
13322
14067
|
const keyHandler = (e) => {
|
|
13323
14068
|
if (e.key === "Escape") {
|
|
13324
|
-
if (isTopLayer())
|
|
14069
|
+
if (e.defaultPrevented || !isTopLayer()) return;
|
|
14070
|
+
e.preventDefault();
|
|
14071
|
+
setOpen(false);
|
|
13325
14072
|
return;
|
|
13326
14073
|
}
|
|
13327
14074
|
const actionable = items.filter((it) => !it.separator && !it.disabled);
|
|
@@ -13458,10 +14205,11 @@ function NotificationCenter({
|
|
|
13458
14205
|
const [internalFilter, setInternalFilter] = useState("all");
|
|
13459
14206
|
const isControlled = controlledOpen !== void 0;
|
|
13460
14207
|
const open = isControlled ? controlledOpen : internalOpen;
|
|
14208
|
+
const onOpenChangeRef = useLatest(onOpenChange);
|
|
13461
14209
|
const setOpen = useCallback((v) => {
|
|
13462
|
-
if (isControlled)
|
|
14210
|
+
if (isControlled) onOpenChangeRef.current?.(v);
|
|
13463
14211
|
else setInternalOpen(v);
|
|
13464
|
-
}, [isControlled,
|
|
14212
|
+
}, [isControlled, onOpenChangeRef]);
|
|
13465
14213
|
const triggerRef = useRef(null);
|
|
13466
14214
|
const panelRef = useRef(null);
|
|
13467
14215
|
const pos = usePosition(triggerRef, panelRef, open, { side: "bottom", align: "end", offset: 8, flip: true });
|
|
@@ -13469,8 +14217,7 @@ function NotificationCenter({
|
|
|
13469
14217
|
const setFilter = onFilterChange ?? setInternalFilter;
|
|
13470
14218
|
const unreadCount = notifications.filter((n) => !n.read).length;
|
|
13471
14219
|
const filteredNotifications = filter === "unread" ? notifications.filter((n) => !n.read) : notifications;
|
|
13472
|
-
const isTopLayer =
|
|
13473
|
-
useCloseOnFocusOut(open, triggerRef, panelRef, () => setOpen(false), isTopLayer);
|
|
14220
|
+
const { isTop: isTopLayer, returnFocus } = usePopupFocus(open, { trigger: triggerRef, panel: panelRef, close: () => setOpen(false), tabExits: "edges" });
|
|
13474
14221
|
useEffect(() => {
|
|
13475
14222
|
if (!open) return;
|
|
13476
14223
|
const id = requestAnimationFrame(() => focusInitial(panelRef.current));
|
|
@@ -13479,10 +14226,10 @@ function NotificationCenter({
|
|
|
13479
14226
|
useEffect(() => {
|
|
13480
14227
|
if (!open) return;
|
|
13481
14228
|
const onKey = (e) => {
|
|
13482
|
-
if (e.key
|
|
13483
|
-
|
|
13484
|
-
|
|
13485
|
-
|
|
14229
|
+
if (e.key !== "Escape" || e.defaultPrevented || !isTopLayer()) return;
|
|
14230
|
+
e.preventDefault();
|
|
14231
|
+
returnFocus();
|
|
14232
|
+
setOpen(false);
|
|
13486
14233
|
};
|
|
13487
14234
|
const onClick = (e) => {
|
|
13488
14235
|
const target = e.target;
|
|
@@ -13495,7 +14242,7 @@ function NotificationCenter({
|
|
|
13495
14242
|
document.removeEventListener("keydown", onKey);
|
|
13496
14243
|
document.removeEventListener("mousedown", onClick);
|
|
13497
14244
|
};
|
|
13498
|
-
}, [open, setOpen, isTopLayer]);
|
|
14245
|
+
}, [open, setOpen, isTopLayer, returnFocus]);
|
|
13499
14246
|
const grouped = groupByDate(filteredNotifications);
|
|
13500
14247
|
if (variant === "page") {
|
|
13501
14248
|
return /* @__PURE__ */ jsxs("div", { ref, className: cn("w-full", className), children: [
|
|
@@ -13604,6 +14351,8 @@ function NotificationCenter({
|
|
|
13604
14351
|
ref: triggerRef,
|
|
13605
14352
|
onClick: () => setOpen(!open),
|
|
13606
14353
|
"aria-label": `Notifications${unreadCount ? ` (${unreadCount} unread)` : ""}`,
|
|
14354
|
+
"aria-haspopup": "dialog",
|
|
14355
|
+
"aria-expanded": open,
|
|
13607
14356
|
className: cn(
|
|
13608
14357
|
"relative flex items-center justify-center w-9 h-9",
|
|
13609
14358
|
"rounded-[var(--ds-radius-md)]",
|
|
@@ -13622,6 +14371,8 @@ function NotificationCenter({
|
|
|
13622
14371
|
"div",
|
|
13623
14372
|
{
|
|
13624
14373
|
ref: panelRef,
|
|
14374
|
+
role: "dialog",
|
|
14375
|
+
"aria-label": "Notifications",
|
|
13625
14376
|
className: cn(
|
|
13626
14377
|
"fixed z-[var(--ds-z-popover)] w-[360px] max-h-[480px] flex flex-col",
|
|
13627
14378
|
"bg-[var(--ds-bg-surface-elevated)]",
|
|
@@ -13768,17 +14519,30 @@ function Tour({ steps, open, onClose, onComplete, container }) {
|
|
|
13768
14519
|
if (current > 0) setCurrent((c) => c - 1);
|
|
13769
14520
|
}, [current]);
|
|
13770
14521
|
const isTopLayer = useOverlayLayer(open);
|
|
14522
|
+
const nextRef = useRef(null);
|
|
14523
|
+
const titleId = useId();
|
|
14524
|
+
useFocusTrap(popoverRef, open, isTopLayer);
|
|
14525
|
+
useReturnFocus(open, popoverRef);
|
|
14526
|
+
useEffect(() => {
|
|
14527
|
+
if (!open) return;
|
|
14528
|
+
const raf = requestAnimationFrame(() => nextRef.current?.focus());
|
|
14529
|
+
return () => cancelAnimationFrame(raf);
|
|
14530
|
+
}, [open, current]);
|
|
14531
|
+
const onCloseRef = useLatest(onClose);
|
|
14532
|
+
const handleNextRef = useLatest(handleNext);
|
|
14533
|
+
const handlePrevRef = useLatest(handlePrev);
|
|
13771
14534
|
useEffect(() => {
|
|
13772
14535
|
if (!open) return;
|
|
13773
14536
|
const onKey = (e) => {
|
|
13774
|
-
if (!isTopLayer()) return;
|
|
13775
|
-
|
|
13776
|
-
|
|
13777
|
-
|
|
14537
|
+
if (e.defaultPrevented || !isTopLayer()) return;
|
|
14538
|
+
const act = e.key === "Escape" ? onCloseRef.current : e.key === "ArrowRight" ? handleNextRef.current : e.key === "ArrowLeft" ? handlePrevRef.current : null;
|
|
14539
|
+
if (!act) return;
|
|
14540
|
+
e.preventDefault();
|
|
14541
|
+
act();
|
|
13778
14542
|
};
|
|
13779
14543
|
document.addEventListener("keydown", onKey);
|
|
13780
14544
|
return () => document.removeEventListener("keydown", onKey);
|
|
13781
|
-
}, [open,
|
|
14545
|
+
}, [open, isTopLayer, onCloseRef, handleNextRef, handlePrevRef]);
|
|
13782
14546
|
if (!open || !step) return null;
|
|
13783
14547
|
const padding = 8;
|
|
13784
14548
|
const spotlightRadius = 8;
|
|
@@ -13820,6 +14584,9 @@ function Tour({ steps, open, onClose, onComplete, container }) {
|
|
|
13820
14584
|
"div",
|
|
13821
14585
|
{
|
|
13822
14586
|
ref: popoverRef,
|
|
14587
|
+
role: "dialog",
|
|
14588
|
+
"aria-modal": "true",
|
|
14589
|
+
"aria-labelledby": titleId,
|
|
13823
14590
|
className: cn(
|
|
13824
14591
|
"fixed z-[2] w-[300px]",
|
|
13825
14592
|
"bg-[var(--ds-bg-surface-elevated)]",
|
|
@@ -13832,7 +14599,7 @@ function Tour({ steps, open, onClose, onComplete, container }) {
|
|
|
13832
14599
|
children: [
|
|
13833
14600
|
/* @__PURE__ */ jsxs("div", { className: "px-ds-4 pt-ds-4 pb-ds-3", children: [
|
|
13834
14601
|
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-ds-2 mb-ds-1", children: [
|
|
13835
|
-
/* @__PURE__ */ jsx("h3", { className: "text-sm font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)]", children: step.title }),
|
|
14602
|
+
/* @__PURE__ */ jsx("h3", { id: titleId, className: "text-sm font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)]", children: step.title }),
|
|
13836
14603
|
/* @__PURE__ */ jsx(
|
|
13837
14604
|
"button",
|
|
13838
14605
|
{
|
|
@@ -13868,6 +14635,7 @@ function Tour({ steps, open, onClose, onComplete, container }) {
|
|
|
13868
14635
|
/* @__PURE__ */ jsx(
|
|
13869
14636
|
"button",
|
|
13870
14637
|
{
|
|
14638
|
+
ref: nextRef,
|
|
13871
14639
|
onClick: handleNext,
|
|
13872
14640
|
className: cn(
|
|
13873
14641
|
"px-ds-3 py-ds-1.5 text-xs font-medium rounded-[var(--ds-radius-sm)]",
|
|
@@ -14238,7 +15006,7 @@ function useDestructiveAction(options) {
|
|
|
14238
15006
|
}
|
|
14239
15007
|
setOpen(true);
|
|
14240
15008
|
};
|
|
14241
|
-
const
|
|
15009
|
+
const matches2 = !typedRequired || typed.trim().toLowerCase() === typedText.trim().toLowerCase();
|
|
14242
15010
|
const element = open ? /* @__PURE__ */ jsx(
|
|
14243
15011
|
Dialog,
|
|
14244
15012
|
{
|
|
@@ -14249,7 +15017,7 @@ function useDestructiveAction(options) {
|
|
|
14249
15017
|
variant: "destructive",
|
|
14250
15018
|
footer: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
14251
15019
|
/* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: close, disabled: busy, children: "Cancel" }),
|
|
14252
|
-
/* @__PURE__ */ jsx(Button, { variant: "destructive", onClick: () => void confirm(), disabled: !
|
|
15020
|
+
/* @__PURE__ */ jsx(Button, { variant: "destructive", onClick: () => void confirm(), disabled: !matches2 || busy, loading: busy, children: label })
|
|
14253
15021
|
] }),
|
|
14254
15022
|
children: typedRequired && /* @__PURE__ */ jsx(Field, { label: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
14255
15023
|
"Type ",
|