@openspecui/web 2.3.2 → 2.3.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/dist/assets/CanvasRenderer-DLCesp1A.js +1 -0
- package/dist/assets/WebGLRenderer-DYT9IbsA.js +1 -0
- package/dist/assets/WebGPURenderer-CYfC6MR9.js +1 -0
- package/dist/assets/browserAll-CmR4zgGr.js +1 -0
- package/dist/assets/{dist-D3tpHX6Y.js → dist-5fi0H1tv.js} +1 -1
- package/dist/assets/{dist-DjPJlCHP.js → dist-9w-ZAZ0x.js} +1 -1
- package/dist/assets/{dist-NxlD47Et.js → dist-AstaMS2N.js} +1 -1
- package/dist/assets/{dist-AzZzg9Or.js → dist-BY07yBep.js} +1 -1
- package/dist/assets/dist-BkrPETxD.js +1 -0
- package/dist/assets/dist-DABwUepA.js +1 -0
- package/dist/assets/{dist-BLkBtxRp.js → dist-DDChZc3A.js} +1 -1
- package/dist/assets/{dist-704BMcqW.js → dist-DQMVt2X6.js} +1 -1
- package/dist/assets/{dist-CHbFRWhr.js → dist-DTgAMGJk.js} +1 -1
- package/dist/assets/{dist-BYskKa8I.js → dist-DtkkWh_t.js} +1 -1
- package/dist/assets/dist-hgHsmBgz.js +1 -0
- package/dist/assets/{dist-DICpu_MT.js → dist-j40sCais.js} +1 -1
- package/dist/assets/{ghostty-web-C70d-U4t.js → ghostty-web-BRCaoYqS.js} +1 -1
- package/dist/assets/index-C0tlID-0.css +1 -0
- package/dist/assets/index-CUgehjti.js +1578 -0
- package/dist/assets/{init-BWnHltxK.js → init-CIIgfU1P.js} +1 -1
- package/dist/assets/trpc-2zCd4YGO.js +1 -0
- package/dist/assets/webworkerAll-CwuSdyaU.js +1 -0
- package/dist/index.html +2 -2
- package/dist-ssg/client/.vite/ssr-manifest.json +18 -15
- package/dist-ssg/client/assets/CanvasRenderer-vRzYl9FZ.js +1 -0
- package/dist-ssg/client/assets/WebGLRenderer-BrfpRfdk.js +1 -0
- package/dist-ssg/client/assets/WebGPURenderer-r7TRWUkD.js +1 -0
- package/dist-ssg/client/assets/browserAll-D7igzN7y.js +1 -0
- package/dist-ssg/client/assets/{dist-C887n21g.js → dist-BFqpuvkT.js} +1 -1
- package/dist-ssg/client/assets/{dist-Dsknr6vA.js → dist-BNNep2NV.js} +1 -1
- package/dist-ssg/client/assets/{dist-hHeeK4R0.js → dist-B_u-l1Yw.js} +1 -1
- package/dist-ssg/client/assets/{dist-Bl--njTk.js → dist-CRvuTuq9.js} +1 -1
- package/dist-ssg/client/assets/{dist-C65ij9xh.js → dist-CXGBVAg6.js} +1 -1
- package/dist-ssg/client/assets/{dist-X2a3RXr4.js → dist-ClTBYSyP.js} +1 -1
- package/dist-ssg/client/assets/{dist-TuIRzaj8.js → dist-CmH6Ad9e.js} +1 -1
- package/dist-ssg/client/assets/{dist-Dv6uiUoE.js → dist-DBjExBIn.js} +1 -1
- package/dist-ssg/client/assets/{dist-eTaUIlfT.js → dist-DKZbBcYn.js} +1 -1
- package/dist-ssg/client/assets/dist-Ky-fb63H.js +1 -0
- package/dist-ssg/client/assets/dist-tjvftgmy.js +1 -0
- package/dist-ssg/client/assets/dist-y9aZTMms.js +1 -0
- package/dist-ssg/client/assets/{ghostty-web-CHBQyH7_.js → ghostty-web-PY5w9Rgq.js} +1 -1
- package/dist-ssg/client/assets/index-DvpLdKST.css +2 -0
- package/dist-ssg/client/assets/{index.ssg-DkyqyrXf.js → index.ssg-yS5IzoBe.js} +136 -146
- package/dist-ssg/client/assets/{init-BRd1iFqg.js → init-zJql3EoS.js} +1 -1
- package/dist-ssg/client/assets/trpc-Z2U-lHEj.js +1 -0
- package/dist-ssg/client/assets/webworkerAll-_OODBDte.js +1 -0
- package/dist-ssg/client/index.ssg.html +2 -2
- package/dist-ssg/server/entry-server.js +578 -83
- package/package.json +1 -1
- package/dist/assets/CanvasRenderer-XYe2KglB.js +0 -1
- package/dist/assets/WebGLRenderer-DCMbi58z.js +0 -1
- package/dist/assets/WebGPURenderer-D8qkuqdr.js +0 -1
- package/dist/assets/browserAll-haNDWq66.js +0 -1
- package/dist/assets/dist-BXHMHEwl.js +0 -1
- package/dist/assets/dist-D0pwQ8q9.js +0 -1
- package/dist/assets/dist-D_Ftxw8J.js +0 -1
- package/dist/assets/index-C5SoNGIA.css +0 -1
- package/dist/assets/index-Djyctzdp.js +0 -1588
- package/dist/assets/trpc-C7hf8_bp.js +0 -1
- package/dist/assets/webworkerAll-BXCHpnO9.js +0 -1
- package/dist-ssg/client/assets/CanvasRenderer-BVt34cwv.js +0 -1
- package/dist-ssg/client/assets/WebGLRenderer-DTGXjggz.js +0 -1
- package/dist-ssg/client/assets/WebGPURenderer-9B_42fBK.js +0 -1
- package/dist-ssg/client/assets/browserAll-DNt0Yfet.js +0 -1
- package/dist-ssg/client/assets/dist-CkOzcD72.js +0 -1
- package/dist-ssg/client/assets/dist-DuL-Iyhd.js +0 -1
- package/dist-ssg/client/assets/dist-_NPWTu8A.js +0 -1
- package/dist-ssg/client/assets/index-BE9cyYzu.css +0 -2
- package/dist-ssg/client/assets/trpc-BX7m8KYM.js +0 -1
- package/dist-ssg/client/assets/webworkerAll-C_Psgpip.js +0 -1
|
@@ -7433,7 +7433,7 @@ function useSearch(opts) {
|
|
|
7433
7433
|
}
|
|
7434
7434
|
//#endregion
|
|
7435
7435
|
//#region ../../node_modules/.pnpm/@tanstack+react-router@1.139.3_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/@tanstack/react-router/dist/esm/utils.js
|
|
7436
|
-
var useLayoutEffect$
|
|
7436
|
+
var useLayoutEffect$7 = typeof window !== "undefined" ? import_react.useLayoutEffect : import_react.useEffect;
|
|
7437
7437
|
function usePrevious(value) {
|
|
7438
7438
|
const ref = import_react.useRef({
|
|
7439
7439
|
value,
|
|
@@ -8353,7 +8353,7 @@ function Transitioner() {
|
|
|
8353
8353
|
unsub();
|
|
8354
8354
|
};
|
|
8355
8355
|
}, [router, router.history]);
|
|
8356
|
-
useLayoutEffect$
|
|
8356
|
+
useLayoutEffect$7(() => {
|
|
8357
8357
|
if (typeof window !== "undefined" && router.ssr || mountLoadForRouter.current.router === router && mountLoadForRouter.current.mounted) return;
|
|
8358
8358
|
mountLoadForRouter.current = {
|
|
8359
8359
|
router,
|
|
@@ -8368,7 +8368,7 @@ function Transitioner() {
|
|
|
8368
8368
|
};
|
|
8369
8369
|
tryLoad();
|
|
8370
8370
|
}, [router]);
|
|
8371
|
-
useLayoutEffect$
|
|
8371
|
+
useLayoutEffect$7(() => {
|
|
8372
8372
|
if (previousIsLoading && !isLoading) router.emit({
|
|
8373
8373
|
type: "onLoad",
|
|
8374
8374
|
...getLocationChangeInfo(router.state)
|
|
@@ -8378,7 +8378,7 @@ function Transitioner() {
|
|
|
8378
8378
|
router,
|
|
8379
8379
|
isLoading
|
|
8380
8380
|
]);
|
|
8381
|
-
useLayoutEffect$
|
|
8381
|
+
useLayoutEffect$7(() => {
|
|
8382
8382
|
if (previousIsPagePending && !isPagePending) router.emit({
|
|
8383
8383
|
type: "onBeforeRouteMount",
|
|
8384
8384
|
...getLocationChangeInfo(router.state)
|
|
@@ -8388,7 +8388,7 @@ function Transitioner() {
|
|
|
8388
8388
|
previousIsPagePending,
|
|
8389
8389
|
router
|
|
8390
8390
|
]);
|
|
8391
|
-
useLayoutEffect$
|
|
8391
|
+
useLayoutEffect$7(() => {
|
|
8392
8392
|
if (previousIsAnyPending && !isAnyPending) {
|
|
8393
8393
|
const changeInfo = getLocationChangeInfo(router.state);
|
|
8394
8394
|
router.emit({
|
|
@@ -39494,8 +39494,9 @@ function waitForDomCommit() {
|
|
|
39494
39494
|
setTimeout(finish, 0);
|
|
39495
39495
|
});
|
|
39496
39496
|
}
|
|
39497
|
-
function
|
|
39497
|
+
function filterAfterEntries(entries, beforeEntries, intent) {
|
|
39498
39498
|
if (beforeEntries.length === 0) return entries;
|
|
39499
|
+
if (intent.kind === "tab-carousel") return entries;
|
|
39499
39500
|
const beforeElements = new Set(beforeEntries.map(([element]) => element));
|
|
39500
39501
|
return entries.filter(([element]) => !beforeElements.has(element));
|
|
39501
39502
|
}
|
|
@@ -39503,15 +39504,15 @@ async function collectSettledAfterEntries(beforeEntries, collectAfterEntries, in
|
|
|
39503
39504
|
if (!collectAfterEntries) return [];
|
|
39504
39505
|
if (intent.kind === "route-detail" && beforeEntries.length > 0) return waitForNamedEntriesReady({
|
|
39505
39506
|
expectedNames: beforeEntries.map(([, name]) => name),
|
|
39506
|
-
collectEntries: () =>
|
|
39507
|
+
collectEntries: () => filterAfterEntries(collectAfterEntries(), beforeEntries, intent)
|
|
39507
39508
|
});
|
|
39508
39509
|
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
39509
|
-
const entries =
|
|
39510
|
+
const entries = filterAfterEntries(collectAfterEntries(), beforeEntries, intent);
|
|
39510
39511
|
if (entries.length > 0 || beforeEntries.length === 0) return entries;
|
|
39511
39512
|
await Promise.resolve();
|
|
39512
39513
|
await waitForDomCommit();
|
|
39513
39514
|
}
|
|
39514
|
-
return
|
|
39515
|
+
return filterAfterEntries(collectAfterEntries(), beforeEntries, intent);
|
|
39515
39516
|
}
|
|
39516
39517
|
function setIntentDataset(intent) {
|
|
39517
39518
|
const root = document.documentElement;
|
|
@@ -73681,16 +73682,6 @@ var tabsStyleText = (id) => {
|
|
|
73681
73682
|
transform: scaleX(0.5);
|
|
73682
73683
|
}
|
|
73683
73684
|
|
|
73684
|
-
#${id}[data-tabs-variant='default'] .tabs-button > button.tab-selected {
|
|
73685
|
-
background-image: linear-gradient(
|
|
73686
|
-
to bottom,
|
|
73687
|
-
transparent,
|
|
73688
|
-
transparent calc(100% - 2px),
|
|
73689
|
-
var(--primary) calc(100% - 2px),
|
|
73690
|
-
var(--primary)
|
|
73691
|
-
);
|
|
73692
|
-
}
|
|
73693
|
-
|
|
73694
73685
|
#${id} .tabs-strip {
|
|
73695
73686
|
background-image: linear-gradient(
|
|
73696
73687
|
to bottom,
|
|
@@ -73728,11 +73719,17 @@ function TabsImpl({ tabs, selectedTab: controlled, onTabChange, onTabClose, onTa
|
|
|
73728
73719
|
const dropIndicatorRef = (0, import_react.useRef)(null);
|
|
73729
73720
|
const contentOrderRef = (0, import_react.useRef)(tabs.map((tab) => tab.id));
|
|
73730
73721
|
const rootRef = (0, import_react.useRef)(null);
|
|
73722
|
+
const headerRef = (0, import_react.useRef)(null);
|
|
73723
|
+
const headerShellRef = (0, import_react.useRef)(null);
|
|
73724
|
+
const headerForegroundRef = (0, import_react.useRef)(null);
|
|
73725
|
+
const selectionIndicatorRef = (0, import_react.useRef)(null);
|
|
73726
|
+
const tabsButtonRef = (0, import_react.useRef)(null);
|
|
73731
73727
|
const triggerRefs = (0, import_react.useRef)(/* @__PURE__ */ new Map());
|
|
73732
73728
|
const panelRefs = (0, import_react.useRef)(/* @__PURE__ */ new Map());
|
|
73733
73729
|
const activeTab = controlled ?? uncontrolled;
|
|
73734
73730
|
const reorderable = typeof onTabOrderChange === "function" && tabs.length > 1;
|
|
73735
73731
|
const tabIds = tabs.map((tab) => tab.id);
|
|
73732
|
+
const tabLayoutSignature = tabIds.join("|");
|
|
73736
73733
|
const tabsById = (0, import_react.useMemo)(() => new Map(tabs.map((tab) => [tab.id, tab])), [tabs]);
|
|
73737
73734
|
const contentTabs = (0, import_react.useMemo)(() => {
|
|
73738
73735
|
const nextOrder = buildStableContentTabIds(contentOrderRef.current, tabIds);
|
|
@@ -73752,10 +73749,69 @@ function TabsImpl({ tabs, selectedTab: controlled, onTabChange, onTabClose, onTa
|
|
|
73752
73749
|
getPanel(tabId) {
|
|
73753
73750
|
return panelRefs.current.get(tabId) ?? null;
|
|
73754
73751
|
},
|
|
73752
|
+
getHeaderShell() {
|
|
73753
|
+
return headerShellRef.current;
|
|
73754
|
+
},
|
|
73755
|
+
getHeaderForeground() {
|
|
73756
|
+
return headerForegroundRef.current;
|
|
73757
|
+
},
|
|
73758
|
+
getSelectionIndicator() {
|
|
73759
|
+
return selectionIndicatorRef.current;
|
|
73760
|
+
},
|
|
73755
73761
|
getActiveTabId() {
|
|
73756
73762
|
return activeTab || null;
|
|
73757
73763
|
}
|
|
73758
73764
|
}), [activeTab]);
|
|
73765
|
+
const syncSelectionIndicator = (0, import_react.useCallback)(() => {
|
|
73766
|
+
const indicator = selectionIndicatorRef.current;
|
|
73767
|
+
const header = headerRef.current;
|
|
73768
|
+
const activeTrigger = activeTab ? triggerRefs.current.get(activeTab) : null;
|
|
73769
|
+
if (!indicator) return;
|
|
73770
|
+
if (variant !== "default" || !header || !activeTrigger) {
|
|
73771
|
+
indicator.style.opacity = "0";
|
|
73772
|
+
indicator.style.width = "0px";
|
|
73773
|
+
indicator.style.height = "0px";
|
|
73774
|
+
indicator.style.transform = "translate(0px, 0px)";
|
|
73775
|
+
return;
|
|
73776
|
+
}
|
|
73777
|
+
const headerRect = header.getBoundingClientRect();
|
|
73778
|
+
const triggerRect = activeTrigger.getBoundingClientRect();
|
|
73779
|
+
indicator.style.opacity = "1";
|
|
73780
|
+
indicator.style.width = `${triggerRect.width}px`;
|
|
73781
|
+
indicator.style.height = `${triggerRect.height}px`;
|
|
73782
|
+
indicator.style.transform = `translate(${triggerRect.left - headerRect.left}px, ${triggerRect.top - headerRect.top}px)`;
|
|
73783
|
+
}, [activeTab, variant]);
|
|
73784
|
+
(0, import_react.useLayoutEffect)(() => {
|
|
73785
|
+
syncSelectionIndicator();
|
|
73786
|
+
}, [syncSelectionIndicator, tabLayoutSignature]);
|
|
73787
|
+
(0, import_react.useLayoutEffect)(() => {
|
|
73788
|
+
if (variant !== "default") return;
|
|
73789
|
+
const tabsButton = tabsButtonRef.current;
|
|
73790
|
+
if (!tabsButton) return;
|
|
73791
|
+
const handleScroll = () => {
|
|
73792
|
+
syncSelectionIndicator();
|
|
73793
|
+
};
|
|
73794
|
+
tabsButton.addEventListener("scroll", handleScroll, { passive: true });
|
|
73795
|
+
if (typeof ResizeObserver === "undefined") return () => {
|
|
73796
|
+
tabsButton.removeEventListener("scroll", handleScroll);
|
|
73797
|
+
};
|
|
73798
|
+
const observer = new ResizeObserver(() => {
|
|
73799
|
+
syncSelectionIndicator();
|
|
73800
|
+
});
|
|
73801
|
+
observer.observe(tabsButton);
|
|
73802
|
+
if (headerRef.current) observer.observe(headerRef.current);
|
|
73803
|
+
const activeTrigger = activeTab ? triggerRefs.current.get(activeTab) : null;
|
|
73804
|
+
if (activeTrigger) observer.observe(activeTrigger);
|
|
73805
|
+
return () => {
|
|
73806
|
+
tabsButton.removeEventListener("scroll", handleScroll);
|
|
73807
|
+
observer.disconnect();
|
|
73808
|
+
};
|
|
73809
|
+
}, [
|
|
73810
|
+
activeTab,
|
|
73811
|
+
syncSelectionIndicator,
|
|
73812
|
+
tabLayoutSignature,
|
|
73813
|
+
variant
|
|
73814
|
+
]);
|
|
73759
73815
|
const handleChange = (id) => {
|
|
73760
73816
|
if (!controlled) setUncontrolled(id);
|
|
73761
73817
|
onTabChange?.(id);
|
|
@@ -73835,77 +73891,115 @@ function TabsImpl({ tabs, selectedTab: controlled, onTabChange, onTabClose, onTa
|
|
|
73835
73891
|
event.dataTransfer.dropEffect = "move";
|
|
73836
73892
|
}, [reorderable]);
|
|
73837
73893
|
if (tabs.length === 0) return null;
|
|
73838
|
-
const headerClassName = variant === "terminal" ? "tabs-header bg-terminal text-terminal-foreground sticky top-0 z-20 flex min-w-0 items-stretch" : "tabs-header
|
|
73839
|
-
const stripClassName = variant === "terminal" ? "tabs-strip min-w-0 flex-1 bg-terminal px-4" : "tabs-strip
|
|
73894
|
+
const headerClassName = variant === "terminal" ? "tabs-header bg-terminal text-terminal-foreground sticky top-0 z-20 flex min-w-0 items-stretch" : "tabs-header relative sticky top-0 z-20 min-w-0";
|
|
73895
|
+
const stripClassName = variant === "terminal" ? "tabs-strip min-w-0 flex-1 bg-terminal px-4" : "tabs-strip min-w-0 flex-1 rounded-l-md px-4";
|
|
73840
73896
|
const listClassName = variant === "terminal" ? "tabs-button scrollbar-none flex min-w-0 gap-1 overflow-x-auto pt-2" : "tabs-button scrollbar-none flex min-w-0 gap-1 overflow-x-auto";
|
|
73841
|
-
const buttonBaseClassName = `group relative m-0 flex h-full shrink-0 items-center gap-2 px-2 text-sm font-medium transition-colors ${variant === "terminal" ? "rounded-t-[8px] py-1" : "py-2"}`;
|
|
73842
|
-
const activeButtonClassName = variant === "terminal" ? "tab-selected bg-background text-foreground" : "tab-selected
|
|
73897
|
+
const buttonBaseClassName = `group relative z-10 m-0 flex h-full shrink-0 items-center gap-2 px-2 text-sm font-medium transition-colors ${variant === "terminal" ? "rounded-t-[8px] py-1" : "py-2"}`;
|
|
73898
|
+
const activeButtonClassName = variant === "terminal" ? "tab-selected bg-background text-foreground" : "tab-selected text-foreground";
|
|
73843
73899
|
const inactiveButtonClassName = variant === "terminal" ? "bg-terminal text-terminal-foreground/80 hover:bg-terminal hover:text-terminal-foreground" : "text-muted-foreground hover:bg-background/35 hover:text-foreground";
|
|
73844
|
-
const actionsClassName = variant === "terminal" ? "tabs-actions border-border bg-terminal text-terminal-foreground flex shrink-0 items-center border-b px-1" : "tabs-actions
|
|
73900
|
+
const actionsClassName = variant === "terminal" ? "tabs-actions border-border bg-terminal text-terminal-foreground flex shrink-0 items-center border-b px-1" : "tabs-actions border-zinc-500/15 flex shrink-0 items-center rounded-r-md border-l px-1";
|
|
73845
73901
|
const handleTabBarDoubleClick = (event) => {
|
|
73846
73902
|
if (!onTabBarDoubleClick) return;
|
|
73847
73903
|
if (event.target.closest("[data-tab-item=\"true\"]")) return;
|
|
73848
73904
|
onTabBarDoubleClick();
|
|
73849
73905
|
};
|
|
73906
|
+
const tabButtons = tabs.map((tab) => {
|
|
73907
|
+
const dragIndicatorStyle = dropIndicator?.tabId === tab.id ? { boxShadow: dropIndicator.position === "before" ? "inset 2px 0 0 var(--border)" : "inset -2px 0 0 var(--border)" } : void 0;
|
|
73908
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
|
|
73909
|
+
ref: (element) => {
|
|
73910
|
+
triggerRefs.current.set(tab.id, element);
|
|
73911
|
+
},
|
|
73912
|
+
"data-tab-item": "true",
|
|
73913
|
+
"data-tab-id": tab.id,
|
|
73914
|
+
draggable: reorderable,
|
|
73915
|
+
onClick: () => handleChange(tab.id),
|
|
73916
|
+
onDragStart: (event) => handleDragStart(event, tab.id),
|
|
73917
|
+
onDragEnd: handleDragEnd,
|
|
73918
|
+
onDragOver: (event) => handleItemDragOver(event, tab.id),
|
|
73919
|
+
onDrop: (event) => handleItemDrop(event, tab.id),
|
|
73920
|
+
className: `${buttonBaseClassName} ${activeTab === tab.id ? activeButtonClassName : inactiveButtonClassName} ${reorderable ? "cursor-grab active:cursor-grabbing" : ""}`,
|
|
73921
|
+
style: dragIndicatorStyle,
|
|
73922
|
+
children: [
|
|
73923
|
+
tab.icon,
|
|
73924
|
+
tab.label,
|
|
73925
|
+
tab.closable && onTabClose && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
73926
|
+
role: "button",
|
|
73927
|
+
tabIndex: 0,
|
|
73928
|
+
onClick: (event) => {
|
|
73929
|
+
event.stopPropagation();
|
|
73930
|
+
onTabClose(tab.id);
|
|
73931
|
+
},
|
|
73932
|
+
onKeyDown: (event) => {
|
|
73933
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
73934
|
+
event.stopPropagation();
|
|
73935
|
+
onTabClose(tab.id);
|
|
73936
|
+
}
|
|
73937
|
+
},
|
|
73938
|
+
draggable: false,
|
|
73939
|
+
className: `hover:text-foreground -mr-1 rounded p-0.5 transition ${tab.closeButtonVisibility === "always" ? "opacity-100" : "opacity-0 group-hover:opacity-100 [button:hover>&]:opacity-100"} ${activeTab === tab.id ? "text-current/80" : "text-muted-foreground"}`,
|
|
73940
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(X$2, { className: "h-3 w-3" })
|
|
73941
|
+
})
|
|
73942
|
+
]
|
|
73943
|
+
}, tab.id);
|
|
73944
|
+
});
|
|
73850
73945
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
73851
73946
|
id,
|
|
73852
73947
|
ref: rootRef,
|
|
73853
73948
|
"data-tabs-variant": variant,
|
|
73854
73949
|
className: `relative isolate flex min-h-0 min-w-0 flex-1 flex-col ${className}`,
|
|
73855
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.
|
|
73950
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
73951
|
+
ref: headerRef,
|
|
73856
73952
|
className: headerClassName,
|
|
73857
|
-
children:
|
|
73953
|
+
children: variant === "default" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
73954
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
73955
|
+
ref: headerShellRef,
|
|
73956
|
+
"data-tabs-header-shell": "true",
|
|
73957
|
+
className: "tabs-header-shell bg-card/95 pointer-events-none absolute inset-0 z-0 rounded-md border border-zinc-500/15 shadow-[inset_0_-1px_0_color-mix(in_srgb,var(--border)_85%,transparent)] backdrop-blur-sm"
|
|
73958
|
+
}),
|
|
73959
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
73960
|
+
className: "pointer-events-none absolute inset-0 z-10",
|
|
73961
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
73962
|
+
ref: selectionIndicatorRef,
|
|
73963
|
+
"data-tabs-selection-indicator": "true",
|
|
73964
|
+
"aria-hidden": "true",
|
|
73965
|
+
className: "tabs-selection-indicator border-primary bg-background/70 duration-280 absolute left-0 top-0 rounded-md border-b-2 opacity-0 shadow-[inset_0_-1px_0_color-mix(in_srgb,var(--border)_85%,transparent)] transition-[transform,width,height,opacity] ease-[cubic-bezier(0.22,1,0.36,1)]"
|
|
73966
|
+
})
|
|
73967
|
+
}),
|
|
73968
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
73969
|
+
ref: headerForegroundRef,
|
|
73970
|
+
"data-tabs-header-foreground": "true",
|
|
73971
|
+
className: "tabs-header-foreground relative z-20 flex min-w-0 items-stretch",
|
|
73972
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
73973
|
+
className: stripClassName,
|
|
73974
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
73975
|
+
ref: tabsButtonRef,
|
|
73976
|
+
className: listClassName,
|
|
73977
|
+
onDoubleClick: handleTabBarDoubleClick,
|
|
73978
|
+
onDragOver: handleListDragOver,
|
|
73979
|
+
onDrop: handleListDrop,
|
|
73980
|
+
children: tabButtons
|
|
73981
|
+
})
|
|
73982
|
+
}), actions && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
73983
|
+
"data-tabs-actions": "true",
|
|
73984
|
+
className: actionsClassName,
|
|
73985
|
+
children: actions
|
|
73986
|
+
})]
|
|
73987
|
+
})
|
|
73988
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
73858
73989
|
className: stripClassName,
|
|
73859
73990
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
73991
|
+
ref: tabsButtonRef,
|
|
73860
73992
|
className: listClassName,
|
|
73861
73993
|
onDoubleClick: handleTabBarDoubleClick,
|
|
73862
73994
|
onDragOver: handleListDragOver,
|
|
73863
73995
|
onDrop: handleListDrop,
|
|
73864
|
-
children:
|
|
73865
|
-
const dragIndicatorStyle = dropIndicator?.tabId === tab.id ? { boxShadow: dropIndicator.position === "before" ? "inset 2px 0 0 var(--border)" : "inset -2px 0 0 var(--border)" } : void 0;
|
|
73866
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
|
|
73867
|
-
ref: (element) => {
|
|
73868
|
-
triggerRefs.current.set(tab.id, element);
|
|
73869
|
-
},
|
|
73870
|
-
"data-tab-item": "true",
|
|
73871
|
-
"data-tab-id": tab.id,
|
|
73872
|
-
draggable: reorderable,
|
|
73873
|
-
onClick: () => handleChange(tab.id),
|
|
73874
|
-
onDragStart: (event) => handleDragStart(event, tab.id),
|
|
73875
|
-
onDragEnd: handleDragEnd,
|
|
73876
|
-
onDragOver: (event) => handleItemDragOver(event, tab.id),
|
|
73877
|
-
onDrop: (event) => handleItemDrop(event, tab.id),
|
|
73878
|
-
className: `${buttonBaseClassName} ${activeTab === tab.id ? activeButtonClassName : inactiveButtonClassName} ${reorderable ? "cursor-grab active:cursor-grabbing" : ""}`,
|
|
73879
|
-
style: dragIndicatorStyle,
|
|
73880
|
-
children: [
|
|
73881
|
-
tab.icon,
|
|
73882
|
-
tab.label,
|
|
73883
|
-
tab.closable && onTabClose && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
73884
|
-
role: "button",
|
|
73885
|
-
tabIndex: 0,
|
|
73886
|
-
onClick: (event) => {
|
|
73887
|
-
event.stopPropagation();
|
|
73888
|
-
onTabClose(tab.id);
|
|
73889
|
-
},
|
|
73890
|
-
onKeyDown: (event) => {
|
|
73891
|
-
if (event.key === "Enter" || event.key === " ") {
|
|
73892
|
-
event.stopPropagation();
|
|
73893
|
-
onTabClose(tab.id);
|
|
73894
|
-
}
|
|
73895
|
-
},
|
|
73896
|
-
draggable: false,
|
|
73897
|
-
className: `hover:text-foreground -mr-1 rounded p-0.5 transition ${tab.closeButtonVisibility === "always" ? "opacity-100" : "opacity-0 group-hover:opacity-100 [button:hover>&]:opacity-100"} ${activeTab === tab.id ? "text-current/80" : "text-muted-foreground"}`,
|
|
73898
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(X$2, { className: "h-3 w-3" })
|
|
73899
|
-
})
|
|
73900
|
-
]
|
|
73901
|
-
}, tab.id);
|
|
73902
|
-
})
|
|
73996
|
+
children: tabButtons
|
|
73903
73997
|
})
|
|
73904
73998
|
}), actions && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
73905
73999
|
"data-tabs-actions": "true",
|
|
73906
74000
|
className: actionsClassName,
|
|
73907
74001
|
children: actions
|
|
73908
|
-
})]
|
|
74002
|
+
})] })
|
|
73909
74003
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
73910
74004
|
className: "relative flex min-h-0 flex-1 overflow-hidden",
|
|
73911
74005
|
children: contentTabs.map((tab) => tab.unmountOnHide ? activeTab === tab.id && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
@@ -73931,6 +74025,249 @@ function TabsImpl({ tabs, selectedTab: controlled, onTabChange, onTabClose, onTa
|
|
|
73931
74025
|
}
|
|
73932
74026
|
var Tabs = (0, import_react.forwardRef)(TabsImpl);
|
|
73933
74027
|
//#endregion
|
|
74028
|
+
//#region src/lib/view-transitions/tab-scroll-freeze.ts
|
|
74029
|
+
var DATA_VISIBLE_HEIGHT = "tabVisibleHeight";
|
|
74030
|
+
var DATA_TOP_INSET = "tabTopInset";
|
|
74031
|
+
var DATA_SCROLL_OFFSET = "tabScrollOffset";
|
|
74032
|
+
var DATA_LAYOUT_BRIDGE = "tabLayoutBridge";
|
|
74033
|
+
var DATA_LAYOUT_BRIDGE_BASE_PADDING = "tabLayoutBridgeBasePadding";
|
|
74034
|
+
var DATA_LAYOUT_BRIDGE_INLINE_PADDING = "tabLayoutBridgeInlinePadding";
|
|
74035
|
+
var TAB_SCROLL_ROOT_SELECTOR = "[data-tab-scroll-root=\"true\"]";
|
|
74036
|
+
function clamp$2(value, min, max) {
|
|
74037
|
+
return Math.min(Math.max(value, min), max);
|
|
74038
|
+
}
|
|
74039
|
+
function maxViewportScroll(viewport) {
|
|
74040
|
+
return Math.max(viewport.scrollHeight - viewport.clientHeight, 0);
|
|
74041
|
+
}
|
|
74042
|
+
function maxPanelScroll(panel, visibleHeight) {
|
|
74043
|
+
return Math.max(panel.scrollHeight - visibleHeight, 0);
|
|
74044
|
+
}
|
|
74045
|
+
function readPanelLayoutBridge(panel) {
|
|
74046
|
+
return Number(panel.dataset[DATA_LAYOUT_BRIDGE] ?? "0") || 0;
|
|
74047
|
+
}
|
|
74048
|
+
function ensurePanelLayoutBridgeState(panel) {
|
|
74049
|
+
panel.dataset[DATA_LAYOUT_BRIDGE_BASE_PADDING] ||= window.getComputedStyle(panel).paddingBottom;
|
|
74050
|
+
panel.dataset[DATA_LAYOUT_BRIDGE_INLINE_PADDING] ||= panel.style.paddingBottom;
|
|
74051
|
+
}
|
|
74052
|
+
function setPanelLayoutBridge(panel, extraHeight) {
|
|
74053
|
+
ensurePanelLayoutBridgeState(panel);
|
|
74054
|
+
const normalizedHeight = Math.max(Math.ceil(extraHeight), 0);
|
|
74055
|
+
panel.dataset[DATA_LAYOUT_BRIDGE] = String(normalizedHeight);
|
|
74056
|
+
if (normalizedHeight <= 0) {
|
|
74057
|
+
panel.style.paddingBottom = panel.dataset[DATA_LAYOUT_BRIDGE_INLINE_PADDING] ?? "";
|
|
74058
|
+
return;
|
|
74059
|
+
}
|
|
74060
|
+
const basePadding = panel.dataset[DATA_LAYOUT_BRIDGE_BASE_PADDING] ?? "0px";
|
|
74061
|
+
panel.style.paddingBottom = `calc(${basePadding} + ${normalizedHeight}px)`;
|
|
74062
|
+
}
|
|
74063
|
+
function restoreViewportScroll(viewport, panel, targetScrollTop) {
|
|
74064
|
+
const applyScrollTop = () => {
|
|
74065
|
+
if (!viewport.isConnected || !panel.isConnected) return true;
|
|
74066
|
+
const existingBridge = readPanelLayoutBridge(panel);
|
|
74067
|
+
const baseMaxViewportScroll = Math.max(maxViewportScroll(viewport) - existingBridge, 0);
|
|
74068
|
+
setPanelLayoutBridge(panel, Math.max(targetScrollTop - baseMaxViewportScroll, 0));
|
|
74069
|
+
const nextScrollTop = clamp$2(targetScrollTop, 0, maxViewportScroll(viewport));
|
|
74070
|
+
viewport.scrollTop = nextScrollTop;
|
|
74071
|
+
return viewport.scrollTop === nextScrollTop;
|
|
74072
|
+
};
|
|
74073
|
+
if (applyScrollTop() || typeof requestAnimationFrame !== "function") return;
|
|
74074
|
+
let retriesRemaining = 10;
|
|
74075
|
+
const retry = () => {
|
|
74076
|
+
if (applyScrollTop() || retriesRemaining <= 0) return;
|
|
74077
|
+
retriesRemaining -= 1;
|
|
74078
|
+
requestAnimationFrame(retry);
|
|
74079
|
+
};
|
|
74080
|
+
requestAnimationFrame(retry);
|
|
74081
|
+
}
|
|
74082
|
+
function hasVerticalScrollBehavior(overflowY) {
|
|
74083
|
+
return overflowY === "auto" || overflowY === "scroll" || overflowY === "overlay";
|
|
74084
|
+
}
|
|
74085
|
+
function findScrollableDescendant(panel) {
|
|
74086
|
+
const walker = document.createTreeWalker(panel, NodeFilter.SHOW_ELEMENT);
|
|
74087
|
+
let candidate = null;
|
|
74088
|
+
while (walker.nextNode()) {
|
|
74089
|
+
const node = walker.currentNode;
|
|
74090
|
+
if (!(node instanceof HTMLElement)) continue;
|
|
74091
|
+
if (!hasVerticalScrollBehavior(window.getComputedStyle(node).overflowY) || node.scrollHeight <= node.clientHeight) continue;
|
|
74092
|
+
if (node.scrollTop > 0) return node;
|
|
74093
|
+
candidate ??= node;
|
|
74094
|
+
}
|
|
74095
|
+
return candidate;
|
|
74096
|
+
}
|
|
74097
|
+
function resolveContentScrollRoot(panel) {
|
|
74098
|
+
const markedRoot = panel.matches(TAB_SCROLL_ROOT_SELECTOR) ? panel : panel.querySelector(TAB_SCROLL_ROOT_SELECTOR);
|
|
74099
|
+
if (markedRoot) return markedRoot;
|
|
74100
|
+
return findScrollableDescendant(panel);
|
|
74101
|
+
}
|
|
74102
|
+
function panelDocumentTop(panel, viewport) {
|
|
74103
|
+
const panelRect = panel.getBoundingClientRect();
|
|
74104
|
+
const viewportRect = viewport.getBoundingClientRect();
|
|
74105
|
+
return viewport.scrollTop + panelRect.top - viewportRect.top;
|
|
74106
|
+
}
|
|
74107
|
+
function setFrozenMetrics(panel, snapshot) {
|
|
74108
|
+
panel.dataset[DATA_VISIBLE_HEIGHT] = String(snapshot.visibleHeight);
|
|
74109
|
+
panel.dataset[DATA_TOP_INSET] = String(snapshot.topInset);
|
|
74110
|
+
panel.dataset[DATA_SCROLL_OFFSET] = String(snapshot.innerScrollTop);
|
|
74111
|
+
}
|
|
74112
|
+
function clearFrozenMetrics(panel) {
|
|
74113
|
+
delete panel.dataset[DATA_VISIBLE_HEIGHT];
|
|
74114
|
+
delete panel.dataset[DATA_TOP_INSET];
|
|
74115
|
+
delete panel.dataset[DATA_SCROLL_OFFSET];
|
|
74116
|
+
}
|
|
74117
|
+
function applyFrozenStyles(panel, snapshot) {
|
|
74118
|
+
const previousStyles = {
|
|
74119
|
+
height: panel.style.height,
|
|
74120
|
+
maxHeight: panel.style.maxHeight,
|
|
74121
|
+
minHeight: panel.style.minHeight,
|
|
74122
|
+
overflowY: panel.style.overflowY
|
|
74123
|
+
};
|
|
74124
|
+
const height = `${snapshot.visibleHeight}px`;
|
|
74125
|
+
panel.style.height = height;
|
|
74126
|
+
panel.style.minHeight = height;
|
|
74127
|
+
panel.style.maxHeight = height;
|
|
74128
|
+
panel.style.overflowY = "hidden";
|
|
74129
|
+
setFrozenMetrics(panel, snapshot);
|
|
74130
|
+
return previousStyles;
|
|
74131
|
+
}
|
|
74132
|
+
function restorePanel(panel, previousStyles) {
|
|
74133
|
+
panel.style.height = previousStyles.height;
|
|
74134
|
+
panel.style.maxHeight = previousStyles.maxHeight;
|
|
74135
|
+
panel.style.minHeight = previousStyles.minHeight;
|
|
74136
|
+
panel.style.overflowY = previousStyles.overflowY;
|
|
74137
|
+
clearFrozenMetrics(panel);
|
|
74138
|
+
}
|
|
74139
|
+
function restoreContentScrollRoot(element, targetScrollTop) {
|
|
74140
|
+
if (!element) return;
|
|
74141
|
+
const applyScrollTop = () => {
|
|
74142
|
+
if (!element.isConnected) return true;
|
|
74143
|
+
element.scrollTop = targetScrollTop;
|
|
74144
|
+
return element.scrollTop === targetScrollTop;
|
|
74145
|
+
};
|
|
74146
|
+
if (applyScrollTop() || typeof requestAnimationFrame !== "function") return;
|
|
74147
|
+
let retriesRemaining = 10;
|
|
74148
|
+
const retry = () => {
|
|
74149
|
+
if (applyScrollTop() || retriesRemaining <= 0) return;
|
|
74150
|
+
retriesRemaining -= 1;
|
|
74151
|
+
requestAnimationFrame(retry);
|
|
74152
|
+
};
|
|
74153
|
+
requestAnimationFrame(retry);
|
|
74154
|
+
}
|
|
74155
|
+
function normalizeViewportSelectors(viewportSelector) {
|
|
74156
|
+
return typeof viewportSelector === "string" ? viewportSelector.split(",").map((selector) => selector.trim()) : [...viewportSelector];
|
|
74157
|
+
}
|
|
74158
|
+
function resolveViewportBoundary(panel, viewportSelector) {
|
|
74159
|
+
const selectors = normalizeViewportSelectors(viewportSelector);
|
|
74160
|
+
for (const selector of selectors) {
|
|
74161
|
+
if (!selector) continue;
|
|
74162
|
+
try {
|
|
74163
|
+
const match = panel.closest(selector);
|
|
74164
|
+
if (match instanceof HTMLElement) return match;
|
|
74165
|
+
} catch {
|
|
74166
|
+
return null;
|
|
74167
|
+
}
|
|
74168
|
+
}
|
|
74169
|
+
return null;
|
|
74170
|
+
}
|
|
74171
|
+
function resolveScrollViewport(panel, boundary) {
|
|
74172
|
+
let current = panel.parentElement;
|
|
74173
|
+
while (current) {
|
|
74174
|
+
if (hasVerticalScrollBehavior(window.getComputedStyle(current).overflowY) && current.scrollHeight > current.clientHeight) return current;
|
|
74175
|
+
if (boundary && current === boundary) break;
|
|
74176
|
+
current = current.parentElement;
|
|
74177
|
+
}
|
|
74178
|
+
if (!boundary) return null;
|
|
74179
|
+
if (hasVerticalScrollBehavior(window.getComputedStyle(boundary).overflowY)) return boundary;
|
|
74180
|
+
return null;
|
|
74181
|
+
}
|
|
74182
|
+
function resolveTabScrollElements(handle, tabId, viewportSelector) {
|
|
74183
|
+
if (!viewportSelector) return null;
|
|
74184
|
+
const panel = handle?.getPanel(tabId);
|
|
74185
|
+
if (!(panel instanceof HTMLElement)) return null;
|
|
74186
|
+
const viewport = resolveScrollViewport(panel, resolveViewportBoundary(panel, viewportSelector));
|
|
74187
|
+
if (!(viewport instanceof HTMLElement)) return null;
|
|
74188
|
+
return {
|
|
74189
|
+
panel,
|
|
74190
|
+
contentScrollRoot: resolveContentScrollRoot(panel),
|
|
74191
|
+
viewport
|
|
74192
|
+
};
|
|
74193
|
+
}
|
|
74194
|
+
function restorePanelContentScroll(panel, snapshot) {
|
|
74195
|
+
if (!(panel instanceof HTMLElement) || !snapshot) return;
|
|
74196
|
+
const contentScrollRoot = resolveContentScrollRoot(panel);
|
|
74197
|
+
if (contentScrollRoot && contentScrollRoot !== panel) restoreContentScrollRoot(contentScrollRoot, snapshot.contentScrollTop);
|
|
74198
|
+
}
|
|
74199
|
+
function restorePanelViewportScroll(panel, viewport, snapshot) {
|
|
74200
|
+
if (!(panel instanceof HTMLElement) || !(viewport instanceof HTMLElement)) return;
|
|
74201
|
+
if (!snapshot) {
|
|
74202
|
+
setPanelLayoutBridge(panel, 0);
|
|
74203
|
+
return;
|
|
74204
|
+
}
|
|
74205
|
+
restoreViewportScroll(viewport, panel, snapshot.viewportScrollTop);
|
|
74206
|
+
}
|
|
74207
|
+
function captureTabScrollMemory(elements) {
|
|
74208
|
+
const { panel, contentScrollRoot, viewport } = elements;
|
|
74209
|
+
const panelRect = panel.getBoundingClientRect();
|
|
74210
|
+
const viewportRect = viewport.getBoundingClientRect();
|
|
74211
|
+
const visibleHeight = clamp$2(Math.min(panelRect.bottom, viewportRect.bottom) - Math.max(panelRect.top, viewportRect.top), 0, viewport.clientHeight);
|
|
74212
|
+
if (visibleHeight <= 0) return null;
|
|
74213
|
+
const topInset = Math.max(panelRect.top - viewportRect.top, 0);
|
|
74214
|
+
const innerScrollTop = clamp$2(Math.max(viewportRect.top - panelRect.top, 0), 0, maxPanelScroll(panel, visibleHeight));
|
|
74215
|
+
return {
|
|
74216
|
+
contentScrollTop: contentScrollRoot && contentScrollRoot !== panel ? contentScrollRoot.scrollTop : 0,
|
|
74217
|
+
innerScrollTop,
|
|
74218
|
+
topInset,
|
|
74219
|
+
visibleHeight,
|
|
74220
|
+
viewportScrollTop: viewport.scrollTop
|
|
74221
|
+
};
|
|
74222
|
+
}
|
|
74223
|
+
function freezeOutgoingTab(elements, snapshot) {
|
|
74224
|
+
const previousStyles = applyFrozenStyles(elements.panel, snapshot);
|
|
74225
|
+
if (elements.contentScrollRoot && elements.contentScrollRoot !== elements.panel) restoreContentScrollRoot(elements.contentScrollRoot, snapshot.contentScrollTop);
|
|
74226
|
+
elements.panel.scrollTop = snapshot.innerScrollTop;
|
|
74227
|
+
if (snapshot.innerScrollTop > 0) elements.viewport.scrollTop = clamp$2(elements.viewport.scrollTop - snapshot.innerScrollTop, 0, maxViewportScroll(elements.viewport));
|
|
74228
|
+
return {
|
|
74229
|
+
contentScrollRoot: elements.contentScrollRoot && elements.contentScrollRoot !== elements.panel ? elements.contentScrollRoot : null,
|
|
74230
|
+
contentScrollTop: snapshot.contentScrollTop,
|
|
74231
|
+
finalViewportScrollTop: snapshot.viewportScrollTop,
|
|
74232
|
+
panel: elements.panel,
|
|
74233
|
+
previousStyles,
|
|
74234
|
+
viewport: elements.viewport
|
|
74235
|
+
};
|
|
74236
|
+
}
|
|
74237
|
+
function freezeIncomingTab(elements, snapshot) {
|
|
74238
|
+
const normalizedSnapshot = {
|
|
74239
|
+
contentScrollTop: elements.contentScrollRoot && elements.contentScrollRoot !== elements.panel ? snapshot.contentScrollTop : 0,
|
|
74240
|
+
topInset: clamp$2(snapshot.topInset, 0, elements.viewport.clientHeight),
|
|
74241
|
+
visibleHeight: clamp$2(snapshot.visibleHeight, 1, elements.viewport.clientHeight),
|
|
74242
|
+
innerScrollTop: 0,
|
|
74243
|
+
viewportScrollTop: snapshot.viewportScrollTop
|
|
74244
|
+
};
|
|
74245
|
+
normalizedSnapshot.innerScrollTop = clamp$2(snapshot.innerScrollTop, 0, maxPanelScroll(elements.panel, normalizedSnapshot.visibleHeight));
|
|
74246
|
+
const nextViewportScrollTop = clamp$2(panelDocumentTop(elements.panel, elements.viewport) - normalizedSnapshot.topInset, 0, maxViewportScroll(elements.viewport));
|
|
74247
|
+
const previousStyles = applyFrozenStyles(elements.panel, normalizedSnapshot);
|
|
74248
|
+
elements.viewport.scrollTop = nextViewportScrollTop;
|
|
74249
|
+
if (elements.contentScrollRoot && elements.contentScrollRoot !== elements.panel) restoreContentScrollRoot(elements.contentScrollRoot, normalizedSnapshot.contentScrollTop);
|
|
74250
|
+
elements.panel.scrollTop = normalizedSnapshot.innerScrollTop;
|
|
74251
|
+
return {
|
|
74252
|
+
contentScrollRoot: elements.contentScrollRoot && elements.contentScrollRoot !== elements.panel ? elements.contentScrollRoot : null,
|
|
74253
|
+
contentScrollTop: normalizedSnapshot.contentScrollTop,
|
|
74254
|
+
finalViewportScrollTop: snapshot.viewportScrollTop,
|
|
74255
|
+
panel: elements.panel,
|
|
74256
|
+
previousStyles,
|
|
74257
|
+
viewport: elements.viewport
|
|
74258
|
+
};
|
|
74259
|
+
}
|
|
74260
|
+
function finalizeFrozenIncomingTab(state) {
|
|
74261
|
+
restorePanel(state.panel, state.previousStyles);
|
|
74262
|
+
restoreViewportScroll(state.viewport, state.panel, state.finalViewportScrollTop);
|
|
74263
|
+
state.panel.scrollTop = 0;
|
|
74264
|
+
if (state.contentScrollRoot) restoreContentScrollRoot(state.contentScrollRoot, state.contentScrollTop);
|
|
74265
|
+
}
|
|
74266
|
+
function cleanupFrozenTab(state) {
|
|
74267
|
+
restorePanel(state.panel, state.previousStyles);
|
|
74268
|
+
state.panel.scrollTop = 0;
|
|
74269
|
+
}
|
|
74270
|
+
//#endregion
|
|
73934
74271
|
//#region src/lib/view-transitions/tabs.ts
|
|
73935
74272
|
var SERVER_LOCATION = {
|
|
73936
74273
|
pathname: "/",
|
|
@@ -73955,6 +74292,11 @@ function resolveTabArea(pathname, area) {
|
|
|
73955
74292
|
if (area) return area;
|
|
73956
74293
|
return isStaticMode() ? "main" : navController.getAreaForPath(pathname);
|
|
73957
74294
|
}
|
|
74295
|
+
function normalizeViewportSelectorOption(viewportSelector) {
|
|
74296
|
+
if (!viewportSelector) return;
|
|
74297
|
+
const normalized = (typeof viewportSelector === "string" ? viewportSelector.split(",") : [...viewportSelector]).map((selector) => selector.trim()).filter((selector) => selector.length > 0);
|
|
74298
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
74299
|
+
}
|
|
73958
74300
|
function readWindowLocation() {
|
|
73959
74301
|
if (typeof window === "undefined") return SERVER_LOCATION;
|
|
73960
74302
|
return {
|
|
@@ -74009,13 +74351,24 @@ function useRoutedTabsLocation() {
|
|
|
74009
74351
|
function collectTabEntries(handle, tabId) {
|
|
74010
74352
|
if (!handle) return [];
|
|
74011
74353
|
const entries = [];
|
|
74354
|
+
const headerShell = handle.getHeaderShell();
|
|
74355
|
+
if (headerShell) entries.push([headerShell, "vt-tab-header-shell"]);
|
|
74356
|
+
const selectionIndicator = handle.getSelectionIndicator();
|
|
74357
|
+
if (selectionIndicator) entries.push([selectionIndicator, "vt-tab-edge"]);
|
|
74358
|
+
const headerForeground = handle.getHeaderForeground();
|
|
74359
|
+
if (headerForeground) entries.push([headerForeground, "vt-tab-header-foreground"]);
|
|
74012
74360
|
const panel = handle.getPanel(tabId);
|
|
74013
74361
|
if (panel) entries.push([panel, "vt-tab-panel"]);
|
|
74014
74362
|
return entries;
|
|
74015
74363
|
}
|
|
74016
|
-
function useRoutedCarouselTabs({ queryKey, tabs, initialTab, area, history = "replace", allowUnknownSelection = false }) {
|
|
74364
|
+
function useRoutedCarouselTabs({ queryKey, tabs, initialTab, area, history = "replace", allowUnknownSelection = false, viewportSelector }) {
|
|
74017
74365
|
const { location, router } = useRoutedTabsLocation();
|
|
74018
74366
|
const tabsRef = (0, import_react.useRef)(null);
|
|
74367
|
+
const viewportSelectorValue = (0, import_react.useMemo)(() => normalizeViewportSelectorOption(viewportSelector), [typeof viewportSelector === "string" ? viewportSelector : (viewportSelector ?? []).join("\0")]);
|
|
74368
|
+
const scrollMemoryByTabRef = (0, import_react.useRef)(/* @__PURE__ */ new Map());
|
|
74369
|
+
const frozenTabsRef = (0, import_react.useRef)(/* @__PURE__ */ new Map());
|
|
74370
|
+
const frozenTabTokenRef = (0, import_react.useRef)(0);
|
|
74371
|
+
const skipNextRestoreTabRef = (0, import_react.useRef)(null);
|
|
74019
74372
|
const selectedFromLocation = (0, import_react.useMemo)(() => resolveSelectedTab({
|
|
74020
74373
|
tabs,
|
|
74021
74374
|
queryKey,
|
|
@@ -74039,7 +74392,8 @@ function useRoutedCarouselTabs({ queryKey, tabs, initialTab, area, history = "re
|
|
|
74039
74392
|
router,
|
|
74040
74393
|
selectedFromLocation,
|
|
74041
74394
|
selectedTab,
|
|
74042
|
-
tabs
|
|
74395
|
+
tabs,
|
|
74396
|
+
viewportSelector: viewportSelectorValue
|
|
74043
74397
|
});
|
|
74044
74398
|
latestRef.current = {
|
|
74045
74399
|
allowUnknownSelection,
|
|
@@ -74050,15 +74404,107 @@ function useRoutedCarouselTabs({ queryKey, tabs, initialTab, area, history = "re
|
|
|
74050
74404
|
router,
|
|
74051
74405
|
selectedFromLocation,
|
|
74052
74406
|
selectedTab,
|
|
74053
|
-
tabs
|
|
74407
|
+
tabs,
|
|
74408
|
+
viewportSelector: viewportSelectorValue
|
|
74054
74409
|
};
|
|
74410
|
+
const cleanupFrozenTabById = (0, import_react.useCallback)((tabId, token) => {
|
|
74411
|
+
const frozenEntry = frozenTabsRef.current.get(tabId);
|
|
74412
|
+
if (!frozenEntry || token != null && frozenEntry.token !== token) return;
|
|
74413
|
+
cleanupFrozenTab(frozenEntry.state);
|
|
74414
|
+
frozenTabsRef.current.delete(tabId);
|
|
74415
|
+
}, []);
|
|
74416
|
+
const cleanupAllFrozenTabs = (0, import_react.useCallback)(() => {
|
|
74417
|
+
for (const frozenEntry of frozenTabsRef.current.values()) cleanupFrozenTab(frozenEntry.state);
|
|
74418
|
+
frozenTabsRef.current.clear();
|
|
74419
|
+
}, []);
|
|
74420
|
+
const captureTabSnapshot = (0, import_react.useCallback)((tabId, nextViewportSelector) => {
|
|
74421
|
+
const elements = resolveTabScrollElements(tabsRef.current, tabId, nextViewportSelector);
|
|
74422
|
+
if (!elements) return null;
|
|
74423
|
+
return captureTabScrollMemory(elements);
|
|
74424
|
+
}, []);
|
|
74425
|
+
const captureOutgoingTab = (0, import_react.useCallback)((tabId, nextViewportSelector, snapshotOverride) => {
|
|
74426
|
+
const elements = resolveTabScrollElements(tabsRef.current, tabId, nextViewportSelector);
|
|
74427
|
+
if (!elements) return;
|
|
74428
|
+
const snapshot = snapshotOverride ?? captureTabScrollMemory(elements);
|
|
74429
|
+
if (!snapshot) return;
|
|
74430
|
+
scrollMemoryByTabRef.current.set(tabId, snapshot);
|
|
74431
|
+
cleanupFrozenTabById(tabId);
|
|
74432
|
+
const token = ++frozenTabTokenRef.current;
|
|
74433
|
+
frozenTabsRef.current.set(tabId, {
|
|
74434
|
+
token,
|
|
74435
|
+
state: freezeOutgoingTab(elements, snapshot)
|
|
74436
|
+
});
|
|
74437
|
+
return token;
|
|
74438
|
+
}, [cleanupFrozenTabById]);
|
|
74439
|
+
const prepareIncomingTab = (0, import_react.useCallback)((tabId, nextViewportSelector, fallbackSnapshot) => {
|
|
74440
|
+
const elements = resolveTabScrollElements(tabsRef.current, tabId, nextViewportSelector);
|
|
74441
|
+
if (!elements) return null;
|
|
74442
|
+
const snapshot = scrollMemoryByTabRef.current.get(tabId) ?? fallbackSnapshot ?? captureTabScrollMemory(elements);
|
|
74443
|
+
if (!snapshot) return null;
|
|
74444
|
+
if (!scrollMemoryByTabRef.current.has(tabId)) scrollMemoryByTabRef.current.set(tabId, snapshot);
|
|
74445
|
+
cleanupFrozenTabById(tabId);
|
|
74446
|
+
const token = ++frozenTabTokenRef.current;
|
|
74447
|
+
frozenTabsRef.current.set(tabId, {
|
|
74448
|
+
token,
|
|
74449
|
+
state: freezeIncomingTab(elements, snapshot)
|
|
74450
|
+
});
|
|
74451
|
+
return token;
|
|
74452
|
+
}, [cleanupFrozenTabById]);
|
|
74453
|
+
const finalizeIncomingTab = (0, import_react.useCallback)((tabId, token) => {
|
|
74454
|
+
const frozenEntry = frozenTabsRef.current.get(tabId);
|
|
74455
|
+
if (!frozenEntry || token != null && frozenEntry.token !== token) return;
|
|
74456
|
+
finalizeFrozenIncomingTab(frozenEntry.state);
|
|
74457
|
+
frozenTabsRef.current.delete(tabId);
|
|
74458
|
+
}, []);
|
|
74055
74459
|
(0, import_react.useEffect)(() => {
|
|
74056
74460
|
setSelectedTabState((current) => current === selectedFromLocation ? current : selectedFromLocation);
|
|
74057
74461
|
}, [selectedFromLocation]);
|
|
74462
|
+
(0, import_react.useLayoutEffect)(() => {
|
|
74463
|
+
if (skipNextRestoreTabRef.current === selectedTab) {
|
|
74464
|
+
skipNextRestoreTabRef.current = null;
|
|
74465
|
+
return;
|
|
74466
|
+
}
|
|
74467
|
+
const snapshot = scrollMemoryByTabRef.current.get(selectedTab);
|
|
74468
|
+
const elements = resolveTabScrollElements(tabsRef.current, selectedTab, viewportSelectorValue);
|
|
74469
|
+
const panel = elements?.panel ?? tabsRef.current?.getPanel(selectedTab) ?? null;
|
|
74470
|
+
restorePanelContentScroll(panel, snapshot);
|
|
74471
|
+
restorePanelViewportScroll(panel, elements?.viewport ?? null, snapshot);
|
|
74472
|
+
}, [selectedTab, viewportSelectorValue]);
|
|
74473
|
+
(0, import_react.useEffect)(() => {
|
|
74474
|
+
const elements = resolveTabScrollElements(tabsRef.current, selectedTab, viewportSelectorValue);
|
|
74475
|
+
const contentScrollRoot = elements?.contentScrollRoot;
|
|
74476
|
+
if (!elements || !contentScrollRoot || contentScrollRoot === elements.panel) return;
|
|
74477
|
+
const rememberContentScroll = () => {
|
|
74478
|
+
const existingSnapshot = scrollMemoryByTabRef.current.get(selectedTab);
|
|
74479
|
+
if (!existingSnapshot) return;
|
|
74480
|
+
scrollMemoryByTabRef.current.set(selectedTab, {
|
|
74481
|
+
...existingSnapshot,
|
|
74482
|
+
contentScrollTop: contentScrollRoot.scrollTop
|
|
74483
|
+
});
|
|
74484
|
+
};
|
|
74485
|
+
rememberContentScroll();
|
|
74486
|
+
contentScrollRoot.addEventListener("scroll", rememberContentScroll, { passive: true });
|
|
74487
|
+
return () => {
|
|
74488
|
+
contentScrollRoot.removeEventListener("scroll", rememberContentScroll);
|
|
74489
|
+
};
|
|
74490
|
+
}, [selectedTab, viewportSelectorValue]);
|
|
74491
|
+
(0, import_react.useEffect)(() => {
|
|
74492
|
+
const validIds = new Set(tabs.map((tab) => tab.id));
|
|
74493
|
+
for (const tabId of scrollMemoryByTabRef.current.keys()) if (!validIds.has(tabId)) scrollMemoryByTabRef.current.delete(tabId);
|
|
74494
|
+
for (const tabId of Array.from(frozenTabsRef.current.keys())) if (!validIds.has(tabId)) cleanupFrozenTabById(tabId);
|
|
74495
|
+
}, [cleanupFrozenTabById, tabs]);
|
|
74496
|
+
(0, import_react.useEffect)(() => {
|
|
74497
|
+
scrollMemoryByTabRef.current.clear();
|
|
74498
|
+
cleanupAllFrozenTabs();
|
|
74499
|
+
}, [cleanupAllFrozenTabs, location.pathname]);
|
|
74500
|
+
(0, import_react.useEffect)(() => () => {
|
|
74501
|
+
cleanupAllFrozenTabs();
|
|
74502
|
+
}, [cleanupAllFrozenTabs]);
|
|
74058
74503
|
const setSelectedTab = (0, import_react.useCallback)((nextTabId, options) => {
|
|
74059
|
-
const { allowUnknownSelection: allowUnknown, area: latestArea, history: defaultHistory, location: latestLocation, queryKey: latestQueryKey, router: latestRouter, selectedFromLocation: latestSelectedFromLocation, selectedTab: currentTab, tabs: latestTabs } = latestRef.current;
|
|
74504
|
+
const { allowUnknownSelection: allowUnknown, area: latestArea, history: defaultHistory, location: latestLocation, queryKey: latestQueryKey, router: latestRouter, selectedFromLocation: latestSelectedFromLocation, selectedTab: currentTab, tabs: latestTabs, viewportSelector: latestViewportSelector } = latestRef.current;
|
|
74060
74505
|
if (!new Set(latestTabs.map((tab) => tab.id)).has(nextTabId) && !allowUnknown) return;
|
|
74061
74506
|
const nextHistory = options?.history ?? defaultHistory;
|
|
74507
|
+
const transferScroll = options?.transferScroll ?? true;
|
|
74062
74508
|
if (currentTab === nextTabId && latestSelectedFromLocation === nextTabId) return;
|
|
74063
74509
|
const commitSelection = () => {
|
|
74064
74510
|
setSelectedTabState(nextTabId);
|
|
@@ -74082,28 +74528,77 @@ function useRoutedCarouselTabs({ queryKey, tabs, initialTab, area, history = "re
|
|
|
74082
74528
|
}
|
|
74083
74529
|
navController.push(nextArea, href, latestLocation.state);
|
|
74084
74530
|
};
|
|
74531
|
+
if (!transferScroll) {
|
|
74532
|
+
const outgoingSnapshot = captureTabSnapshot(currentTab, latestViewportSelector);
|
|
74533
|
+
if (outgoingSnapshot) scrollMemoryByTabRef.current.set(currentTab, outgoingSnapshot);
|
|
74534
|
+
skipNextRestoreTabRef.current = nextTabId;
|
|
74535
|
+
if (!options?.animate || currentTab === nextTabId) {
|
|
74536
|
+
commitSelection();
|
|
74537
|
+
return;
|
|
74538
|
+
}
|
|
74539
|
+
runViewTransition({
|
|
74540
|
+
intent: {
|
|
74541
|
+
area: resolveTabArea(latestLocation.pathname, latestArea),
|
|
74542
|
+
kind: "tab-carousel",
|
|
74543
|
+
direction: "forward"
|
|
74544
|
+
},
|
|
74545
|
+
collectBeforeEntries: () => collectTabEntries(tabsRef.current, currentTab),
|
|
74546
|
+
collectAfterEntries: () => collectTabEntries(tabsRef.current, nextTabId),
|
|
74547
|
+
update: commitSelection
|
|
74548
|
+
});
|
|
74549
|
+
return;
|
|
74550
|
+
}
|
|
74551
|
+
const runSelectionWithScrollTransfer = (animated) => {
|
|
74552
|
+
const outgoingSnapshot = captureTabSnapshot(currentTab, latestViewportSelector);
|
|
74553
|
+
const incomingSeedSnapshot = scrollMemoryByTabRef.current.get(nextTabId) ?? outgoingSnapshot ?? captureTabSnapshot(nextTabId, latestViewportSelector);
|
|
74554
|
+
const outgoingToken = captureOutgoingTab(currentTab, latestViewportSelector, outgoingSnapshot);
|
|
74555
|
+
if (!animated) {
|
|
74556
|
+
(0, import_react_dom.flushSync)(() => {
|
|
74557
|
+
commitSelection();
|
|
74558
|
+
});
|
|
74559
|
+
const incomingToken = prepareIncomingTab(nextTabId, latestViewportSelector, incomingSeedSnapshot);
|
|
74560
|
+
if (incomingToken != null) finalizeIncomingTab(nextTabId, incomingToken);
|
|
74561
|
+
if (outgoingToken != null) cleanupFrozenTabById(currentTab, outgoingToken);
|
|
74562
|
+
return;
|
|
74563
|
+
}
|
|
74564
|
+
let incomingToken = null;
|
|
74565
|
+
runViewTransition({
|
|
74566
|
+
intent: {
|
|
74567
|
+
area: resolveTabArea(latestLocation.pathname, latestArea),
|
|
74568
|
+
kind: "tab-carousel",
|
|
74569
|
+
direction
|
|
74570
|
+
},
|
|
74571
|
+
collectBeforeEntries: () => collectTabEntries(tabsRef.current, currentTab),
|
|
74572
|
+
collectAfterEntries: () => {
|
|
74573
|
+
if (incomingToken == null) incomingToken = prepareIncomingTab(nextTabId, latestViewportSelector, incomingSeedSnapshot);
|
|
74574
|
+
return collectTabEntries(tabsRef.current, nextTabId);
|
|
74575
|
+
},
|
|
74576
|
+
update: commitSelection
|
|
74577
|
+
}).finally(() => {
|
|
74578
|
+
if (incomingToken == null) incomingToken = prepareIncomingTab(nextTabId, latestViewportSelector, incomingSeedSnapshot);
|
|
74579
|
+
if (incomingToken != null) finalizeIncomingTab(nextTabId, incomingToken);
|
|
74580
|
+
if (outgoingToken != null) cleanupFrozenTabById(currentTab, outgoingToken);
|
|
74581
|
+
});
|
|
74582
|
+
};
|
|
74085
74583
|
if (!options?.animate || currentTab === nextTabId) {
|
|
74086
|
-
|
|
74584
|
+
runSelectionWithScrollTransfer(false);
|
|
74087
74585
|
return;
|
|
74088
74586
|
}
|
|
74089
74587
|
const currentIndex = latestTabs.findIndex((tab) => tab.id === currentTab);
|
|
74090
74588
|
const nextIndex = latestTabs.findIndex((tab) => tab.id === nextTabId);
|
|
74091
74589
|
if (currentIndex < 0 || nextIndex < 0) {
|
|
74092
|
-
|
|
74590
|
+
runSelectionWithScrollTransfer(false);
|
|
74093
74591
|
return;
|
|
74094
74592
|
}
|
|
74095
74593
|
const direction = nextIndex >= currentIndex ? "forward" : "backward";
|
|
74096
|
-
|
|
74097
|
-
|
|
74098
|
-
|
|
74099
|
-
|
|
74100
|
-
|
|
74101
|
-
|
|
74102
|
-
|
|
74103
|
-
|
|
74104
|
-
update: commitSelection
|
|
74105
|
-
});
|
|
74106
|
-
}, []);
|
|
74594
|
+
runSelectionWithScrollTransfer(true);
|
|
74595
|
+
}, [
|
|
74596
|
+
captureOutgoingTab,
|
|
74597
|
+
captureTabSnapshot,
|
|
74598
|
+
cleanupFrozenTabById,
|
|
74599
|
+
finalizeIncomingTab,
|
|
74600
|
+
prepareIncomingTab
|
|
74601
|
+
]);
|
|
74107
74602
|
return {
|
|
74108
74603
|
tabsRef,
|
|
74109
74604
|
selectedTab,
|