gridsmith-ui 0.6.3 → 0.6.5
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/README.md +6 -0
- package/dist/charts.js.map +1 -1
- package/dist/{chunk-R5QGJURZ.js → chunk-DDKCQVKO.js} +16 -8
- package/dist/chunk-DDKCQVKO.js.map +1 -0
- package/dist/{chunk-DPF6776I.js → chunk-EKQHHP72.js} +18 -15
- package/dist/chunk-EKQHHP72.js.map +1 -0
- package/dist/{chunk-TYU2LQGK.js → chunk-KXNJJKIV.js} +3 -3
- package/dist/{chunk-TYU2LQGK.js.map → chunk-KXNJJKIV.js.map} +1 -1
- package/dist/data-grid.d.ts +1 -1
- package/dist/data-grid.js +2 -2
- package/dist/data-grid.js.map +1 -1
- package/dist/editor.js +7 -4
- package/dist/editor.js.map +1 -1
- package/dist/index.d.ts +32 -13
- package/dist/index.js +427 -347
- package/dist/index.js.map +1 -1
- package/dist/kanban.js +2 -2
- package/dist/resizable.js +1 -1
- package/dist/roots.css +41 -0
- package/dist/tokens.css +52 -0
- package/dist/{use-breakpoint-Cn51IubK.d.ts → use-breakpoint-BfKzmkxx.d.ts} +3 -0
- package/dist/virtualized.js.map +1 -1
- package/dist-static/tokens.css +52 -0
- package/package.json +1 -1
- package/dist/chunk-DPF6776I.js.map +0 -1
- package/dist/chunk-R5QGJURZ.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Skeleton } from './chunk-QGBG72OB.js';
|
|
2
2
|
export { Skeleton } from './chunk-QGBG72OB.js';
|
|
3
|
-
import { Badge } from './chunk-
|
|
4
|
-
export { Badge } from './chunk-
|
|
5
|
-
import { useBreakpoint } from './chunk-
|
|
6
|
-
export { BreakpointWidthProvider, useBreakpoint } from './chunk-
|
|
7
|
-
import { Tooltip, useTextOverflow, usePosition, Slot } from './chunk-
|
|
8
|
-
export { Tooltip, useTextOverflow } from './chunk-
|
|
3
|
+
import { Badge } from './chunk-KXNJJKIV.js';
|
|
4
|
+
export { Badge } from './chunk-KXNJJKIV.js';
|
|
5
|
+
import { useBreakpoint } from './chunk-EKQHHP72.js';
|
|
6
|
+
export { BreakpointWidthProvider, useBreakpoint } from './chunk-EKQHHP72.js';
|
|
7
|
+
import { Tooltip, useTextOverflow, usePosition, Slot, useLatest } from './chunk-DDKCQVKO.js';
|
|
8
|
+
export { Tooltip, useTextOverflow } from './chunk-DDKCQVKO.js';
|
|
9
9
|
import { Icon } from './chunk-GX6O72IV.js';
|
|
10
|
-
import { cn, GLASS_SURFACE, ACTIVE_RING, GLASS_BACKDROP, GLASS_DROPDOWN, lockBodyScroll, unlockBodyScroll, GLASS_OVERLAY,
|
|
10
|
+
import { cn, GLASS_SURFACE, ACTIVE_RING, GLASS_BACKDROP, GLASS_DROPDOWN, FOCUS_RING, lockBodyScroll, unlockBodyScroll, GLASS_OVERLAY, HAS_FOCUS_RING, FOCUS_WITHIN_RING } from './chunk-TTZSZNJ6.js';
|
|
11
11
|
import { createContext, forwardRef, useContext, useState, useRef, useEffect, useCallback, useId, isValidElement, cloneElement, Fragment as Fragment$1, useMemo, Children, useLayoutEffect } from 'react';
|
|
12
12
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
13
13
|
import { createPortal } from 'react-dom';
|
|
@@ -149,11 +149,13 @@ function DropdownMenu({ trigger, items, align = "end", className, container }) {
|
|
|
149
149
|
if (!isDivider(item) && !item.disabled) acc.push(i);
|
|
150
150
|
return acc;
|
|
151
151
|
}, []);
|
|
152
|
+
const [prevOpen, setPrevOpen] = useState(open);
|
|
153
|
+
if (open !== prevOpen) {
|
|
154
|
+
setPrevOpen(open);
|
|
155
|
+
if (!open) setFocusedIdx(-1);
|
|
156
|
+
}
|
|
152
157
|
useEffect(() => {
|
|
153
|
-
if (!open)
|
|
154
|
-
setFocusedIdx(-1);
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
158
|
+
if (!open) return;
|
|
157
159
|
const onKeyDown = (e) => {
|
|
158
160
|
if (e.key === "Escape") setOpen(false);
|
|
159
161
|
};
|
|
@@ -534,13 +536,15 @@ function Dropdown({
|
|
|
534
536
|
}
|
|
535
537
|
setPos({ top, left, width });
|
|
536
538
|
}, []);
|
|
539
|
+
const [prevOpen, setPrevOpen] = useState(open);
|
|
540
|
+
if (open !== prevOpen) {
|
|
541
|
+
setPrevOpen(open);
|
|
542
|
+
if (open) setSearch("");
|
|
543
|
+
else setPositioned(false);
|
|
544
|
+
}
|
|
537
545
|
useEffect(() => {
|
|
538
|
-
if (!open)
|
|
539
|
-
setPositioned(false);
|
|
540
|
-
return;
|
|
541
|
-
}
|
|
546
|
+
if (!open) return;
|
|
542
547
|
updatePos();
|
|
543
|
-
setSearch("");
|
|
544
548
|
requestAnimationFrame(() => {
|
|
545
549
|
if (searchRef.current) {
|
|
546
550
|
searchRef.current.focus();
|
|
@@ -570,14 +574,14 @@ function Dropdown({
|
|
|
570
574
|
return () => document.removeEventListener("mousedown", handler);
|
|
571
575
|
}, [open]);
|
|
572
576
|
const typeahead = useRef({ buffer: "", at: 0 });
|
|
573
|
-
const optionButtons = () => Array.from(menuRef.current?.querySelectorAll('[role="option"]') ?? []);
|
|
574
|
-
const focusOption = (idx) => {
|
|
575
|
-
const els = optionButtons();
|
|
576
|
-
if (els.length === 0) return;
|
|
577
|
-
els[(idx % els.length + els.length) % els.length].focus();
|
|
578
|
-
};
|
|
579
577
|
useEffect(() => {
|
|
580
578
|
if (!open) return;
|
|
579
|
+
const optionButtons = () => Array.from(menuRef.current?.querySelectorAll('[role="option"]') ?? []);
|
|
580
|
+
const focusOption = (idx) => {
|
|
581
|
+
const els = optionButtons();
|
|
582
|
+
if (els.length === 0) return;
|
|
583
|
+
els[(idx % els.length + els.length) % els.length].focus();
|
|
584
|
+
};
|
|
581
585
|
const onKey = (e) => {
|
|
582
586
|
const inMenu = menuRef.current?.contains(document.activeElement) || triggerRef.current === document.activeElement;
|
|
583
587
|
if (!inMenu) return;
|
|
@@ -812,6 +816,7 @@ function Combobox({ value, onChange, options, placeholder = "Search\u2026", disa
|
|
|
812
816
|
const [highlightIdx, setHighlightIdx] = useState(0);
|
|
813
817
|
const inputRef = useRef(null);
|
|
814
818
|
const triggerRef = useRef(null);
|
|
819
|
+
const [triggerWidth, setTriggerWidth] = useState(void 0);
|
|
815
820
|
const listRef = useRef(null);
|
|
816
821
|
const listboxId = useId();
|
|
817
822
|
const pos = usePosition(triggerRef, listRef, open, { side: "bottom", align: "start", offset: 4, flip: true });
|
|
@@ -820,9 +825,11 @@ function Combobox({ value, onChange, options, placeholder = "Search\u2026", disa
|
|
|
820
825
|
);
|
|
821
826
|
const selectedLabel = options.find((o) => o.value === value)?.label ?? "";
|
|
822
827
|
const { ref: overflowRef, isTruncated: labelTruncated } = useTextOverflow({ lines: 1, content: selectedLabel, disabled: open });
|
|
823
|
-
|
|
828
|
+
const [prevQuery, setPrevQuery] = useState(query);
|
|
829
|
+
if (query !== prevQuery) {
|
|
830
|
+
setPrevQuery(query);
|
|
824
831
|
setHighlightIdx(0);
|
|
825
|
-
}
|
|
832
|
+
}
|
|
826
833
|
useEffect(() => {
|
|
827
834
|
if (!open) return;
|
|
828
835
|
const handler = (e) => {
|
|
@@ -870,6 +877,7 @@ function Combobox({ value, onChange, options, placeholder = "Search\u2026", disa
|
|
|
870
877
|
}, [overflowRef]);
|
|
871
878
|
const triggerContent = /* @__PURE__ */ jsxs("div", { ref: (node) => {
|
|
872
879
|
triggerRef.current = node;
|
|
880
|
+
setTriggerWidth(node?.offsetWidth);
|
|
873
881
|
if (typeof ref === "function") ref(node);
|
|
874
882
|
else if (ref) ref.current = node;
|
|
875
883
|
}, className: cn("relative", className), children: [
|
|
@@ -950,7 +958,7 @@ function Combobox({ value, onChange, options, placeholder = "Search\u2026", disa
|
|
|
950
958
|
"rounded-[var(--ds-radius-md)]",
|
|
951
959
|
"shadow-[var(--ds-shadow-dropdown),var(--ds-glass-inset)]"
|
|
952
960
|
),
|
|
953
|
-
style: { top: pos.top, left: pos.left, width:
|
|
961
|
+
style: { top: pos.top, left: pos.left, width: triggerWidth },
|
|
954
962
|
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(
|
|
955
963
|
"button",
|
|
956
964
|
{
|
|
@@ -1491,7 +1499,7 @@ function getMonthGrid(year, month, weekStartsOn = 0) {
|
|
|
1491
1499
|
const firstOfMonth = new Date(year, month, 1);
|
|
1492
1500
|
const gridStart = startOfWeek(firstOfMonth, weekStartsOn);
|
|
1493
1501
|
const weeks = [];
|
|
1494
|
-
|
|
1502
|
+
const current = new Date(gridStart);
|
|
1495
1503
|
for (let w = 0; w < 6; w++) {
|
|
1496
1504
|
const week = [];
|
|
1497
1505
|
for (let d = 0; d < 7; d++) {
|
|
@@ -2292,11 +2300,11 @@ function NumberInput({
|
|
|
2292
2300
|
const [focused, setFocused] = useState(false);
|
|
2293
2301
|
const [draft, setDraft] = useState(String(value));
|
|
2294
2302
|
const decimals = allowDecimals ?? step % 1 !== 0;
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
}
|
|
2303
|
+
const [prevSync, setPrevSync] = useState({ value, focused });
|
|
2304
|
+
if (value !== prevSync.value || focused !== prevSync.focused) {
|
|
2305
|
+
setPrevSync({ value, focused });
|
|
2306
|
+
if (!focused) setDraft(String(value));
|
|
2307
|
+
}
|
|
2300
2308
|
const clamp = useCallback(
|
|
2301
2309
|
(v) => Math.min(max, Math.max(min, v)),
|
|
2302
2310
|
[min, max]
|
|
@@ -2397,7 +2405,7 @@ function NumberInput({
|
|
|
2397
2405
|
onMouseDown: (e) => {
|
|
2398
2406
|
e.preventDefault();
|
|
2399
2407
|
inputRef.current?.focus();
|
|
2400
|
-
!disabled && !atMin
|
|
2408
|
+
if (!disabled && !atMin) startRepeat(decrement);
|
|
2401
2409
|
},
|
|
2402
2410
|
onMouseUp: stopRepeat,
|
|
2403
2411
|
onMouseLeave: stopRepeat,
|
|
@@ -2453,7 +2461,7 @@ function NumberInput({
|
|
|
2453
2461
|
onMouseDown: (e) => {
|
|
2454
2462
|
e.preventDefault();
|
|
2455
2463
|
inputRef.current?.focus();
|
|
2456
|
-
!disabled && !atMax
|
|
2464
|
+
if (!disabled && !atMax) startRepeat(increment);
|
|
2457
2465
|
},
|
|
2458
2466
|
onMouseUp: stopRepeat,
|
|
2459
2467
|
onMouseLeave: stopRepeat,
|
|
@@ -3012,11 +3020,12 @@ function ColorPicker({
|
|
|
3012
3020
|
const [hexInput, setHexInput] = useState(value);
|
|
3013
3021
|
const satLightRef = useRef(null);
|
|
3014
3022
|
const draggingRef = useRef(false);
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3023
|
+
const [prevValue, setPrevValue] = useState(value);
|
|
3024
|
+
if (value !== prevValue) {
|
|
3025
|
+
setPrevValue(value);
|
|
3026
|
+
setHsl(hexToHsl(value));
|
|
3018
3027
|
setHexInput(value);
|
|
3019
|
-
}
|
|
3028
|
+
}
|
|
3020
3029
|
const emitChange = useCallback(
|
|
3021
3030
|
(newHsl) => {
|
|
3022
3031
|
setHsl(newHsl);
|
|
@@ -3250,17 +3259,15 @@ function useFormContext() {
|
|
|
3250
3259
|
function FormWrapper({ onSubmit, validationMode = "onSubmit", children, className, ref }) {
|
|
3251
3260
|
const [errors, setErrors] = useState({});
|
|
3252
3261
|
const [submitted, setSubmitted] = useState(false);
|
|
3253
|
-
const errorsRef =
|
|
3254
|
-
errorsRef.current = errors;
|
|
3262
|
+
const errorsRef = useLatest(errors);
|
|
3255
3263
|
const pendingSubmit = useRef(false);
|
|
3256
|
-
const onSubmitRef =
|
|
3257
|
-
onSubmitRef.current = onSubmit;
|
|
3264
|
+
const onSubmitRef = useLatest(onSubmit);
|
|
3258
3265
|
useEffect(() => {
|
|
3259
3266
|
if (pendingSubmit.current && submitted) {
|
|
3260
3267
|
pendingSubmit.current = false;
|
|
3261
3268
|
onSubmitRef.current(errorsRef.current);
|
|
3262
3269
|
}
|
|
3263
|
-
}, [submitted, errors]);
|
|
3270
|
+
}, [submitted, errors, errorsRef, onSubmitRef]);
|
|
3264
3271
|
const setError = useCallback((field, message) => {
|
|
3265
3272
|
setErrors((prev) => ({ ...prev, [field]: message }));
|
|
3266
3273
|
}, []);
|
|
@@ -5818,9 +5825,12 @@ function MonthDropdown({
|
|
|
5818
5825
|
offset: 8,
|
|
5819
5826
|
flip: true
|
|
5820
5827
|
});
|
|
5821
|
-
|
|
5828
|
+
const browseSyncKey = open ? currentDate.getTime() : null;
|
|
5829
|
+
const [prevBrowseSyncKey, setPrevBrowseSyncKey] = useState(browseSyncKey);
|
|
5830
|
+
if (browseSyncKey !== prevBrowseSyncKey) {
|
|
5831
|
+
setPrevBrowseSyncKey(browseSyncKey);
|
|
5822
5832
|
if (open) setBrowseYear(currentDate.getFullYear());
|
|
5823
|
-
}
|
|
5833
|
+
}
|
|
5824
5834
|
useEffect(() => {
|
|
5825
5835
|
if (!open) return;
|
|
5826
5836
|
const onKey = (e) => {
|
|
@@ -5938,9 +5948,12 @@ function YearDropdown({
|
|
|
5938
5948
|
});
|
|
5939
5949
|
const currentYear = currentDate.getFullYear();
|
|
5940
5950
|
const [rangeStart, setRangeStart] = useState(() => currentYear - 4);
|
|
5941
|
-
|
|
5951
|
+
const rangeSyncKey = open ? currentYear : null;
|
|
5952
|
+
const [prevRangeSyncKey, setPrevRangeSyncKey] = useState(rangeSyncKey);
|
|
5953
|
+
if (rangeSyncKey !== prevRangeSyncKey) {
|
|
5954
|
+
setPrevRangeSyncKey(rangeSyncKey);
|
|
5942
5955
|
if (open) setRangeStart(currentYear - 4);
|
|
5943
|
-
}
|
|
5956
|
+
}
|
|
5944
5957
|
useEffect(() => {
|
|
5945
5958
|
if (!open) return;
|
|
5946
5959
|
const onKey = (e) => {
|
|
@@ -6662,6 +6675,13 @@ function TruncLabel2({ children }) {
|
|
|
6662
6675
|
if (!isTruncated) return label;
|
|
6663
6676
|
return /* @__PURE__ */ jsx(Tooltip, { content: children, children: label });
|
|
6664
6677
|
}
|
|
6678
|
+
function allDescendantIds(node) {
|
|
6679
|
+
const ids = [node.id];
|
|
6680
|
+
if (node.children) {
|
|
6681
|
+
for (const child of node.children) ids.push(...allDescendantIds(child));
|
|
6682
|
+
}
|
|
6683
|
+
return ids;
|
|
6684
|
+
}
|
|
6665
6685
|
function TreeView({
|
|
6666
6686
|
nodes,
|
|
6667
6687
|
selectable,
|
|
@@ -6704,13 +6724,6 @@ function TreeView({
|
|
|
6704
6724
|
},
|
|
6705
6725
|
[selectable, multiSelect, onSelect]
|
|
6706
6726
|
);
|
|
6707
|
-
const allDescendantIds = useCallback((node) => {
|
|
6708
|
-
const ids = [node.id];
|
|
6709
|
-
if (node.children) {
|
|
6710
|
-
for (const child of node.children) ids.push(...allDescendantIds(child));
|
|
6711
|
-
}
|
|
6712
|
-
return ids;
|
|
6713
|
-
}, []);
|
|
6714
6727
|
const handleCheck = useCallback(
|
|
6715
6728
|
(node) => {
|
|
6716
6729
|
if (!checkable) return;
|
|
@@ -6726,7 +6739,7 @@ function TreeView({
|
|
|
6726
6739
|
return next;
|
|
6727
6740
|
});
|
|
6728
6741
|
},
|
|
6729
|
-
[checkable,
|
|
6742
|
+
[checkable, onCheck]
|
|
6730
6743
|
);
|
|
6731
6744
|
const getCheckState = useCallback(
|
|
6732
6745
|
(node) => {
|
|
@@ -6737,7 +6750,7 @@ function TreeView({
|
|
|
6737
6750
|
if (checkedCount > 0) return "indeterminate";
|
|
6738
6751
|
return "unchecked";
|
|
6739
6752
|
},
|
|
6740
|
-
[checked
|
|
6753
|
+
[checked]
|
|
6741
6754
|
);
|
|
6742
6755
|
const flatNodes = useCallback(() => {
|
|
6743
6756
|
const result = [];
|
|
@@ -6833,7 +6846,9 @@ function TreeNodeRow({
|
|
|
6833
6846
|
className: cn(
|
|
6834
6847
|
"flex items-center gap-ds-2 py-ds-1.5 px-ds-2 rounded-[var(--ds-radius-md)] cursor-pointer transition-colors",
|
|
6835
6848
|
"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
6836
|
-
|
|
6849
|
+
// Active style comes from the theme's --ds-tree-* tokens (rail / tint;
|
|
6850
|
+
// pill degrades to tint). The rail is drawn on the selected row only.
|
|
6851
|
+
isSelected ? "bg-[var(--ds-tree-active-bg)] text-[var(--ds-tree-active-text)] font-medium border-l-[length:var(--ds-tree-active-rail)] border-[var(--ds-accent-primary)]" : "text-[var(--ds-text-primary)] hover:bg-[var(--ds-tab-hover-bg)] hover:text-[var(--ds-text-primary)]",
|
|
6837
6852
|
node.disabled && "opacity-disabled pointer-events-none"
|
|
6838
6853
|
),
|
|
6839
6854
|
style: { paddingLeft: `calc(var(--ds-space-5) * ${depth} + var(--ds-space-2))` },
|
|
@@ -6860,7 +6875,7 @@ function TreeNodeRow({
|
|
|
6860
6875
|
{
|
|
6861
6876
|
name: "chevron-right",
|
|
6862
6877
|
size: 14,
|
|
6863
|
-
className: cn("text-[var(--ds-text-muted)] transition-transform", isExpanded && "rotate-90")
|
|
6878
|
+
className: cn(isSelected ? "text-[var(--ds-tree-active-muted)]" : "text-[var(--ds-text-muted)]", "transition-transform", isExpanded && "rotate-90")
|
|
6864
6879
|
}
|
|
6865
6880
|
)
|
|
6866
6881
|
}
|
|
@@ -6875,7 +6890,7 @@ function TreeNodeRow({
|
|
|
6875
6890
|
}
|
|
6876
6891
|
}
|
|
6877
6892
|
),
|
|
6878
|
-
node.icon && /* @__PURE__ */ jsx(Icon, { name: node.icon, size: 16, className: cn("shrink-0", isSelected ? "text-[var(--ds-
|
|
6893
|
+
node.icon && /* @__PURE__ */ jsx(Icon, { name: node.icon, size: 16, className: cn("shrink-0", isSelected ? "text-[var(--ds-tree-active-text)]" : "text-[var(--ds-text-muted)]") }),
|
|
6879
6894
|
/* @__PURE__ */ jsx(TruncLabel2, { children: node.label })
|
|
6880
6895
|
]
|
|
6881
6896
|
}
|
|
@@ -7363,6 +7378,19 @@ function useTabsCtx() {
|
|
|
7363
7378
|
if (!ctx) throw new Error("Tabs.List / Tabs.Trigger / Tabs.Content must be used inside <Tabs>");
|
|
7364
7379
|
return ctx;
|
|
7365
7380
|
}
|
|
7381
|
+
function trackClasses(orientation) {
|
|
7382
|
+
if (orientation === "vertical") {
|
|
7383
|
+
return cn(
|
|
7384
|
+
"flex flex-col gap-ds-0.5 min-w-[var(--ds-tab-rail-width)]",
|
|
7385
|
+
"border-r-[length:var(--ds-nav-v-track-border)] border-[var(--ds-border-default)]",
|
|
7386
|
+
"pr-[var(--ds-nav-v-track-padding)]"
|
|
7387
|
+
);
|
|
7388
|
+
}
|
|
7389
|
+
return cn(
|
|
7390
|
+
"flex gap-[var(--ds-nav-h-track-gap)]",
|
|
7391
|
+
"border-b-[length:var(--ds-nav-h-track-border)] border-[var(--ds-border-default)]"
|
|
7392
|
+
);
|
|
7393
|
+
}
|
|
7366
7394
|
function getTabsFromDOM(el) {
|
|
7367
7395
|
const tablist = el.closest('[role="tablist"]');
|
|
7368
7396
|
if (!tablist) return [];
|
|
@@ -7410,7 +7438,6 @@ function TabButton({
|
|
|
7410
7438
|
icon,
|
|
7411
7439
|
disabled,
|
|
7412
7440
|
orientation,
|
|
7413
|
-
variant,
|
|
7414
7441
|
activeTab,
|
|
7415
7442
|
onTabChange,
|
|
7416
7443
|
fullWidth,
|
|
@@ -7423,10 +7450,11 @@ function TabButton({
|
|
|
7423
7450
|
const isActive = activeTab === id;
|
|
7424
7451
|
const tabId = `ds-tab-${id}`;
|
|
7425
7452
|
const panelId = hasPanel === false ? void 0 : `ds-tabpanel-${id}`;
|
|
7453
|
+
const badgeBg = orientation === "vertical" ? "bg-[var(--ds-nav-v-badge-bg)]" : "bg-[var(--ds-nav-h-badge-bg)]";
|
|
7426
7454
|
const countBadge = count !== void 0 ? /* @__PURE__ */ jsx("span", { className: cn(
|
|
7427
7455
|
orientation === "vertical" ? "ml-ds-2" : "",
|
|
7428
7456
|
"px-ds-1.5 py-ds-0.5 text-xs rounded-[var(--ds-radius-sm)]",
|
|
7429
|
-
|
|
7457
|
+
isActive ? cn(badgeBg, "text-[var(--ds-text-on-primary)]") : "bg-[var(--ds-bg-emphasis)] text-[var(--ds-text-muted)]"
|
|
7430
7458
|
), children: count }) : null;
|
|
7431
7459
|
if (orientation === "vertical") {
|
|
7432
7460
|
const btn2 = /* @__PURE__ */ jsxs(
|
|
@@ -7443,10 +7471,12 @@ function TabButton({
|
|
|
7443
7471
|
className: cn(
|
|
7444
7472
|
"flex items-center justify-between px-ds-3 py-ds-2 text-sm font-medium text-left",
|
|
7445
7473
|
disabled ? "cursor-not-allowed opacity-disabled" : "cursor-pointer",
|
|
7446
|
-
"rounded-[var(--ds-radius
|
|
7474
|
+
"rounded-[var(--ds-nav-v-item-radius)]",
|
|
7447
7475
|
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
7448
7476
|
"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
7449
|
-
|
|
7477
|
+
// The rail is drawn on the active item only (today's behaviour; a
|
|
7478
|
+
// transparent placeholder on every item is a future layout tweak).
|
|
7479
|
+
isActive ? "bg-[var(--ds-nav-v-active-bg)] text-[var(--ds-nav-v-active-text)] border-l-[length:var(--ds-nav-v-active-rail)] border-[var(--ds-accent-primary)]" : "text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-tab-hover-bg)]",
|
|
7450
7480
|
className
|
|
7451
7481
|
),
|
|
7452
7482
|
children: [
|
|
@@ -7479,13 +7509,11 @@ function TabButton({
|
|
|
7479
7509
|
"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
7480
7510
|
fullWidth && "flex-1",
|
|
7481
7511
|
truncate && "flex-1 min-w-0 flex items-center",
|
|
7482
|
-
|
|
7483
|
-
|
|
7484
|
-
isActive ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]" : "text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-tab-hover-bg)]"
|
|
7485
|
-
) : isActive ? "text-[var(--ds-text-primary)] border-b-[length:var(--ds-border-width)] border-[var(--ds-accent-primary)]" : "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)]",
|
|
7512
|
+
"rounded-[var(--ds-nav-h-item-radius)]",
|
|
7513
|
+
isActive ? "bg-[var(--ds-nav-h-active-bg)] text-[var(--ds-nav-h-active-text)] border-[var(--ds-accent-primary)]" : "text-[var(--ds-nav-h-inactive-text)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-nav-h-hover-bg)]",
|
|
7486
7514
|
className
|
|
7487
7515
|
),
|
|
7488
|
-
style:
|
|
7516
|
+
style: isActive ? { borderBottomWidth: "var(--ds-nav-h-indicator)", marginBottom: "calc(var(--ds-nav-h-track-border) * -1)" } : void 0,
|
|
7489
7517
|
children: truncate ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7490
7518
|
icon && /* @__PURE__ */ jsx(Icon, { name: icon, size: 16, className: "shrink-0" }),
|
|
7491
7519
|
/* @__PURE__ */ jsx("span", { ref: truncRef, className: "truncate min-w-0 flex-1", children: label }),
|
|
@@ -7501,18 +7529,14 @@ function TabButton({
|
|
|
7501
7529
|
return btn;
|
|
7502
7530
|
}
|
|
7503
7531
|
function TabsList({ children, className }) {
|
|
7504
|
-
const { orientation,
|
|
7532
|
+
const { orientation, fullWidth, overflow } = useTabsCtx();
|
|
7505
7533
|
if (orientation === "vertical") {
|
|
7506
7534
|
return /* @__PURE__ */ jsx(
|
|
7507
7535
|
"div",
|
|
7508
7536
|
{
|
|
7509
7537
|
role: "tablist",
|
|
7510
7538
|
"aria-orientation": "vertical",
|
|
7511
|
-
className: cn(
|
|
7512
|
-
"flex flex-col gap-ds-0.5 min-w-[var(--ds-tab-rail-width)]",
|
|
7513
|
-
variant === "underline" && "border-r-[length:var(--ds-border-width)] border-[var(--ds-border-default)] pr-ds-1",
|
|
7514
|
-
className
|
|
7515
|
-
),
|
|
7539
|
+
className: cn(trackClasses("vertical"), className),
|
|
7516
7540
|
children
|
|
7517
7541
|
}
|
|
7518
7542
|
);
|
|
@@ -7522,10 +7546,9 @@ function TabsList({ children, className }) {
|
|
|
7522
7546
|
{
|
|
7523
7547
|
role: "tablist",
|
|
7524
7548
|
className: cn(
|
|
7525
|
-
"
|
|
7549
|
+
trackClasses("horizontal"),
|
|
7550
|
+
"max-w-full",
|
|
7526
7551
|
overflow === "hidden" ? "overflow-hidden" : overflow === "truncate" ? "overflow-hidden" : "overflow-x-auto overflow-y-hidden",
|
|
7527
|
-
variant === "underline" && "border-b-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
7528
|
-
variant === "pill" && "gap-ds-1 p-ds-0.5 bg-[var(--ds-bg-muted)] rounded-[var(--ds-radius-lg)]",
|
|
7529
7552
|
fullWidth && "w-full",
|
|
7530
7553
|
className
|
|
7531
7554
|
),
|
|
@@ -7534,7 +7557,7 @@ function TabsList({ children, className }) {
|
|
|
7534
7557
|
);
|
|
7535
7558
|
}
|
|
7536
7559
|
function TabsTrigger({ value, children, count, icon, disabled, truncate, className }) {
|
|
7537
|
-
const { activeTab, onTabChange, orientation,
|
|
7560
|
+
const { activeTab, onTabChange, orientation, fullWidth, overflow } = useTabsCtx();
|
|
7538
7561
|
return /* @__PURE__ */ jsx(
|
|
7539
7562
|
TabButton,
|
|
7540
7563
|
{
|
|
@@ -7545,7 +7568,6 @@ function TabsTrigger({ value, children, count, icon, disabled, truncate, classNa
|
|
|
7545
7568
|
disabled,
|
|
7546
7569
|
truncate: overflow === "truncate" || truncate,
|
|
7547
7570
|
orientation,
|
|
7548
|
-
variant,
|
|
7549
7571
|
activeTab,
|
|
7550
7572
|
onTabChange,
|
|
7551
7573
|
fullWidth,
|
|
@@ -7574,7 +7596,6 @@ function TabsRoot(props) {
|
|
|
7574
7596
|
activeTab,
|
|
7575
7597
|
onTabChange,
|
|
7576
7598
|
orientation = "horizontal",
|
|
7577
|
-
variant = "underline",
|
|
7578
7599
|
fullWidth = false,
|
|
7579
7600
|
overflow = "scroll",
|
|
7580
7601
|
className
|
|
@@ -7601,11 +7622,7 @@ function TabsRoot(props) {
|
|
|
7601
7622
|
{
|
|
7602
7623
|
role: "tablist",
|
|
7603
7624
|
"aria-orientation": "vertical",
|
|
7604
|
-
className: cn(
|
|
7605
|
-
"flex flex-col gap-ds-0.5 min-w-[var(--ds-tab-rail-width)]",
|
|
7606
|
-
variant === "underline" && "border-r-[length:var(--ds-border-width)] border-[var(--ds-border-default)] pr-ds-1",
|
|
7607
|
-
className
|
|
7608
|
-
),
|
|
7625
|
+
className: cn(trackClasses("vertical"), className),
|
|
7609
7626
|
children: tabs.map((tab, i) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
7610
7627
|
tab.group && tab.group !== tabs[i - 1]?.group && /* @__PURE__ */ jsx(
|
|
7611
7628
|
"span",
|
|
@@ -7618,7 +7635,7 @@ function TabsRoot(props) {
|
|
|
7618
7635
|
children: tab.group
|
|
7619
7636
|
}
|
|
7620
7637
|
),
|
|
7621
|
-
/* @__PURE__ */ jsx(TabButton, { hasPanel: false, ...tab, orientation: effectiveOrientation,
|
|
7638
|
+
/* @__PURE__ */ jsx(TabButton, { hasPanel: false, ...tab, orientation: effectiveOrientation, activeTab, onTabChange, fullWidth, onKeyDown: (e) => handleTabKeyDown(e, tab.id, () => tabs, effectiveOrientation, onTabChange) })
|
|
7622
7639
|
] }, tab.id))
|
|
7623
7640
|
}
|
|
7624
7641
|
);
|
|
@@ -7629,18 +7646,16 @@ function TabsRoot(props) {
|
|
|
7629
7646
|
{
|
|
7630
7647
|
role: "tablist",
|
|
7631
7648
|
className: cn(
|
|
7632
|
-
"
|
|
7649
|
+
trackClasses("horizontal"),
|
|
7633
7650
|
effectiveOverflow === "scroll" ? "overflow-x-auto overflow-y-hidden" : "overflow-hidden",
|
|
7634
|
-
variant === "underline" && "border-b-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
7635
|
-
variant === "pill" && "gap-ds-1 p-ds-0.5 bg-[var(--ds-bg-muted)] rounded-[var(--ds-radius-lg)]",
|
|
7636
7651
|
fullWidth && "w-full",
|
|
7637
7652
|
className
|
|
7638
7653
|
),
|
|
7639
|
-
children: tabs.map((tab) => /* @__PURE__ */ jsx(TabButton, { hasPanel: false, ...tab, orientation: effectiveOrientation,
|
|
7654
|
+
children: tabs.map((tab) => /* @__PURE__ */ jsx(TabButton, { hasPanel: false, ...tab, orientation: effectiveOrientation, activeTab, onTabChange, fullWidth, onKeyDown: (e) => handleTabKeyDown(e, tab.id, () => tabs, effectiveOrientation, onTabChange) }, tab.id))
|
|
7640
7655
|
}
|
|
7641
7656
|
);
|
|
7642
7657
|
}
|
|
7643
|
-
return /* @__PURE__ */ jsx(TabsContext.Provider, { value: { activeTab, onTabChange, orientation: effectiveOrientation,
|
|
7658
|
+
return /* @__PURE__ */ jsx(TabsContext.Provider, { value: { activeTab, onTabChange, orientation: effectiveOrientation, fullWidth, overflow }, children: /* @__PURE__ */ jsx("div", { className, children: props.children }) });
|
|
7644
7659
|
}
|
|
7645
7660
|
var Tabs = Object.assign(TabsRoot, {
|
|
7646
7661
|
List: TabsList,
|
|
@@ -7845,6 +7860,11 @@ var Breadcrumbs = forwardRef(function Breadcrumbs2({
|
|
|
7845
7860
|
function Popover({ open, onOpenChange, trigger, children, side = "bottom", align = "center", width, className, container }) {
|
|
7846
7861
|
const triggerRef = useRef(null);
|
|
7847
7862
|
const floatingRef = useRef(null);
|
|
7863
|
+
const [triggerWidth, setTriggerWidth] = useState(void 0);
|
|
7864
|
+
const setTriggerNode = useCallback((node) => {
|
|
7865
|
+
triggerRef.current = node;
|
|
7866
|
+
setTriggerWidth(node?.offsetWidth);
|
|
7867
|
+
}, []);
|
|
7848
7868
|
const pos = usePosition(triggerRef, floatingRef, open, { side, align, offset: 8, flip: true });
|
|
7849
7869
|
useEffect(() => {
|
|
7850
7870
|
if (!open) return;
|
|
@@ -7870,8 +7890,11 @@ function Popover({ open, onOpenChange, trigger, children, side = "bottom", align
|
|
|
7870
7890
|
/* @__PURE__ */ jsx(
|
|
7871
7891
|
Slot,
|
|
7872
7892
|
{
|
|
7873
|
-
ref:
|
|
7874
|
-
onClick: () =>
|
|
7893
|
+
ref: setTriggerNode,
|
|
7894
|
+
onClick: () => {
|
|
7895
|
+
setTriggerWidth(triggerRef.current?.offsetWidth);
|
|
7896
|
+
onOpenChange(!open);
|
|
7897
|
+
},
|
|
7875
7898
|
children: trigger
|
|
7876
7899
|
}
|
|
7877
7900
|
),
|
|
@@ -7891,7 +7914,7 @@ function Popover({ open, onOpenChange, trigger, children, side = "bottom", align
|
|
|
7891
7914
|
style: {
|
|
7892
7915
|
top: pos.top,
|
|
7893
7916
|
left: pos.left,
|
|
7894
|
-
width: width === "trigger" ?
|
|
7917
|
+
width: width === "trigger" ? triggerWidth : width === "auto" ? void 0 : width
|
|
7895
7918
|
},
|
|
7896
7919
|
children
|
|
7897
7920
|
}
|
|
@@ -8507,10 +8530,7 @@ function CompactFlyout({
|
|
|
8507
8530
|
onMouseEnter,
|
|
8508
8531
|
onMouseLeave
|
|
8509
8532
|
}) {
|
|
8510
|
-
const
|
|
8511
|
-
useLayoutEffect(() => {
|
|
8512
|
-
setPos(computeCompactFlyoutPos(anchorEl, items.length));
|
|
8513
|
-
}, [anchorEl, items.length]);
|
|
8533
|
+
const pos = useMemo(() => computeCompactFlyoutPos(anchorEl, items.length), [anchorEl, items.length]);
|
|
8514
8534
|
useEffect(() => {
|
|
8515
8535
|
function handler(e) {
|
|
8516
8536
|
if (e.key === "Escape") onClose();
|
|
@@ -8549,7 +8569,7 @@ function CompactFlyout({
|
|
|
8549
8569
|
},
|
|
8550
8570
|
className: cn(
|
|
8551
8571
|
"flex items-center gap-ds-2 px-ds-2 py-ds-1.5 text-xs rounded-[var(--ds-radius-sm)] transition-colors cursor-pointer",
|
|
8552
|
-
child.active ? "bg-sidebar-
|
|
8572
|
+
child.active ? "bg-[var(--ds-sidebar-active-bg)] text-[var(--ds-sidebar-active-accent)] font-medium" : "text-[var(--ds-sidebar-text-secondary)] hover:bg-[var(--ds-sidebar-item-hover)] hover:text-[var(--ds-sidebar-text)]"
|
|
8553
8573
|
),
|
|
8554
8574
|
children: [
|
|
8555
8575
|
child.icon && /* @__PURE__ */ jsx(Icon, { name: child.icon, size: 14 }),
|
|
@@ -8655,7 +8675,10 @@ function SidebarNav({
|
|
|
8655
8675
|
"flex items-center gap-ds-2 transition-colors cursor-pointer",
|
|
8656
8676
|
isRoot ? cn(rootPy, rootText, isMinimal ? "rounded-[var(--ds-radius-full)]" : "rounded-[var(--ds-radius-md)]") : cn(childPy, "text-xs rounded-[var(--ds-radius-sm)]"),
|
|
8657
8677
|
isRoot ? collapsed ? "justify-center px-0" : "px-ds-3" : "px-ds-2",
|
|
8658
|
-
|
|
8678
|
+
// Active style comes from the theme's --ds-sidebar-active-* tokens
|
|
8679
|
+
// (rail / tint / pill). The rail token is 0px for minimal sidebars,
|
|
8680
|
+
// so the transparent placeholder on inactive roots is harmless there.
|
|
8681
|
+
item.active ? isRoot ? "bg-[var(--ds-sidebar-active-bg)] text-[var(--ds-sidebar-active-text)] font-medium border-l-[length:var(--ds-sidebar-active-rail)] border-[var(--ds-sidebar-active-accent)]" : "bg-[var(--ds-sidebar-active-bg)] text-[var(--ds-sidebar-active-accent)] font-medium" : isRoot ? "text-[var(--ds-sidebar-text-secondary)] hover:bg-[var(--ds-sidebar-item-hover)] hover:text-[var(--ds-sidebar-text)] border-l-[length:var(--ds-sidebar-active-rail)] border-transparent" : "text-[var(--ds-sidebar-text-muted)] hover:bg-[var(--ds-sidebar-item-hover)] hover:text-[var(--ds-sidebar-text)]"
|
|
8659
8682
|
),
|
|
8660
8683
|
children: [
|
|
8661
8684
|
item.icon && /* @__PURE__ */ jsx(
|
|
@@ -8663,7 +8686,7 @@ function SidebarNav({
|
|
|
8663
8686
|
{
|
|
8664
8687
|
name: item.icon,
|
|
8665
8688
|
size: isRoot ? rootIconSize : childIconSize,
|
|
8666
|
-
className: cn("shrink-0", item.active && "text-[var(--ds-sidebar-accent)]")
|
|
8689
|
+
className: cn("shrink-0", item.active && "text-[var(--ds-sidebar-active-accent)]")
|
|
8667
8690
|
}
|
|
8668
8691
|
),
|
|
8669
8692
|
!collapsed && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -8735,7 +8758,10 @@ function SidebarNav({
|
|
|
8735
8758
|
"flex items-center gap-ds-2 w-full text-left transition-colors cursor-pointer",
|
|
8736
8759
|
isRoot ? cn(rootPy, rootText, isMinimal ? "rounded-[var(--ds-radius-full)]" : "rounded-[var(--ds-radius-md)]") : cn(childPy, "text-xs rounded-[var(--ds-radius-sm)]"),
|
|
8737
8760
|
isRoot ? collapsed ? "justify-center px-0" : "px-ds-3" : "px-ds-2",
|
|
8738
|
-
|
|
8761
|
+
// This row has no fill, so its label, icon and chevron keep the plain
|
|
8762
|
+
// sidebar tokens: --ds-sidebar-active-accent is on-primary white under
|
|
8763
|
+
// `pill` and would vanish here. Only filled elements read the active set.
|
|
8764
|
+
item.active || childActive ? isRoot ? "text-[var(--ds-sidebar-text)] font-medium border-l-[length:var(--ds-sidebar-active-rail)] border-transparent" : "text-[var(--ds-sidebar-text)] font-medium" : isRoot ? "text-[var(--ds-sidebar-text-secondary)] hover:bg-[var(--ds-sidebar-item-hover)] hover:text-[var(--ds-sidebar-text)] border-l-[length:var(--ds-sidebar-active-rail)] border-transparent" : "text-[var(--ds-sidebar-text-muted)] hover:bg-[var(--ds-sidebar-item-hover)] hover:text-[var(--ds-sidebar-text)]"
|
|
8739
8765
|
),
|
|
8740
8766
|
children: [
|
|
8741
8767
|
item.icon && /* @__PURE__ */ jsx(
|
|
@@ -8900,7 +8926,7 @@ function CompactNavItem({
|
|
|
8900
8926
|
expanded,
|
|
8901
8927
|
onToggleExpand
|
|
8902
8928
|
}) {
|
|
8903
|
-
const
|
|
8929
|
+
const [triggerEl, setTriggerEl] = useState(null);
|
|
8904
8930
|
const handleMouseEnter = useCallback(() => {
|
|
8905
8931
|
onCancelClose();
|
|
8906
8932
|
if (hasChildren && !isOpen) onOpen(flyoutKey);
|
|
@@ -8919,14 +8945,16 @@ function CompactNavItem({
|
|
|
8919
8945
|
/* @__PURE__ */ jsxs(
|
|
8920
8946
|
"button",
|
|
8921
8947
|
{
|
|
8922
|
-
ref:
|
|
8948
|
+
ref: setTriggerEl,
|
|
8923
8949
|
onMouseEnter: !mobile && hasChildren ? handleMouseEnter : void 0,
|
|
8924
8950
|
onMouseLeave: !mobile && hasChildren && isOpen ? handleMouseLeave : void 0,
|
|
8925
8951
|
onClick: handleClick,
|
|
8926
8952
|
"aria-expanded": hasChildren ? mobile ? expanded : isOpen : void 0,
|
|
8927
8953
|
className: cn(
|
|
8928
8954
|
"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",
|
|
8929
|
-
|
|
8955
|
+
// Compact tiles have no edge to stroke: they read the fill and text
|
|
8956
|
+
// tokens only, never --ds-sidebar-active-rail.
|
|
8957
|
+
item.active || childActive ? "bg-[var(--ds-sidebar-active-bg)] text-[var(--ds-sidebar-active-accent)]" : "text-[var(--ds-sidebar-text-secondary)] hover:bg-[var(--ds-sidebar-item-hover)] hover:text-[var(--ds-sidebar-text)]"
|
|
8930
8958
|
),
|
|
8931
8959
|
children: [
|
|
8932
8960
|
item.icon && /* @__PURE__ */ jsx(
|
|
@@ -8934,7 +8962,7 @@ function CompactNavItem({
|
|
|
8934
8962
|
{
|
|
8935
8963
|
name: item.icon,
|
|
8936
8964
|
size: 20,
|
|
8937
|
-
className: cn((item.active || childActive) && "text-[var(--ds-sidebar-accent)]")
|
|
8965
|
+
className: cn((item.active || childActive) && "text-[var(--ds-sidebar-active-accent)]")
|
|
8938
8966
|
}
|
|
8939
8967
|
),
|
|
8940
8968
|
/* @__PURE__ */ jsx(TruncLabel3, { className: "text-[clamp(9px,var(--ds-font-size-2xs),12px)] leading-tight max-w-full", side: "right", container: portalContainer ?? void 0, children: item.label }),
|
|
@@ -8945,7 +8973,7 @@ function CompactNavItem({
|
|
|
8945
8973
|
size: 10,
|
|
8946
8974
|
className: cn(
|
|
8947
8975
|
"absolute right-1 top-1/2 -translate-y-1/2 transition-transform",
|
|
8948
|
-
item.active || childActive ? "text-[var(--ds-sidebar-accent)]" : "text-[var(--ds-sidebar-text-muted)]",
|
|
8976
|
+
item.active || childActive ? "text-[var(--ds-sidebar-active-accent)]" : "text-[var(--ds-sidebar-text-muted)]",
|
|
8949
8977
|
expanded && "rotate-180"
|
|
8950
8978
|
)
|
|
8951
8979
|
}
|
|
@@ -8953,12 +8981,12 @@ function CompactNavItem({
|
|
|
8953
8981
|
]
|
|
8954
8982
|
}
|
|
8955
8983
|
),
|
|
8956
|
-
!mobile && isOpen && hasChildren && item.children &&
|
|
8984
|
+
!mobile && isOpen && hasChildren && item.children && triggerEl && /* @__PURE__ */ jsx(
|
|
8957
8985
|
CompactFlyout,
|
|
8958
8986
|
{
|
|
8959
8987
|
parentLabel: item.label,
|
|
8960
8988
|
items: item.children,
|
|
8961
|
-
anchorEl:
|
|
8989
|
+
anchorEl: triggerEl,
|
|
8962
8990
|
portalContainer,
|
|
8963
8991
|
onItemClick,
|
|
8964
8992
|
onClose,
|
|
@@ -8972,7 +9000,7 @@ function CompactNavItem({
|
|
|
8972
9000
|
onClick: () => onItemClick?.(child, ci),
|
|
8973
9001
|
className: cn(
|
|
8974
9002
|
"flex items-center gap-ds-2 px-ds-3 py-ds-1.5 text-[length:var(--ds-font-size-xs)] rounded-[var(--ds-radius-sm)] transition-colors cursor-pointer w-full",
|
|
8975
|
-
child.active ? "bg-sidebar-
|
|
9003
|
+
child.active ? "bg-[var(--ds-sidebar-active-bg)] text-[var(--ds-sidebar-active-accent)] font-medium" : "text-[var(--ds-sidebar-text-muted)] hover:bg-[var(--ds-sidebar-item-hover)] hover:text-[var(--ds-sidebar-text)]"
|
|
8976
9004
|
),
|
|
8977
9005
|
children: [
|
|
8978
9006
|
child.icon && /* @__PURE__ */ jsx(Icon, { name: child.icon, size: 14, className: "shrink-0" }),
|
|
@@ -9948,6 +9976,187 @@ function Dock({
|
|
|
9948
9976
|
}
|
|
9949
9977
|
);
|
|
9950
9978
|
}
|
|
9979
|
+
function Sheet({ open, onClose, title, children, footer, snapPoints = [0.5, 0.92], container, flush }) {
|
|
9980
|
+
const titleId = useId();
|
|
9981
|
+
const panelRef = useRef(null);
|
|
9982
|
+
const [mounted, setMounted] = useState(open);
|
|
9983
|
+
const [snapIdx, setSnapIdx] = useState(0);
|
|
9984
|
+
const [dragOffset, setDragOffset] = useState(0);
|
|
9985
|
+
const [dragging, setDragging] = useState(false);
|
|
9986
|
+
const dragStartY = useRef(0);
|
|
9987
|
+
const startHeight = useRef(0);
|
|
9988
|
+
const onCloseRef = useLatest(onClose);
|
|
9989
|
+
const [prevOpen, setPrevOpen] = useState(open);
|
|
9990
|
+
if (open !== prevOpen) {
|
|
9991
|
+
setPrevOpen(open);
|
|
9992
|
+
if (open) {
|
|
9993
|
+
setMounted(true);
|
|
9994
|
+
setSnapIdx(0);
|
|
9995
|
+
setDragOffset(0);
|
|
9996
|
+
}
|
|
9997
|
+
}
|
|
9998
|
+
const viewportHeight = useCallback(
|
|
9999
|
+
() => container instanceof HTMLElement ? container.clientHeight : window.innerHeight,
|
|
10000
|
+
[container]
|
|
10001
|
+
);
|
|
10002
|
+
function handleTransitionEnd() {
|
|
10003
|
+
if (!open) setMounted(false);
|
|
10004
|
+
}
|
|
10005
|
+
useReturnFocus(open);
|
|
10006
|
+
useEffect(() => {
|
|
10007
|
+
if (!open || !mounted) return;
|
|
10008
|
+
const raf = requestAnimationFrame(() => focusInitial(panelRef.current));
|
|
10009
|
+
return () => cancelAnimationFrame(raf);
|
|
10010
|
+
}, [open, mounted]);
|
|
10011
|
+
useEffect(() => {
|
|
10012
|
+
if (!open) return;
|
|
10013
|
+
const onKeyDown = (e) => {
|
|
10014
|
+
if (e.key === "Escape") onCloseRef.current();
|
|
10015
|
+
};
|
|
10016
|
+
document.addEventListener("keydown", onKeyDown);
|
|
10017
|
+
if (!container) lockBodyScroll();
|
|
10018
|
+
return () => {
|
|
10019
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
10020
|
+
if (!container) unlockBodyScroll();
|
|
10021
|
+
};
|
|
10022
|
+
}, [open, container, onCloseRef]);
|
|
10023
|
+
const handlePointerDown = useCallback((e) => {
|
|
10024
|
+
setDragging(true);
|
|
10025
|
+
dragStartY.current = e.clientY;
|
|
10026
|
+
startHeight.current = (snapPoints[snapIdx] ?? snapPoints[0]) * viewportHeight();
|
|
10027
|
+
setDragOffset(0);
|
|
10028
|
+
e.target.setPointerCapture(e.pointerId);
|
|
10029
|
+
}, [snapIdx, snapPoints, viewportHeight]);
|
|
10030
|
+
const handlePointerMove = useCallback((e) => {
|
|
10031
|
+
if (!dragging) return;
|
|
10032
|
+
const delta = dragStartY.current - e.clientY;
|
|
10033
|
+
setDragOffset(delta);
|
|
10034
|
+
}, [dragging]);
|
|
10035
|
+
const handlePointerUp = useCallback(() => {
|
|
10036
|
+
if (!dragging) return;
|
|
10037
|
+
setDragging(false);
|
|
10038
|
+
const currentHeightPx = startHeight.current + dragOffset;
|
|
10039
|
+
const currentFraction = currentHeightPx / viewportHeight();
|
|
10040
|
+
if (currentFraction < snapPoints[0] * 0.6) {
|
|
10041
|
+
onClose();
|
|
10042
|
+
setDragOffset(0);
|
|
10043
|
+
return;
|
|
10044
|
+
}
|
|
10045
|
+
let bestIdx = 0;
|
|
10046
|
+
let bestDist = Math.abs(currentFraction - snapPoints[0]);
|
|
10047
|
+
for (let i = 1; i < snapPoints.length; i++) {
|
|
10048
|
+
const dist = Math.abs(currentFraction - snapPoints[i]);
|
|
10049
|
+
if (dist < bestDist) {
|
|
10050
|
+
bestDist = dist;
|
|
10051
|
+
bestIdx = i;
|
|
10052
|
+
}
|
|
10053
|
+
}
|
|
10054
|
+
setSnapIdx(bestIdx);
|
|
10055
|
+
setDragOffset(0);
|
|
10056
|
+
}, [dragging, dragOffset, snapPoints, onClose, viewportHeight]);
|
|
10057
|
+
if (!mounted) return null;
|
|
10058
|
+
const baseHeight = (snapPoints[snapIdx] ?? snapPoints[0]) * 100;
|
|
10059
|
+
const heightUnit = container ? "%" : "vh";
|
|
10060
|
+
const dragPx = dragging ? dragOffset : 0;
|
|
10061
|
+
const positionClass = container ? "absolute" : "fixed";
|
|
10062
|
+
return createPortal(
|
|
10063
|
+
/* @__PURE__ */ jsxs(
|
|
10064
|
+
"div",
|
|
10065
|
+
{
|
|
10066
|
+
className: cn(
|
|
10067
|
+
`${positionClass} inset-0 z-[var(--ds-z-modal)] transition-opacity duration-[var(--ds-transition-speed)]`,
|
|
10068
|
+
open ? "pointer-events-auto" : "pointer-events-none"
|
|
10069
|
+
),
|
|
10070
|
+
onTransitionEnd: handleTransitionEnd,
|
|
10071
|
+
children: [
|
|
10072
|
+
/* @__PURE__ */ jsx(
|
|
10073
|
+
"div",
|
|
10074
|
+
{
|
|
10075
|
+
className: cn(
|
|
10076
|
+
"absolute inset-0 bg-black/50 transition-opacity duration-[var(--ds-transition-speed)]",
|
|
10077
|
+
open ? "opacity-100" : "opacity-0"
|
|
10078
|
+
),
|
|
10079
|
+
onClick: onClose
|
|
10080
|
+
}
|
|
10081
|
+
),
|
|
10082
|
+
/* @__PURE__ */ jsxs(
|
|
10083
|
+
"div",
|
|
10084
|
+
{
|
|
10085
|
+
ref: panelRef,
|
|
10086
|
+
role: "dialog",
|
|
10087
|
+
"aria-modal": "true",
|
|
10088
|
+
"aria-labelledby": title ? titleId : void 0,
|
|
10089
|
+
"data-ds-sheet": "",
|
|
10090
|
+
className: cn(
|
|
10091
|
+
`${positionClass} bottom-0 left-0 right-0 z-10 flex flex-col`,
|
|
10092
|
+
"bg-[var(--ds-bg-surface)] text-[var(--ds-text-primary)]",
|
|
10093
|
+
GLASS_OVERLAY,
|
|
10094
|
+
"border-t-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
10095
|
+
"rounded-t-[var(--ds-radius-xl)]",
|
|
10096
|
+
!dragging && "transition-[transform,height] duration-[var(--ds-transition-speed)] ease-[var(--ds-transition-ease)]",
|
|
10097
|
+
open ? "translate-y-0" : "translate-y-full"
|
|
10098
|
+
),
|
|
10099
|
+
style: {
|
|
10100
|
+
containerType: "inline-size",
|
|
10101
|
+
height: dragPx ? `calc(${baseHeight}${heightUnit} + ${dragPx}px)` : `${baseHeight}${heightUnit}`
|
|
10102
|
+
},
|
|
10103
|
+
children: [
|
|
10104
|
+
/* @__PURE__ */ jsx(
|
|
10105
|
+
"div",
|
|
10106
|
+
{
|
|
10107
|
+
className: "flex justify-center pt-ds-2 pb-ds-1 cursor-grab active:cursor-grabbing touch-none",
|
|
10108
|
+
onPointerDown: handlePointerDown,
|
|
10109
|
+
onPointerMove: handlePointerMove,
|
|
10110
|
+
onPointerUp: handlePointerUp,
|
|
10111
|
+
onPointerCancel: handlePointerUp,
|
|
10112
|
+
children: /* @__PURE__ */ jsx("div", { className: "w-10 h-1 rounded-[var(--ds-radius-full)] bg-[var(--ds-border-default)]" })
|
|
10113
|
+
}
|
|
10114
|
+
),
|
|
10115
|
+
title && /* @__PURE__ */ jsxs(
|
|
10116
|
+
"div",
|
|
10117
|
+
{
|
|
10118
|
+
className: "flex items-center justify-between shrink-0 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
|
|
10119
|
+
style: { padding: "var(--ds-space-2) var(--ds-space-5)" },
|
|
10120
|
+
children: [
|
|
10121
|
+
/* @__PURE__ */ jsx("h2", { id: titleId, className: "font-[family-name:var(--ds-font-display)] text-lg font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)] truncate", children: title }),
|
|
10122
|
+
/* @__PURE__ */ jsx(
|
|
10123
|
+
"button",
|
|
10124
|
+
{
|
|
10125
|
+
onClick: onClose,
|
|
10126
|
+
...{ [OVERLAY_CLOSE_ATTR]: "" },
|
|
10127
|
+
className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer",
|
|
10128
|
+
"aria-label": "Close",
|
|
10129
|
+
children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 18 })
|
|
10130
|
+
}
|
|
10131
|
+
)
|
|
10132
|
+
]
|
|
10133
|
+
}
|
|
10134
|
+
),
|
|
10135
|
+
/* @__PURE__ */ jsx(
|
|
10136
|
+
"div",
|
|
10137
|
+
{
|
|
10138
|
+
className: "flex-1 overflow-y-auto",
|
|
10139
|
+
style: flush ? void 0 : { padding: "var(--ds-space-5)" },
|
|
10140
|
+
children
|
|
10141
|
+
}
|
|
10142
|
+
),
|
|
10143
|
+
footer && /* @__PURE__ */ jsx(
|
|
10144
|
+
"div",
|
|
10145
|
+
{
|
|
10146
|
+
className: "shrink-0 flex items-center justify-end gap-ds-2 border-t-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
|
|
10147
|
+
style: { padding: "var(--ds-space-3) var(--ds-space-5)" },
|
|
10148
|
+
children: footer
|
|
10149
|
+
}
|
|
10150
|
+
)
|
|
10151
|
+
]
|
|
10152
|
+
}
|
|
10153
|
+
)
|
|
10154
|
+
]
|
|
10155
|
+
}
|
|
10156
|
+
),
|
|
10157
|
+
container ?? document.body
|
|
10158
|
+
);
|
|
10159
|
+
}
|
|
9951
10160
|
var slideClasses = {
|
|
9952
10161
|
right: {
|
|
9953
10162
|
panel: "top-0 right-0 h-full",
|
|
@@ -9970,19 +10179,23 @@ var borderByPosition = {
|
|
|
9970
10179
|
left: "border-r-[length:var(--ds-border-width)] border-r-[var(--ds-border-default)]",
|
|
9971
10180
|
bottom: "border-t-[length:var(--ds-border-width)] border-t-[var(--ds-border-default)]"
|
|
9972
10181
|
};
|
|
9973
|
-
function Drawer(
|
|
10182
|
+
function Drawer(props) {
|
|
10183
|
+
const { position = "right", mobile, snapPoints, open, onClose, title, children, footer, container, flush } = props;
|
|
10184
|
+
const isPhone = useBreakpoint("sm");
|
|
10185
|
+
const mobileMode = mobile ?? (position === "left" ? "panel" : "sheet");
|
|
10186
|
+
if (isPhone && mobileMode === "sheet") {
|
|
10187
|
+
return /* @__PURE__ */ jsx(Sheet, { open, onClose, title, footer, container, flush, snapPoints, children });
|
|
10188
|
+
}
|
|
10189
|
+
return /* @__PURE__ */ jsx(DrawerPanel, { ...props });
|
|
10190
|
+
}
|
|
10191
|
+
function DrawerPanel({ open, onClose, position = "right", width = "400px", title, children, footer, container, flush, lightBackdrop, topOffset }) {
|
|
9974
10192
|
const titleId = useId();
|
|
9975
10193
|
const { ref: titleOverflowRef, isTruncated: titleTruncated } = useTextOverflow({ lines: 1 });
|
|
9976
10194
|
const isMobile = useBreakpoint("sm");
|
|
9977
10195
|
const panelRef = useRef(null);
|
|
9978
|
-
const [mounted, setMounted] = useState(
|
|
9979
|
-
const onCloseRef =
|
|
9980
|
-
|
|
9981
|
-
useEffect(() => {
|
|
9982
|
-
if (open) {
|
|
9983
|
-
setMounted(true);
|
|
9984
|
-
}
|
|
9985
|
-
}, [open]);
|
|
10196
|
+
const [mounted, setMounted] = useState(open);
|
|
10197
|
+
const onCloseRef = useLatest(onClose);
|
|
10198
|
+
if (open && !mounted) setMounted(true);
|
|
9986
10199
|
function handleTransitionEnd() {
|
|
9987
10200
|
if (!open) setMounted(false);
|
|
9988
10201
|
}
|
|
@@ -9997,7 +10210,7 @@ function Drawer({ open, onClose, position = "right", width = "400px", title, chi
|
|
|
9997
10210
|
document.removeEventListener("keydown", onKeyDown);
|
|
9998
10211
|
if (!container) unlockBodyScroll();
|
|
9999
10212
|
};
|
|
10000
|
-
}, [open, container]);
|
|
10213
|
+
}, [open, container, onCloseRef]);
|
|
10001
10214
|
useReturnFocus(open);
|
|
10002
10215
|
useEffect(() => {
|
|
10003
10216
|
if (!open || !mounted) return;
|
|
@@ -10132,13 +10345,13 @@ var AppShell = forwardRef(function AppShell2({
|
|
|
10132
10345
|
const hasMobileMenu = mobileMenu != null;
|
|
10133
10346
|
const hasMobileNav = mobileNav != null;
|
|
10134
10347
|
const showMobileDrawer = hasMobileMenu && !(isSmallMobile && hasMobileNav);
|
|
10135
|
-
const
|
|
10348
|
+
const [shellEl, setShellEl] = useState(null);
|
|
10136
10349
|
return /* @__PURE__ */ jsx(
|
|
10137
10350
|
AppShellContext,
|
|
10138
10351
|
{
|
|
10139
10352
|
value: { hasSidebar, hasMobileMenu, hasMobileNav, sidebarOpen, setSidebarOpen, isMobile, isTablet },
|
|
10140
10353
|
children: /* @__PURE__ */ jsxs("div", { ref: (el) => {
|
|
10141
|
-
|
|
10354
|
+
setShellEl(el);
|
|
10142
10355
|
if (typeof ref === "function") ref(el);
|
|
10143
10356
|
else if (ref) ref.current = el;
|
|
10144
10357
|
}, className: cn("relative h-screen flex flex-col bg-[var(--ds-bg-canvas)] overflow-hidden", className), children: [
|
|
@@ -10170,7 +10383,7 @@ var AppShell = forwardRef(function AppShell2({
|
|
|
10170
10383
|
onClose: () => setSidebarOpen(false),
|
|
10171
10384
|
position: "left",
|
|
10172
10385
|
width: mobileMenuWidth ?? "var(--ds-drawer-width)",
|
|
10173
|
-
container:
|
|
10386
|
+
container: shellEl ?? void 0,
|
|
10174
10387
|
flush: mobileMenuFlush,
|
|
10175
10388
|
lightBackdrop: mobileMenuLightBackdrop,
|
|
10176
10389
|
topOffset: layout !== "stacked" && navbar != null ? "var(--ds-navbar-height)" : void 0,
|
|
@@ -10182,10 +10395,13 @@ var AppShell = forwardRef(function AppShell2({
|
|
|
10182
10395
|
}
|
|
10183
10396
|
);
|
|
10184
10397
|
});
|
|
10185
|
-
|
|
10398
|
+
function resolveNavItemType(type) {
|
|
10399
|
+
return type === "default" ? "tint" : type;
|
|
10400
|
+
}
|
|
10401
|
+
var NavbarTypeContext = createContext("tint");
|
|
10186
10402
|
var NavItem = forwardRef(function NavItem2({ label, icon, active = false, href, onClick, type: typeProp, className, children }, ref) {
|
|
10187
10403
|
const contextType = useContext(NavbarTypeContext);
|
|
10188
|
-
const type = typeProp ?? contextType;
|
|
10404
|
+
const type = resolveNavItemType(typeProp ?? contextType);
|
|
10189
10405
|
const baseClasses = cn(
|
|
10190
10406
|
"inline-flex items-center gap-ds-2 cursor-pointer select-none",
|
|
10191
10407
|
"transition-colors duration-[var(--ds-transition-speed)] ease-[var(--ds-transition-ease)]",
|
|
@@ -10217,6 +10433,11 @@ var NavItem = forwardRef(function NavItem2({ label, icon, active = false, href,
|
|
|
10217
10433
|
});
|
|
10218
10434
|
function getTypeClasses(type, active) {
|
|
10219
10435
|
switch (type) {
|
|
10436
|
+
case "pill":
|
|
10437
|
+
return cn(
|
|
10438
|
+
"px-ds-2 py-ds-1 rounded-[var(--ds-radius-sm)]",
|
|
10439
|
+
active ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)] font-[var(--ds-weight-heading)]" : "text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]"
|
|
10440
|
+
);
|
|
10220
10441
|
case "underline":
|
|
10221
10442
|
return cn(
|
|
10222
10443
|
"px-ds-2 py-ds-2 relative",
|
|
@@ -10227,7 +10448,7 @@ function getTypeClasses(type, active) {
|
|
|
10227
10448
|
"px-ds-2 py-ds-1",
|
|
10228
10449
|
active ? "text-[var(--ds-accent-primary)] font-medium" : "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-secondary)]"
|
|
10229
10450
|
);
|
|
10230
|
-
|
|
10451
|
+
case "tint":
|
|
10231
10452
|
return cn(
|
|
10232
10453
|
"px-ds-2 py-ds-1 rounded-[var(--ds-radius-sm)]",
|
|
10233
10454
|
active ? "bg-[var(--ds-accent-subtle)] text-[var(--ds-accent-primary)] font-[var(--ds-weight-heading)]" : "text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]"
|
|
@@ -10261,7 +10482,7 @@ var Navbar = forwardRef(function Navbar2({
|
|
|
10261
10482
|
actions,
|
|
10262
10483
|
userMenu,
|
|
10263
10484
|
variant = "default",
|
|
10264
|
-
type = "
|
|
10485
|
+
type: typeProp = "tint",
|
|
10265
10486
|
align = "left",
|
|
10266
10487
|
size,
|
|
10267
10488
|
position = "flush",
|
|
@@ -10275,6 +10496,7 @@ var Navbar = forwardRef(function Navbar2({
|
|
|
10275
10496
|
const showHamburger = appShell?.isMobile && appShell.hasMobileMenu && !(isSmallPhone && appShell.hasMobileNav) || !!onMenuClick;
|
|
10276
10497
|
const handleHamburger = () => onMenuClick ? onMenuClick() : appShell?.setSidebarOpen(!appShell.sidebarOpen);
|
|
10277
10498
|
const hideNavLinks = appShell?.isMobile && (appShell.hasMobileMenu || appShell.hasMobileNav);
|
|
10499
|
+
const type = resolveNavItemType(typeProp);
|
|
10278
10500
|
const isMinimal = type === "minimal";
|
|
10279
10501
|
const isFloating = position === "floating";
|
|
10280
10502
|
const resolvedSize = size ?? (variant === "compact" ? "sm" : "md");
|
|
@@ -10381,7 +10603,7 @@ function NavMenu({
|
|
|
10381
10603
|
label,
|
|
10382
10604
|
items,
|
|
10383
10605
|
active = false,
|
|
10384
|
-
type = "
|
|
10606
|
+
type = "tint",
|
|
10385
10607
|
onItemClick,
|
|
10386
10608
|
className
|
|
10387
10609
|
}) {
|
|
@@ -10421,6 +10643,7 @@ function NavMenu({
|
|
|
10421
10643
|
);
|
|
10422
10644
|
const isUnderline = type === "underline";
|
|
10423
10645
|
const isMinimal = type === "minimal";
|
|
10646
|
+
const isPill = type === "pill";
|
|
10424
10647
|
const triggerClasses = cn(
|
|
10425
10648
|
"inline-flex items-center gap-ds-1 cursor-pointer transition-colors whitespace-nowrap",
|
|
10426
10649
|
"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
@@ -10430,9 +10653,14 @@ function NavMenu({
|
|
|
10430
10653
|
) : isMinimal ? cn(
|
|
10431
10654
|
"px-ds-2 py-ds-1 text-sm",
|
|
10432
10655
|
hasActiveChild ? "text-[var(--ds-text-primary)] font-medium" : "text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)]"
|
|
10656
|
+
) : isPill ? cn(
|
|
10657
|
+
"px-ds-3 py-ds-1.5 text-sm rounded-[var(--ds-radius-md)]",
|
|
10658
|
+
hasActiveChild ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)] font-medium" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]"
|
|
10433
10659
|
) : cn(
|
|
10660
|
+
// tint (and the deprecated `default` alias) — the same soft accent fill
|
|
10661
|
+
// NavItem uses, so a menu trigger and a link read as one row (decision 30).
|
|
10434
10662
|
"px-ds-3 py-ds-1.5 text-sm rounded-[var(--ds-radius-md)]",
|
|
10435
|
-
hasActiveChild ? "bg-[var(--ds-
|
|
10663
|
+
hasActiveChild ? "bg-[var(--ds-accent-subtle)] text-[var(--ds-accent-primary)] font-medium" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]"
|
|
10436
10664
|
),
|
|
10437
10665
|
className
|
|
10438
10666
|
);
|
|
@@ -10519,7 +10747,9 @@ function NavMenuItemRow({
|
|
|
10519
10747
|
},
|
|
10520
10748
|
className: cn(
|
|
10521
10749
|
"flex items-center gap-ds-2 mx-ds-1 px-ds-2 py-ds-1.5 rounded-[var(--ds-radius-sm)] transition-colors cursor-pointer",
|
|
10522
|
-
|
|
10750
|
+
// The active row takes the accent tint like an active NavItem; it marks
|
|
10751
|
+
// the current page, not a hover.
|
|
10752
|
+
item.active ? "bg-[var(--ds-accent-subtle)] text-[var(--ds-accent-primary)] font-medium" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]"
|
|
10523
10753
|
),
|
|
10524
10754
|
children: [
|
|
10525
10755
|
item.icon && /* @__PURE__ */ jsx(
|
|
@@ -10562,7 +10792,7 @@ function NavMenuGroup({
|
|
|
10562
10792
|
))
|
|
10563
10793
|
] });
|
|
10564
10794
|
}
|
|
10565
|
-
function MobileHeaderMenu({ items, type = "
|
|
10795
|
+
function MobileHeaderMenu({ items, type = "tint", onItemClick, className }) {
|
|
10566
10796
|
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(
|
|
10567
10797
|
MobileMenuItem,
|
|
10568
10798
|
{
|
|
@@ -10619,6 +10849,23 @@ function MobileMenuItem({
|
|
|
10619
10849
|
}
|
|
10620
10850
|
);
|
|
10621
10851
|
}
|
|
10852
|
+
if (type === "pill") {
|
|
10853
|
+
return /* @__PURE__ */ jsxs(
|
|
10854
|
+
"button",
|
|
10855
|
+
{
|
|
10856
|
+
onClick,
|
|
10857
|
+
className: cn(
|
|
10858
|
+
"flex items-center gap-ds-3 px-ds-3 py-ds-2.5 text-sm rounded-[var(--ds-radius-md)] cursor-pointer w-full text-left",
|
|
10859
|
+
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
10860
|
+
item.active ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)] font-[var(--ds-weight-heading)]" : "text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]"
|
|
10861
|
+
),
|
|
10862
|
+
children: [
|
|
10863
|
+
item.icon && /* @__PURE__ */ jsx(Icon, { name: item.icon, size: 18, className: "shrink-0" }),
|
|
10864
|
+
/* @__PURE__ */ jsx("span", { children: item.label })
|
|
10865
|
+
]
|
|
10866
|
+
}
|
|
10867
|
+
);
|
|
10868
|
+
}
|
|
10622
10869
|
return /* @__PURE__ */ jsxs(
|
|
10623
10870
|
"button",
|
|
10624
10871
|
{
|
|
@@ -10649,8 +10896,7 @@ function Dialog({ open, onClose, title, description, children, footer, variant =
|
|
|
10649
10896
|
const overlayRef = useRef(null);
|
|
10650
10897
|
const dialogRef = useRef(null);
|
|
10651
10898
|
const triggerRef = useRef(null);
|
|
10652
|
-
const onCloseRef =
|
|
10653
|
-
onCloseRef.current = onClose;
|
|
10899
|
+
const onCloseRef = useLatest(onClose);
|
|
10654
10900
|
const trapFocus = useCallback((e) => {
|
|
10655
10901
|
if (e.key !== "Tab" || !dialogRef.current) return;
|
|
10656
10902
|
const focusable = dialogRef.current.querySelectorAll(FOCUSABLE);
|
|
@@ -10686,7 +10932,7 @@ function Dialog({ open, onClose, title, description, children, footer, variant =
|
|
|
10686
10932
|
return () => {
|
|
10687
10933
|
document.removeEventListener("keydown", handler);
|
|
10688
10934
|
};
|
|
10689
|
-
}, [open, trapFocus, alert]);
|
|
10935
|
+
}, [open, trapFocus, alert, onCloseRef]);
|
|
10690
10936
|
useEffect(() => {
|
|
10691
10937
|
if (!open) return;
|
|
10692
10938
|
lockBodyScroll();
|
|
@@ -10798,16 +11044,22 @@ function CommandPalette({ open, onOpenChange, commands, placeholder = "Type a co
|
|
|
10798
11044
|
groups.get(g).push(cmd);
|
|
10799
11045
|
}
|
|
10800
11046
|
const flatFiltered = filtered;
|
|
10801
|
-
|
|
11047
|
+
const [prevOpen, setPrevOpen] = useState(open);
|
|
11048
|
+
if (open !== prevOpen) {
|
|
11049
|
+
setPrevOpen(open);
|
|
10802
11050
|
if (open) {
|
|
10803
11051
|
setQuery("");
|
|
10804
11052
|
setSelectedIdx(0);
|
|
10805
|
-
requestAnimationFrame(() => inputRef.current?.focus());
|
|
10806
11053
|
}
|
|
10807
|
-
}
|
|
10808
|
-
|
|
11054
|
+
}
|
|
11055
|
+
const [prevQuery, setPrevQuery] = useState(query);
|
|
11056
|
+
if (query !== prevQuery) {
|
|
11057
|
+
setPrevQuery(query);
|
|
10809
11058
|
setSelectedIdx(0);
|
|
10810
|
-
}
|
|
11059
|
+
}
|
|
11060
|
+
useEffect(() => {
|
|
11061
|
+
if (open) requestAnimationFrame(() => inputRef.current?.focus());
|
|
11062
|
+
}, [open]);
|
|
10811
11063
|
useEffect(() => {
|
|
10812
11064
|
if (!open) return;
|
|
10813
11065
|
const handler = (e) => {
|
|
@@ -10823,23 +11075,20 @@ function CommandPalette({ open, onOpenChange, commands, placeholder = "Type a co
|
|
|
10823
11075
|
},
|
|
10824
11076
|
[onOpenChange]
|
|
10825
11077
|
);
|
|
10826
|
-
const handleKeyDown =
|
|
10827
|
-
(e)
|
|
10828
|
-
|
|
10829
|
-
|
|
10830
|
-
|
|
10831
|
-
|
|
10832
|
-
|
|
10833
|
-
|
|
10834
|
-
|
|
10835
|
-
|
|
10836
|
-
|
|
10837
|
-
|
|
10838
|
-
|
|
10839
|
-
|
|
10840
|
-
},
|
|
10841
|
-
[flatFiltered, selectedIdx, handleSelect]
|
|
10842
|
-
);
|
|
11078
|
+
const handleKeyDown = (e) => {
|
|
11079
|
+
if (e.key === "ArrowDown") {
|
|
11080
|
+
e.preventDefault();
|
|
11081
|
+
setSelectedIdx((prev) => Math.min(prev + 1, flatFiltered.length - 1));
|
|
11082
|
+
listRef.current?.children[Math.min(selectedIdx + 1, flatFiltered.length - 1)]?.scrollIntoView({ block: "nearest" });
|
|
11083
|
+
} else if (e.key === "ArrowUp") {
|
|
11084
|
+
e.preventDefault();
|
|
11085
|
+
setSelectedIdx((prev) => Math.max(prev - 1, 0));
|
|
11086
|
+
listRef.current?.children[Math.max(selectedIdx - 1, 0)]?.scrollIntoView({ block: "nearest" });
|
|
11087
|
+
} else if (e.key === "Enter" && flatFiltered[selectedIdx]) {
|
|
11088
|
+
e.preventDefault();
|
|
11089
|
+
handleSelect(flatFiltered[selectedIdx]);
|
|
11090
|
+
}
|
|
11091
|
+
};
|
|
10843
11092
|
if (!open) return null;
|
|
10844
11093
|
let flatIdx = 0;
|
|
10845
11094
|
return createPortal(
|
|
@@ -11132,179 +11381,6 @@ function ContextMenu({ items, children, className, ref, container }) {
|
|
|
11132
11381
|
}
|
|
11133
11382
|
);
|
|
11134
11383
|
}
|
|
11135
|
-
function Sheet({ open, onClose, title, children, footer, snapPoints = [0.5, 0.92] }) {
|
|
11136
|
-
const titleId = useId();
|
|
11137
|
-
const panelRef = useRef(null);
|
|
11138
|
-
const [mounted, setMounted] = useState(false);
|
|
11139
|
-
const [snapIdx, setSnapIdx] = useState(0);
|
|
11140
|
-
const [dragOffset, setDragOffset] = useState(0);
|
|
11141
|
-
const isDragging = useRef(false);
|
|
11142
|
-
const dragStartY = useRef(0);
|
|
11143
|
-
const startHeight = useRef(0);
|
|
11144
|
-
const onCloseRef = useRef(onClose);
|
|
11145
|
-
onCloseRef.current = onClose;
|
|
11146
|
-
useEffect(() => {
|
|
11147
|
-
if (open) {
|
|
11148
|
-
setMounted(true);
|
|
11149
|
-
setSnapIdx(0);
|
|
11150
|
-
setDragOffset(0);
|
|
11151
|
-
}
|
|
11152
|
-
}, [open]);
|
|
11153
|
-
function handleTransitionEnd() {
|
|
11154
|
-
if (!open) setMounted(false);
|
|
11155
|
-
}
|
|
11156
|
-
useReturnFocus(open);
|
|
11157
|
-
useEffect(() => {
|
|
11158
|
-
if (!open || !mounted) return;
|
|
11159
|
-
const raf = requestAnimationFrame(() => focusInitial(panelRef.current));
|
|
11160
|
-
return () => cancelAnimationFrame(raf);
|
|
11161
|
-
}, [open, mounted]);
|
|
11162
|
-
useEffect(() => {
|
|
11163
|
-
if (!open) return;
|
|
11164
|
-
const onKeyDown = (e) => {
|
|
11165
|
-
if (e.key === "Escape") onCloseRef.current();
|
|
11166
|
-
};
|
|
11167
|
-
document.addEventListener("keydown", onKeyDown);
|
|
11168
|
-
lockBodyScroll();
|
|
11169
|
-
return () => {
|
|
11170
|
-
document.removeEventListener("keydown", onKeyDown);
|
|
11171
|
-
unlockBodyScroll();
|
|
11172
|
-
};
|
|
11173
|
-
}, [open]);
|
|
11174
|
-
const handlePointerDown = useCallback((e) => {
|
|
11175
|
-
isDragging.current = true;
|
|
11176
|
-
dragStartY.current = e.clientY;
|
|
11177
|
-
startHeight.current = (snapPoints[snapIdx] ?? snapPoints[0]) * window.innerHeight;
|
|
11178
|
-
setDragOffset(0);
|
|
11179
|
-
e.target.setPointerCapture(e.pointerId);
|
|
11180
|
-
}, [snapIdx, snapPoints]);
|
|
11181
|
-
const handlePointerMove = useCallback((e) => {
|
|
11182
|
-
if (!isDragging.current) return;
|
|
11183
|
-
const delta = dragStartY.current - e.clientY;
|
|
11184
|
-
setDragOffset(delta);
|
|
11185
|
-
}, []);
|
|
11186
|
-
const handlePointerUp = useCallback(() => {
|
|
11187
|
-
if (!isDragging.current) return;
|
|
11188
|
-
isDragging.current = false;
|
|
11189
|
-
const currentHeightPx = startHeight.current + dragOffset;
|
|
11190
|
-
const currentFraction = currentHeightPx / window.innerHeight;
|
|
11191
|
-
if (currentFraction < snapPoints[0] * 0.6) {
|
|
11192
|
-
onClose();
|
|
11193
|
-
setDragOffset(0);
|
|
11194
|
-
return;
|
|
11195
|
-
}
|
|
11196
|
-
let bestIdx = 0;
|
|
11197
|
-
let bestDist = Math.abs(currentFraction - snapPoints[0]);
|
|
11198
|
-
for (let i = 1; i < snapPoints.length; i++) {
|
|
11199
|
-
const dist = Math.abs(currentFraction - snapPoints[i]);
|
|
11200
|
-
if (dist < bestDist) {
|
|
11201
|
-
bestDist = dist;
|
|
11202
|
-
bestIdx = i;
|
|
11203
|
-
}
|
|
11204
|
-
}
|
|
11205
|
-
setSnapIdx(bestIdx);
|
|
11206
|
-
setDragOffset(0);
|
|
11207
|
-
}, [dragOffset, snapPoints, onClose]);
|
|
11208
|
-
if (!mounted) return null;
|
|
11209
|
-
const baseHeightVh = (snapPoints[snapIdx] ?? snapPoints[0]) * 100;
|
|
11210
|
-
const dragPx = isDragging.current ? dragOffset : 0;
|
|
11211
|
-
return createPortal(
|
|
11212
|
-
/* @__PURE__ */ jsxs(
|
|
11213
|
-
"div",
|
|
11214
|
-
{
|
|
11215
|
-
className: cn(
|
|
11216
|
-
"fixed inset-0 z-[var(--ds-z-modal)] transition-opacity duration-[var(--ds-transition-speed)]",
|
|
11217
|
-
open ? "pointer-events-auto" : "pointer-events-none"
|
|
11218
|
-
),
|
|
11219
|
-
onTransitionEnd: handleTransitionEnd,
|
|
11220
|
-
children: [
|
|
11221
|
-
/* @__PURE__ */ jsx(
|
|
11222
|
-
"div",
|
|
11223
|
-
{
|
|
11224
|
-
className: cn(
|
|
11225
|
-
"absolute inset-0 bg-black/50 transition-opacity duration-[var(--ds-transition-speed)]",
|
|
11226
|
-
open ? "opacity-100" : "opacity-0"
|
|
11227
|
-
),
|
|
11228
|
-
onClick: onClose
|
|
11229
|
-
}
|
|
11230
|
-
),
|
|
11231
|
-
/* @__PURE__ */ jsxs(
|
|
11232
|
-
"div",
|
|
11233
|
-
{
|
|
11234
|
-
ref: panelRef,
|
|
11235
|
-
role: "dialog",
|
|
11236
|
-
"aria-modal": "true",
|
|
11237
|
-
"aria-labelledby": title ? titleId : void 0,
|
|
11238
|
-
className: cn(
|
|
11239
|
-
"fixed bottom-0 left-0 right-0 z-10 flex flex-col",
|
|
11240
|
-
"bg-[var(--ds-bg-surface)] text-[var(--ds-text-primary)]",
|
|
11241
|
-
GLASS_OVERLAY,
|
|
11242
|
-
"border-t-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
11243
|
-
"rounded-t-[var(--ds-radius-xl)]",
|
|
11244
|
-
!isDragging.current && "transition-[transform,height] duration-[var(--ds-transition-speed)] ease-[var(--ds-transition-ease)]",
|
|
11245
|
-
open ? "translate-y-0" : "translate-y-full"
|
|
11246
|
-
),
|
|
11247
|
-
style: {
|
|
11248
|
-
containerType: "inline-size",
|
|
11249
|
-
height: dragPx ? `calc(${baseHeightVh}vh + ${dragPx}px)` : `${baseHeightVh}vh`
|
|
11250
|
-
},
|
|
11251
|
-
children: [
|
|
11252
|
-
/* @__PURE__ */ jsx(
|
|
11253
|
-
"div",
|
|
11254
|
-
{
|
|
11255
|
-
className: "flex justify-center pt-ds-2 pb-ds-1 cursor-grab active:cursor-grabbing touch-none",
|
|
11256
|
-
onPointerDown: handlePointerDown,
|
|
11257
|
-
onPointerMove: handlePointerMove,
|
|
11258
|
-
onPointerUp: handlePointerUp,
|
|
11259
|
-
onPointerCancel: handlePointerUp,
|
|
11260
|
-
children: /* @__PURE__ */ jsx("div", { className: "w-10 h-1 rounded-[var(--ds-radius-full)] bg-[var(--ds-border-default)]" })
|
|
11261
|
-
}
|
|
11262
|
-
),
|
|
11263
|
-
title && /* @__PURE__ */ jsxs(
|
|
11264
|
-
"div",
|
|
11265
|
-
{
|
|
11266
|
-
className: "flex items-center justify-between shrink-0 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
|
|
11267
|
-
style: { padding: "var(--ds-space-2) var(--ds-space-5)" },
|
|
11268
|
-
children: [
|
|
11269
|
-
/* @__PURE__ */ jsx("h2", { id: titleId, className: "font-[family-name:var(--ds-font-display)] text-lg font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)] truncate", children: title }),
|
|
11270
|
-
/* @__PURE__ */ jsx(
|
|
11271
|
-
"button",
|
|
11272
|
-
{
|
|
11273
|
-
onClick: onClose,
|
|
11274
|
-
...{ [OVERLAY_CLOSE_ATTR]: "" },
|
|
11275
|
-
className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer",
|
|
11276
|
-
"aria-label": "Close",
|
|
11277
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 18 })
|
|
11278
|
-
}
|
|
11279
|
-
)
|
|
11280
|
-
]
|
|
11281
|
-
}
|
|
11282
|
-
),
|
|
11283
|
-
/* @__PURE__ */ jsx(
|
|
11284
|
-
"div",
|
|
11285
|
-
{
|
|
11286
|
-
className: "flex-1 overflow-y-auto",
|
|
11287
|
-
style: { padding: "var(--ds-space-5)" },
|
|
11288
|
-
children
|
|
11289
|
-
}
|
|
11290
|
-
),
|
|
11291
|
-
footer && /* @__PURE__ */ jsx(
|
|
11292
|
-
"div",
|
|
11293
|
-
{
|
|
11294
|
-
className: "shrink-0 flex items-center justify-end gap-ds-2 border-t-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
|
|
11295
|
-
style: { padding: "var(--ds-space-3) var(--ds-space-5)" },
|
|
11296
|
-
children: footer
|
|
11297
|
-
}
|
|
11298
|
-
)
|
|
11299
|
-
]
|
|
11300
|
-
}
|
|
11301
|
-
)
|
|
11302
|
-
]
|
|
11303
|
-
}
|
|
11304
|
-
),
|
|
11305
|
-
document.body
|
|
11306
|
-
);
|
|
11307
|
-
}
|
|
11308
11384
|
function TruncTitle({ children }) {
|
|
11309
11385
|
const { ref, isTruncated } = useTextOverflow({ lines: 1 });
|
|
11310
11386
|
const el = /* @__PURE__ */ jsx("span", { ref, className: "truncate", children });
|
|
@@ -11335,7 +11411,10 @@ function NotificationCenter({
|
|
|
11335
11411
|
const [internalFilter, setInternalFilter] = useState("all");
|
|
11336
11412
|
const isControlled = controlledOpen !== void 0;
|
|
11337
11413
|
const open = isControlled ? controlledOpen : internalOpen;
|
|
11338
|
-
const setOpen =
|
|
11414
|
+
const setOpen = useCallback((v) => {
|
|
11415
|
+
if (isControlled) onOpenChange?.(v);
|
|
11416
|
+
else setInternalOpen(v);
|
|
11417
|
+
}, [isControlled, onOpenChange]);
|
|
11339
11418
|
const triggerRef = useRef(null);
|
|
11340
11419
|
const panelRef = useRef(null);
|
|
11341
11420
|
const pos = usePosition(triggerRef, panelRef, open, { side: "bottom", align: "end", offset: 8, flip: true });
|
|
@@ -11359,7 +11438,7 @@ function NotificationCenter({
|
|
|
11359
11438
|
document.removeEventListener("keydown", onKey);
|
|
11360
11439
|
document.removeEventListener("mousedown", onClick);
|
|
11361
11440
|
};
|
|
11362
|
-
}, [open]);
|
|
11441
|
+
}, [open, setOpen]);
|
|
11363
11442
|
const grouped = groupByDate(filteredNotifications);
|
|
11364
11443
|
if (variant === "page") {
|
|
11365
11444
|
return /* @__PURE__ */ jsxs("div", { ref, className: cn("w-full", className), children: [
|
|
@@ -11606,11 +11685,13 @@ function Tour({ steps, open, onClose, onComplete, container }) {
|
|
|
11606
11685
|
if (el) setRect(el.getBoundingClientRect());
|
|
11607
11686
|
else setRect(null);
|
|
11608
11687
|
}, [step]);
|
|
11688
|
+
const [prevOpen, setPrevOpen] = useState(open);
|
|
11689
|
+
if (open !== prevOpen) {
|
|
11690
|
+
setPrevOpen(open);
|
|
11691
|
+
if (!open) setCurrent(0);
|
|
11692
|
+
}
|
|
11609
11693
|
useEffect(() => {
|
|
11610
|
-
if (!open)
|
|
11611
|
-
setCurrent(0);
|
|
11612
|
-
return;
|
|
11613
|
-
}
|
|
11694
|
+
if (!open) return;
|
|
11614
11695
|
measureTarget();
|
|
11615
11696
|
window.addEventListener("resize", measureTarget);
|
|
11616
11697
|
window.addEventListener("scroll", measureTarget, true);
|
|
@@ -11619,16 +11700,6 @@ function Tour({ steps, open, onClose, onComplete, container }) {
|
|
|
11619
11700
|
window.removeEventListener("scroll", measureTarget, true);
|
|
11620
11701
|
};
|
|
11621
11702
|
}, [open, current, measureTarget]);
|
|
11622
|
-
useEffect(() => {
|
|
11623
|
-
if (!open) return;
|
|
11624
|
-
const onKey = (e) => {
|
|
11625
|
-
if (e.key === "Escape") onClose();
|
|
11626
|
-
else if (e.key === "ArrowRight") handleNext();
|
|
11627
|
-
else if (e.key === "ArrowLeft") handlePrev();
|
|
11628
|
-
};
|
|
11629
|
-
document.addEventListener("keydown", onKey);
|
|
11630
|
-
return () => document.removeEventListener("keydown", onKey);
|
|
11631
|
-
});
|
|
11632
11703
|
const handleNext = useCallback(() => {
|
|
11633
11704
|
if (current < steps.length - 1) setCurrent((c) => c + 1);
|
|
11634
11705
|
else {
|
|
@@ -11639,6 +11710,16 @@ function Tour({ steps, open, onClose, onComplete, container }) {
|
|
|
11639
11710
|
const handlePrev = useCallback(() => {
|
|
11640
11711
|
if (current > 0) setCurrent((c) => c - 1);
|
|
11641
11712
|
}, [current]);
|
|
11713
|
+
useEffect(() => {
|
|
11714
|
+
if (!open) return;
|
|
11715
|
+
const onKey = (e) => {
|
|
11716
|
+
if (e.key === "Escape") onClose();
|
|
11717
|
+
else if (e.key === "ArrowRight") handleNext();
|
|
11718
|
+
else if (e.key === "ArrowLeft") handlePrev();
|
|
11719
|
+
};
|
|
11720
|
+
document.addEventListener("keydown", onKey);
|
|
11721
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
11722
|
+
}, [open, onClose, handleNext, handlePrev]);
|
|
11642
11723
|
if (!open || !step) return null;
|
|
11643
11724
|
const padding = 8;
|
|
11644
11725
|
const spotlightRadius = 8;
|
|
@@ -11942,15 +12023,14 @@ function Toast({ variant = "default", message, visible, onDismiss, duration = 3e
|
|
|
11942
12023
|
const timerRef = useRef(void 0);
|
|
11943
12024
|
const startedAtRef = useRef(0);
|
|
11944
12025
|
const remainingRef = useRef(duration);
|
|
11945
|
-
const onDismissRef =
|
|
11946
|
-
onDismissRef.current = onDismiss;
|
|
12026
|
+
const onDismissRef = useLatest(onDismiss);
|
|
11947
12027
|
const startTimer = useCallback((ms) => {
|
|
11948
12028
|
const delay = ms ?? remainingRef.current;
|
|
11949
12029
|
remainingRef.current = delay;
|
|
11950
12030
|
startedAtRef.current = Date.now();
|
|
11951
12031
|
if (!Number.isFinite(delay) || delay <= 0) return;
|
|
11952
12032
|
timerRef.current = setTimeout(() => onDismissRef.current(), delay);
|
|
11953
|
-
}, []);
|
|
12033
|
+
}, [onDismissRef]);
|
|
11954
12034
|
const clearTimer = useCallback(() => {
|
|
11955
12035
|
if (timerRef.current) {
|
|
11956
12036
|
clearTimeout(timerRef.current);
|