@openspecui/web 2.3.4 → 2.3.6
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-BxSz1S0N.js +1 -0
- package/dist/assets/WebGLRenderer-BHhaJ0WJ.js +1 -0
- package/dist/assets/WebGPURenderer-DRKX39eh.js +1 -0
- package/dist/assets/browserAll-D4RKeA6K.js +1 -0
- package/dist/assets/{dist-CyMw4R35.js → dist-7cHS5QWY.js} +1 -1
- package/dist/assets/dist-BDHG1KDB.js +1 -0
- package/dist/assets/{dist-C4qVWCwa.js → dist-Bmr28z9J.js} +1 -1
- package/dist/assets/{dist-Dw21sB44.js → dist-C9Q1D0iI.js} +1 -1
- package/dist/assets/{dist-BURffNKn.js → dist-CHCyBtgU.js} +1 -1
- package/dist/assets/{dist-BkfyzqOP.js → dist-CbImOnsL.js} +1 -1
- package/dist/assets/dist-CdimBSfI.js +1 -0
- package/dist/assets/{dist-0r-fEysT.js → dist-DmBfd3XF.js} +1 -1
- package/dist/assets/{dist-D5aqbpvI.js → dist-DoTjw0T7.js} +1 -1
- package/dist/assets/{dist-C_hvHrdB.js → dist-Pw11Vg0a.js} +1 -1
- package/dist/assets/dist-TbE9jx_5.js +1 -0
- package/dist/assets/{dist-EecJWaiB.js → dist-o5BKCN_5.js} +1 -1
- package/dist/assets/{ghostty-web-Dz4JIhSO.js → ghostty-web-BM-sB-n_.js} +1 -1
- package/dist/assets/index-Cf-Bih4u.css +1 -0
- package/dist/assets/{index-CEpXtWXm.js → index-DglxXq77.js} +92 -102
- package/dist/assets/{init-B8PdfdJA.js → init-CdYLlWcL.js} +1 -1
- package/dist/assets/trpc-Zloaz5j7.js +1 -0
- package/dist/assets/webworkerAll-B7pVi8gv.js +1 -0
- package/dist/index.html +2 -2
- package/dist-ssg/client/.vite/ssr-manifest.json +15 -15
- package/dist-ssg/client/assets/CanvasRenderer-C1h1JIPm.js +1 -0
- package/dist-ssg/client/assets/WebGLRenderer-8qk8lSz6.js +1 -0
- package/dist-ssg/client/assets/WebGPURenderer-BevM1O4I.js +1 -0
- package/dist-ssg/client/assets/browserAll-BgTDhPwL.js +1 -0
- package/dist-ssg/client/assets/{dist-DXnJ5xkX.js → dist-BA9W6ivS.js} +1 -1
- package/dist-ssg/client/assets/dist-BHVRVW4G.js +1 -0
- package/dist-ssg/client/assets/{dist-BTUS8_Kw.js → dist-BKmYJegx.js} +1 -1
- package/dist-ssg/client/assets/{dist-D9LLad4O.js → dist-Bl-Yx_pv.js} +1 -1
- package/dist-ssg/client/assets/{dist-Djq8HFE5.js → dist-Bo9PZWYk.js} +1 -1
- package/dist-ssg/client/assets/{dist-CXFa4KDE.js → dist-BrVgy81Q.js} +1 -1
- package/dist-ssg/client/assets/dist-CI8PS7VF.js +1 -0
- package/dist-ssg/client/assets/dist-CM3Rniow.js +1 -0
- package/dist-ssg/client/assets/{dist-DTnge_6G.js → dist-COdrA1_m.js} +1 -1
- package/dist-ssg/client/assets/{dist-BARr54Cb.js → dist-DcyfplO7.js} +1 -1
- package/dist-ssg/client/assets/{dist-C77YNQqE.js → dist-GfVlAkN6.js} +1 -1
- package/dist-ssg/client/assets/{dist-B7XHcG34.js → dist-VPeqJD5l.js} +1 -1
- package/dist-ssg/client/assets/{ghostty-web-BUrM4LmE.js → ghostty-web-DoANeMT4.js} +1 -1
- package/dist-ssg/client/assets/index-DbX4vFFM.css +2 -0
- package/dist-ssg/client/assets/{index.ssg-BU1Brmat.js → index.ssg-C2pskB7h.js} +94 -104
- package/dist-ssg/client/assets/{init-C5vrHUuy.js → init-DSot5A37.js} +1 -1
- package/dist-ssg/client/assets/trpc-T5xQ21pb.js +1 -0
- package/dist-ssg/client/assets/webworkerAll-DnUz-KLD.js +1 -0
- package/dist-ssg/client/index.ssg.html +2 -2
- package/dist-ssg/server/entry-server.js +412 -107
- package/package.json +1 -1
- package/dist/assets/CanvasRenderer-yznXxqwr.js +0 -1
- package/dist/assets/WebGLRenderer-B23oVGNL.js +0 -1
- package/dist/assets/WebGPURenderer-Cug1nwkB.js +0 -1
- package/dist/assets/browserAll-u3VqlriV.js +0 -1
- package/dist/assets/dist-COUYL3BZ.js +0 -1
- package/dist/assets/dist-hmhW0TeA.js +0 -1
- package/dist/assets/dist-zq2gg3Qj.js +0 -1
- package/dist/assets/index-C5SoNGIA.css +0 -1
- package/dist/assets/trpc-BYEnVZ4c.js +0 -1
- package/dist/assets/webworkerAll-BiDEVq-n.js +0 -1
- package/dist-ssg/client/assets/CanvasRenderer-BCXK2PVZ.js +0 -1
- package/dist-ssg/client/assets/WebGLRenderer-i-T4B6u4.js +0 -1
- package/dist-ssg/client/assets/WebGPURenderer-H88EZaPN.js +0 -1
- package/dist-ssg/client/assets/browserAll-Ae_1KSeb.js +0 -1
- package/dist-ssg/client/assets/dist-D_3RMJZl.js +0 -1
- package/dist-ssg/client/assets/dist-ENBjyU2l.js +0 -1
- package/dist-ssg/client/assets/dist-VCVOuFg2.js +0 -1
- package/dist-ssg/client/assets/index-BE9cyYzu.css +0 -2
- package/dist-ssg/client/assets/trpc-3tg7hkky.js +0 -1
- package/dist-ssg/client/assets/webworkerAll-eiudlEPb.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;
|
|
@@ -41086,6 +41087,7 @@ function useServerStatus() {
|
|
|
41086
41087
|
projectDir: null,
|
|
41087
41088
|
dirName: null,
|
|
41088
41089
|
watcherEnabled: false,
|
|
41090
|
+
projectRecovery: { state: "idle" },
|
|
41089
41091
|
error: null,
|
|
41090
41092
|
wsState: "idle",
|
|
41091
41093
|
reconnectCountdown: null
|
|
@@ -41150,6 +41152,7 @@ function useServerStatus() {
|
|
|
41150
41152
|
projectDir: "Static Export",
|
|
41151
41153
|
dirName: "Static Export",
|
|
41152
41154
|
watcherEnabled: false,
|
|
41155
|
+
projectRecovery: { state: "idle" },
|
|
41153
41156
|
error: null
|
|
41154
41157
|
}));
|
|
41155
41158
|
document.title = "OpenSpec UI (Static)";
|
|
@@ -41165,6 +41168,7 @@ function useServerStatus() {
|
|
|
41165
41168
|
projectDir,
|
|
41166
41169
|
dirName,
|
|
41167
41170
|
watcherEnabled: data.watcherEnabled,
|
|
41171
|
+
projectRecovery: data.projectRecovery,
|
|
41168
41172
|
error: null
|
|
41169
41173
|
}));
|
|
41170
41174
|
document.title = `${dirName} - OpenSpec UI`;
|
|
@@ -73681,16 +73685,6 @@ var tabsStyleText = (id) => {
|
|
|
73681
73685
|
transform: scaleX(0.5);
|
|
73682
73686
|
}
|
|
73683
73687
|
|
|
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
73688
|
#${id} .tabs-strip {
|
|
73695
73689
|
background-image: linear-gradient(
|
|
73696
73690
|
to bottom,
|
|
@@ -73728,11 +73722,17 @@ function TabsImpl({ tabs, selectedTab: controlled, onTabChange, onTabClose, onTa
|
|
|
73728
73722
|
const dropIndicatorRef = (0, import_react.useRef)(null);
|
|
73729
73723
|
const contentOrderRef = (0, import_react.useRef)(tabs.map((tab) => tab.id));
|
|
73730
73724
|
const rootRef = (0, import_react.useRef)(null);
|
|
73725
|
+
const headerRef = (0, import_react.useRef)(null);
|
|
73726
|
+
const headerShellRef = (0, import_react.useRef)(null);
|
|
73727
|
+
const headerForegroundRef = (0, import_react.useRef)(null);
|
|
73728
|
+
const selectionIndicatorRef = (0, import_react.useRef)(null);
|
|
73729
|
+
const tabsButtonRef = (0, import_react.useRef)(null);
|
|
73731
73730
|
const triggerRefs = (0, import_react.useRef)(/* @__PURE__ */ new Map());
|
|
73732
73731
|
const panelRefs = (0, import_react.useRef)(/* @__PURE__ */ new Map());
|
|
73733
73732
|
const activeTab = controlled ?? uncontrolled;
|
|
73734
73733
|
const reorderable = typeof onTabOrderChange === "function" && tabs.length > 1;
|
|
73735
73734
|
const tabIds = tabs.map((tab) => tab.id);
|
|
73735
|
+
const tabLayoutSignature = tabIds.join("|");
|
|
73736
73736
|
const tabsById = (0, import_react.useMemo)(() => new Map(tabs.map((tab) => [tab.id, tab])), [tabs]);
|
|
73737
73737
|
const contentTabs = (0, import_react.useMemo)(() => {
|
|
73738
73738
|
const nextOrder = buildStableContentTabIds(contentOrderRef.current, tabIds);
|
|
@@ -73752,10 +73752,69 @@ function TabsImpl({ tabs, selectedTab: controlled, onTabChange, onTabClose, onTa
|
|
|
73752
73752
|
getPanel(tabId) {
|
|
73753
73753
|
return panelRefs.current.get(tabId) ?? null;
|
|
73754
73754
|
},
|
|
73755
|
+
getHeaderShell() {
|
|
73756
|
+
return headerShellRef.current;
|
|
73757
|
+
},
|
|
73758
|
+
getHeaderForeground() {
|
|
73759
|
+
return headerForegroundRef.current;
|
|
73760
|
+
},
|
|
73761
|
+
getSelectionIndicator() {
|
|
73762
|
+
return selectionIndicatorRef.current;
|
|
73763
|
+
},
|
|
73755
73764
|
getActiveTabId() {
|
|
73756
73765
|
return activeTab || null;
|
|
73757
73766
|
}
|
|
73758
73767
|
}), [activeTab]);
|
|
73768
|
+
const syncSelectionIndicator = (0, import_react.useCallback)(() => {
|
|
73769
|
+
const indicator = selectionIndicatorRef.current;
|
|
73770
|
+
const header = headerRef.current;
|
|
73771
|
+
const activeTrigger = activeTab ? triggerRefs.current.get(activeTab) : null;
|
|
73772
|
+
if (!indicator) return;
|
|
73773
|
+
if (variant !== "default" || !header || !activeTrigger) {
|
|
73774
|
+
indicator.style.opacity = "0";
|
|
73775
|
+
indicator.style.width = "0px";
|
|
73776
|
+
indicator.style.height = "0px";
|
|
73777
|
+
indicator.style.transform = "translate(0px, 0px)";
|
|
73778
|
+
return;
|
|
73779
|
+
}
|
|
73780
|
+
const headerRect = header.getBoundingClientRect();
|
|
73781
|
+
const triggerRect = activeTrigger.getBoundingClientRect();
|
|
73782
|
+
indicator.style.opacity = "1";
|
|
73783
|
+
indicator.style.width = `${triggerRect.width}px`;
|
|
73784
|
+
indicator.style.height = `${triggerRect.height}px`;
|
|
73785
|
+
indicator.style.transform = `translate(${triggerRect.left - headerRect.left}px, ${triggerRect.top - headerRect.top}px)`;
|
|
73786
|
+
}, [activeTab, variant]);
|
|
73787
|
+
(0, import_react.useLayoutEffect)(() => {
|
|
73788
|
+
syncSelectionIndicator();
|
|
73789
|
+
}, [syncSelectionIndicator, tabLayoutSignature]);
|
|
73790
|
+
(0, import_react.useLayoutEffect)(() => {
|
|
73791
|
+
if (variant !== "default") return;
|
|
73792
|
+
const tabsButton = tabsButtonRef.current;
|
|
73793
|
+
if (!tabsButton) return;
|
|
73794
|
+
const handleScroll = () => {
|
|
73795
|
+
syncSelectionIndicator();
|
|
73796
|
+
};
|
|
73797
|
+
tabsButton.addEventListener("scroll", handleScroll, { passive: true });
|
|
73798
|
+
if (typeof ResizeObserver === "undefined") return () => {
|
|
73799
|
+
tabsButton.removeEventListener("scroll", handleScroll);
|
|
73800
|
+
};
|
|
73801
|
+
const observer = new ResizeObserver(() => {
|
|
73802
|
+
syncSelectionIndicator();
|
|
73803
|
+
});
|
|
73804
|
+
observer.observe(tabsButton);
|
|
73805
|
+
if (headerRef.current) observer.observe(headerRef.current);
|
|
73806
|
+
const activeTrigger = activeTab ? triggerRefs.current.get(activeTab) : null;
|
|
73807
|
+
if (activeTrigger) observer.observe(activeTrigger);
|
|
73808
|
+
return () => {
|
|
73809
|
+
tabsButton.removeEventListener("scroll", handleScroll);
|
|
73810
|
+
observer.disconnect();
|
|
73811
|
+
};
|
|
73812
|
+
}, [
|
|
73813
|
+
activeTab,
|
|
73814
|
+
syncSelectionIndicator,
|
|
73815
|
+
tabLayoutSignature,
|
|
73816
|
+
variant
|
|
73817
|
+
]);
|
|
73759
73818
|
const handleChange = (id) => {
|
|
73760
73819
|
if (!controlled) setUncontrolled(id);
|
|
73761
73820
|
onTabChange?.(id);
|
|
@@ -73835,77 +73894,115 @@ function TabsImpl({ tabs, selectedTab: controlled, onTabChange, onTabClose, onTa
|
|
|
73835
73894
|
event.dataTransfer.dropEffect = "move";
|
|
73836
73895
|
}, [reorderable]);
|
|
73837
73896
|
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
|
|
73897
|
+
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";
|
|
73898
|
+
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
73899
|
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
|
|
73900
|
+
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"}`;
|
|
73901
|
+
const activeButtonClassName = variant === "terminal" ? "tab-selected bg-background text-foreground" : "tab-selected text-foreground";
|
|
73843
73902
|
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
|
|
73903
|
+
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
73904
|
const handleTabBarDoubleClick = (event) => {
|
|
73846
73905
|
if (!onTabBarDoubleClick) return;
|
|
73847
73906
|
if (event.target.closest("[data-tab-item=\"true\"]")) return;
|
|
73848
73907
|
onTabBarDoubleClick();
|
|
73849
73908
|
};
|
|
73909
|
+
const tabButtons = tabs.map((tab) => {
|
|
73910
|
+
const dragIndicatorStyle = dropIndicator?.tabId === tab.id ? { boxShadow: dropIndicator.position === "before" ? "inset 2px 0 0 var(--border)" : "inset -2px 0 0 var(--border)" } : void 0;
|
|
73911
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
|
|
73912
|
+
ref: (element) => {
|
|
73913
|
+
triggerRefs.current.set(tab.id, element);
|
|
73914
|
+
},
|
|
73915
|
+
"data-tab-item": "true",
|
|
73916
|
+
"data-tab-id": tab.id,
|
|
73917
|
+
draggable: reorderable,
|
|
73918
|
+
onClick: () => handleChange(tab.id),
|
|
73919
|
+
onDragStart: (event) => handleDragStart(event, tab.id),
|
|
73920
|
+
onDragEnd: handleDragEnd,
|
|
73921
|
+
onDragOver: (event) => handleItemDragOver(event, tab.id),
|
|
73922
|
+
onDrop: (event) => handleItemDrop(event, tab.id),
|
|
73923
|
+
className: `${buttonBaseClassName} ${activeTab === tab.id ? activeButtonClassName : inactiveButtonClassName} ${reorderable ? "cursor-grab active:cursor-grabbing" : ""}`,
|
|
73924
|
+
style: dragIndicatorStyle,
|
|
73925
|
+
children: [
|
|
73926
|
+
tab.icon,
|
|
73927
|
+
tab.label,
|
|
73928
|
+
tab.closable && onTabClose && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
73929
|
+
role: "button",
|
|
73930
|
+
tabIndex: 0,
|
|
73931
|
+
onClick: (event) => {
|
|
73932
|
+
event.stopPropagation();
|
|
73933
|
+
onTabClose(tab.id);
|
|
73934
|
+
},
|
|
73935
|
+
onKeyDown: (event) => {
|
|
73936
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
73937
|
+
event.stopPropagation();
|
|
73938
|
+
onTabClose(tab.id);
|
|
73939
|
+
}
|
|
73940
|
+
},
|
|
73941
|
+
draggable: false,
|
|
73942
|
+
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"}`,
|
|
73943
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(X$2, { className: "h-3 w-3" })
|
|
73944
|
+
})
|
|
73945
|
+
]
|
|
73946
|
+
}, tab.id);
|
|
73947
|
+
});
|
|
73850
73948
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
73851
73949
|
id,
|
|
73852
73950
|
ref: rootRef,
|
|
73853
73951
|
"data-tabs-variant": variant,
|
|
73854
73952
|
className: `relative isolate flex min-h-0 min-w-0 flex-1 flex-col ${className}`,
|
|
73855
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.
|
|
73953
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
73954
|
+
ref: headerRef,
|
|
73856
73955
|
className: headerClassName,
|
|
73857
|
-
children:
|
|
73956
|
+
children: variant === "default" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
73957
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
73958
|
+
ref: headerShellRef,
|
|
73959
|
+
"data-tabs-header-shell": "true",
|
|
73960
|
+
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"
|
|
73961
|
+
}),
|
|
73962
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
73963
|
+
className: "pointer-events-none absolute inset-0 z-10",
|
|
73964
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
73965
|
+
ref: selectionIndicatorRef,
|
|
73966
|
+
"data-tabs-selection-indicator": "true",
|
|
73967
|
+
"aria-hidden": "true",
|
|
73968
|
+
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)]"
|
|
73969
|
+
})
|
|
73970
|
+
}),
|
|
73971
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
73972
|
+
ref: headerForegroundRef,
|
|
73973
|
+
"data-tabs-header-foreground": "true",
|
|
73974
|
+
className: "tabs-header-foreground relative z-20 flex min-w-0 items-stretch",
|
|
73975
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
73976
|
+
className: stripClassName,
|
|
73977
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
73978
|
+
ref: tabsButtonRef,
|
|
73979
|
+
className: listClassName,
|
|
73980
|
+
onDoubleClick: handleTabBarDoubleClick,
|
|
73981
|
+
onDragOver: handleListDragOver,
|
|
73982
|
+
onDrop: handleListDrop,
|
|
73983
|
+
children: tabButtons
|
|
73984
|
+
})
|
|
73985
|
+
}), actions && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
73986
|
+
"data-tabs-actions": "true",
|
|
73987
|
+
className: actionsClassName,
|
|
73988
|
+
children: actions
|
|
73989
|
+
})]
|
|
73990
|
+
})
|
|
73991
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
73858
73992
|
className: stripClassName,
|
|
73859
73993
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
73994
|
+
ref: tabsButtonRef,
|
|
73860
73995
|
className: listClassName,
|
|
73861
73996
|
onDoubleClick: handleTabBarDoubleClick,
|
|
73862
73997
|
onDragOver: handleListDragOver,
|
|
73863
73998
|
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
|
-
})
|
|
73999
|
+
children: tabButtons
|
|
73903
74000
|
})
|
|
73904
74001
|
}), actions && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
73905
74002
|
"data-tabs-actions": "true",
|
|
73906
74003
|
className: actionsClassName,
|
|
73907
74004
|
children: actions
|
|
73908
|
-
})]
|
|
74005
|
+
})] })
|
|
73909
74006
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
73910
74007
|
className: "relative flex min-h-0 flex-1 overflow-hidden",
|
|
73911
74008
|
children: contentTabs.map((tab) => tab.unmountOnHide ? activeTab === tab.id && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
@@ -73935,6 +74032,10 @@ var Tabs = (0, import_react.forwardRef)(TabsImpl);
|
|
|
73935
74032
|
var DATA_VISIBLE_HEIGHT = "tabVisibleHeight";
|
|
73936
74033
|
var DATA_TOP_INSET = "tabTopInset";
|
|
73937
74034
|
var DATA_SCROLL_OFFSET = "tabScrollOffset";
|
|
74035
|
+
var DATA_LAYOUT_BRIDGE = "tabLayoutBridge";
|
|
74036
|
+
var DATA_LAYOUT_BRIDGE_BASE_PADDING = "tabLayoutBridgeBasePadding";
|
|
74037
|
+
var DATA_LAYOUT_BRIDGE_INLINE_PADDING = "tabLayoutBridgeInlinePadding";
|
|
74038
|
+
var TAB_SCROLL_ROOT_SELECTOR = "[data-tab-scroll-root=\"true\"]";
|
|
73938
74039
|
function clamp$2(value, min, max) {
|
|
73939
74040
|
return Math.min(Math.max(value, min), max);
|
|
73940
74041
|
}
|
|
@@ -73944,6 +74045,63 @@ function maxViewportScroll(viewport) {
|
|
|
73944
74045
|
function maxPanelScroll(panel, visibleHeight) {
|
|
73945
74046
|
return Math.max(panel.scrollHeight - visibleHeight, 0);
|
|
73946
74047
|
}
|
|
74048
|
+
function readPanelLayoutBridge(panel) {
|
|
74049
|
+
return Number(panel.dataset[DATA_LAYOUT_BRIDGE] ?? "0") || 0;
|
|
74050
|
+
}
|
|
74051
|
+
function ensurePanelLayoutBridgeState(panel) {
|
|
74052
|
+
panel.dataset[DATA_LAYOUT_BRIDGE_BASE_PADDING] ||= window.getComputedStyle(panel).paddingBottom;
|
|
74053
|
+
panel.dataset[DATA_LAYOUT_BRIDGE_INLINE_PADDING] ||= panel.style.paddingBottom;
|
|
74054
|
+
}
|
|
74055
|
+
function setPanelLayoutBridge(panel, extraHeight) {
|
|
74056
|
+
ensurePanelLayoutBridgeState(panel);
|
|
74057
|
+
const normalizedHeight = Math.max(Math.ceil(extraHeight), 0);
|
|
74058
|
+
panel.dataset[DATA_LAYOUT_BRIDGE] = String(normalizedHeight);
|
|
74059
|
+
if (normalizedHeight <= 0) {
|
|
74060
|
+
panel.style.paddingBottom = panel.dataset[DATA_LAYOUT_BRIDGE_INLINE_PADDING] ?? "";
|
|
74061
|
+
return;
|
|
74062
|
+
}
|
|
74063
|
+
const basePadding = panel.dataset[DATA_LAYOUT_BRIDGE_BASE_PADDING] ?? "0px";
|
|
74064
|
+
panel.style.paddingBottom = `calc(${basePadding} + ${normalizedHeight}px)`;
|
|
74065
|
+
}
|
|
74066
|
+
function restoreViewportScroll(viewport, panel, targetScrollTop) {
|
|
74067
|
+
const applyScrollTop = () => {
|
|
74068
|
+
if (!viewport.isConnected || !panel.isConnected) return true;
|
|
74069
|
+
const existingBridge = readPanelLayoutBridge(panel);
|
|
74070
|
+
const baseMaxViewportScroll = Math.max(maxViewportScroll(viewport) - existingBridge, 0);
|
|
74071
|
+
setPanelLayoutBridge(panel, Math.max(targetScrollTop - baseMaxViewportScroll, 0));
|
|
74072
|
+
const nextScrollTop = clamp$2(targetScrollTop, 0, maxViewportScroll(viewport));
|
|
74073
|
+
viewport.scrollTop = nextScrollTop;
|
|
74074
|
+
return viewport.scrollTop === nextScrollTop;
|
|
74075
|
+
};
|
|
74076
|
+
if (applyScrollTop() || typeof requestAnimationFrame !== "function") return;
|
|
74077
|
+
let retriesRemaining = 10;
|
|
74078
|
+
const retry = () => {
|
|
74079
|
+
if (applyScrollTop() || retriesRemaining <= 0) return;
|
|
74080
|
+
retriesRemaining -= 1;
|
|
74081
|
+
requestAnimationFrame(retry);
|
|
74082
|
+
};
|
|
74083
|
+
requestAnimationFrame(retry);
|
|
74084
|
+
}
|
|
74085
|
+
function hasVerticalScrollBehavior(overflowY) {
|
|
74086
|
+
return overflowY === "auto" || overflowY === "scroll" || overflowY === "overlay";
|
|
74087
|
+
}
|
|
74088
|
+
function findScrollableDescendant(panel) {
|
|
74089
|
+
const walker = document.createTreeWalker(panel, NodeFilter.SHOW_ELEMENT);
|
|
74090
|
+
let candidate = null;
|
|
74091
|
+
while (walker.nextNode()) {
|
|
74092
|
+
const node = walker.currentNode;
|
|
74093
|
+
if (!(node instanceof HTMLElement)) continue;
|
|
74094
|
+
if (!hasVerticalScrollBehavior(window.getComputedStyle(node).overflowY) || node.scrollHeight <= node.clientHeight) continue;
|
|
74095
|
+
if (node.scrollTop > 0) return node;
|
|
74096
|
+
candidate ??= node;
|
|
74097
|
+
}
|
|
74098
|
+
return candidate;
|
|
74099
|
+
}
|
|
74100
|
+
function resolveContentScrollRoot(panel) {
|
|
74101
|
+
const markedRoot = panel.matches(TAB_SCROLL_ROOT_SELECTOR) ? panel : panel.querySelector(TAB_SCROLL_ROOT_SELECTOR);
|
|
74102
|
+
if (markedRoot) return markedRoot;
|
|
74103
|
+
return findScrollableDescendant(panel);
|
|
74104
|
+
}
|
|
73947
74105
|
function panelDocumentTop(panel, viewport) {
|
|
73948
74106
|
const panelRect = panel.getBoundingClientRect();
|
|
73949
74107
|
const viewportRect = viewport.getBoundingClientRect();
|
|
@@ -73981,40 +74139,99 @@ function restorePanel(panel, previousStyles) {
|
|
|
73981
74139
|
panel.style.overflowY = previousStyles.overflowY;
|
|
73982
74140
|
clearFrozenMetrics(panel);
|
|
73983
74141
|
}
|
|
74142
|
+
function restoreContentScrollRoot(element, targetScrollTop) {
|
|
74143
|
+
if (!element) return;
|
|
74144
|
+
const applyScrollTop = () => {
|
|
74145
|
+
if (!element.isConnected) return true;
|
|
74146
|
+
element.scrollTop = targetScrollTop;
|
|
74147
|
+
return element.scrollTop === targetScrollTop;
|
|
74148
|
+
};
|
|
74149
|
+
if (applyScrollTop() || typeof requestAnimationFrame !== "function") return;
|
|
74150
|
+
let retriesRemaining = 10;
|
|
74151
|
+
const retry = () => {
|
|
74152
|
+
if (applyScrollTop() || retriesRemaining <= 0) return;
|
|
74153
|
+
retriesRemaining -= 1;
|
|
74154
|
+
requestAnimationFrame(retry);
|
|
74155
|
+
};
|
|
74156
|
+
requestAnimationFrame(retry);
|
|
74157
|
+
}
|
|
74158
|
+
function normalizeViewportSelectors(viewportSelector) {
|
|
74159
|
+
return typeof viewportSelector === "string" ? viewportSelector.split(",").map((selector) => selector.trim()) : [...viewportSelector];
|
|
74160
|
+
}
|
|
74161
|
+
function resolveViewportBoundary(panel, viewportSelector) {
|
|
74162
|
+
const selectors = normalizeViewportSelectors(viewportSelector);
|
|
74163
|
+
for (const selector of selectors) {
|
|
74164
|
+
if (!selector) continue;
|
|
74165
|
+
try {
|
|
74166
|
+
const match = panel.closest(selector);
|
|
74167
|
+
if (match instanceof HTMLElement) return match;
|
|
74168
|
+
} catch {
|
|
74169
|
+
return null;
|
|
74170
|
+
}
|
|
74171
|
+
}
|
|
74172
|
+
return null;
|
|
74173
|
+
}
|
|
74174
|
+
function resolveScrollViewport(panel, boundary) {
|
|
74175
|
+
let current = panel.parentElement;
|
|
74176
|
+
while (current) {
|
|
74177
|
+
if (hasVerticalScrollBehavior(window.getComputedStyle(current).overflowY) && current.scrollHeight > current.clientHeight) return current;
|
|
74178
|
+
if (boundary && current === boundary) break;
|
|
74179
|
+
current = current.parentElement;
|
|
74180
|
+
}
|
|
74181
|
+
if (!boundary) return null;
|
|
74182
|
+
if (hasVerticalScrollBehavior(window.getComputedStyle(boundary).overflowY)) return boundary;
|
|
74183
|
+
return null;
|
|
74184
|
+
}
|
|
73984
74185
|
function resolveTabScrollElements(handle, tabId, viewportSelector) {
|
|
73985
74186
|
if (!viewportSelector) return null;
|
|
73986
74187
|
const panel = handle?.getPanel(tabId);
|
|
73987
74188
|
if (!(panel instanceof HTMLElement)) return null;
|
|
73988
|
-
|
|
73989
|
-
try {
|
|
73990
|
-
viewport = panel.closest(viewportSelector);
|
|
73991
|
-
} catch {
|
|
73992
|
-
return null;
|
|
73993
|
-
}
|
|
74189
|
+
const viewport = resolveScrollViewport(panel, resolveViewportBoundary(panel, viewportSelector));
|
|
73994
74190
|
if (!(viewport instanceof HTMLElement)) return null;
|
|
73995
74191
|
return {
|
|
73996
74192
|
panel,
|
|
74193
|
+
contentScrollRoot: resolveContentScrollRoot(panel),
|
|
73997
74194
|
viewport
|
|
73998
74195
|
};
|
|
73999
74196
|
}
|
|
74197
|
+
function restorePanelContentScroll(panel, snapshot) {
|
|
74198
|
+
if (!(panel instanceof HTMLElement) || !snapshot) return;
|
|
74199
|
+
const contentScrollRoot = resolveContentScrollRoot(panel);
|
|
74200
|
+
if (contentScrollRoot && contentScrollRoot !== panel) restoreContentScrollRoot(contentScrollRoot, snapshot.contentScrollTop);
|
|
74201
|
+
}
|
|
74202
|
+
function restorePanelViewportScroll(panel, viewport, snapshot) {
|
|
74203
|
+
if (!(panel instanceof HTMLElement) || !(viewport instanceof HTMLElement)) return;
|
|
74204
|
+
if (!snapshot) {
|
|
74205
|
+
setPanelLayoutBridge(panel, 0);
|
|
74206
|
+
return;
|
|
74207
|
+
}
|
|
74208
|
+
restoreViewportScroll(viewport, panel, snapshot.viewportScrollTop);
|
|
74209
|
+
}
|
|
74000
74210
|
function captureTabScrollMemory(elements) {
|
|
74001
|
-
const { panel, viewport } = elements;
|
|
74211
|
+
const { panel, contentScrollRoot, viewport } = elements;
|
|
74002
74212
|
const panelRect = panel.getBoundingClientRect();
|
|
74003
74213
|
const viewportRect = viewport.getBoundingClientRect();
|
|
74004
74214
|
const visibleHeight = clamp$2(Math.min(panelRect.bottom, viewportRect.bottom) - Math.max(panelRect.top, viewportRect.top), 0, viewport.clientHeight);
|
|
74005
74215
|
if (visibleHeight <= 0) return null;
|
|
74006
74216
|
const topInset = Math.max(panelRect.top - viewportRect.top, 0);
|
|
74217
|
+
const innerScrollTop = clamp$2(Math.max(viewportRect.top - panelRect.top, 0), 0, maxPanelScroll(panel, visibleHeight));
|
|
74007
74218
|
return {
|
|
74008
|
-
|
|
74219
|
+
contentScrollTop: contentScrollRoot && contentScrollRoot !== panel ? contentScrollRoot.scrollTop : 0,
|
|
74220
|
+
innerScrollTop,
|
|
74009
74221
|
topInset,
|
|
74010
|
-
visibleHeight
|
|
74222
|
+
visibleHeight,
|
|
74223
|
+
viewportScrollTop: viewport.scrollTop
|
|
74011
74224
|
};
|
|
74012
74225
|
}
|
|
74013
74226
|
function freezeOutgoingTab(elements, snapshot) {
|
|
74014
74227
|
const previousStyles = applyFrozenStyles(elements.panel, snapshot);
|
|
74228
|
+
if (elements.contentScrollRoot && elements.contentScrollRoot !== elements.panel) restoreContentScrollRoot(elements.contentScrollRoot, snapshot.contentScrollTop);
|
|
74015
74229
|
elements.panel.scrollTop = snapshot.innerScrollTop;
|
|
74016
74230
|
if (snapshot.innerScrollTop > 0) elements.viewport.scrollTop = clamp$2(elements.viewport.scrollTop - snapshot.innerScrollTop, 0, maxViewportScroll(elements.viewport));
|
|
74017
74231
|
return {
|
|
74232
|
+
contentScrollRoot: elements.contentScrollRoot && elements.contentScrollRoot !== elements.panel ? elements.contentScrollRoot : null,
|
|
74233
|
+
contentScrollTop: snapshot.contentScrollTop,
|
|
74234
|
+
finalViewportScrollTop: snapshot.viewportScrollTop,
|
|
74018
74235
|
panel: elements.panel,
|
|
74019
74236
|
previousStyles,
|
|
74020
74237
|
viewport: elements.viewport
|
|
@@ -74022,26 +74239,32 @@ function freezeOutgoingTab(elements, snapshot) {
|
|
|
74022
74239
|
}
|
|
74023
74240
|
function freezeIncomingTab(elements, snapshot) {
|
|
74024
74241
|
const normalizedSnapshot = {
|
|
74242
|
+
contentScrollTop: elements.contentScrollRoot && elements.contentScrollRoot !== elements.panel ? snapshot.contentScrollTop : 0,
|
|
74025
74243
|
topInset: clamp$2(snapshot.topInset, 0, elements.viewport.clientHeight),
|
|
74026
74244
|
visibleHeight: clamp$2(snapshot.visibleHeight, 1, elements.viewport.clientHeight),
|
|
74027
|
-
innerScrollTop: 0
|
|
74245
|
+
innerScrollTop: 0,
|
|
74246
|
+
viewportScrollTop: snapshot.viewportScrollTop
|
|
74028
74247
|
};
|
|
74029
74248
|
normalizedSnapshot.innerScrollTop = clamp$2(snapshot.innerScrollTop, 0, maxPanelScroll(elements.panel, normalizedSnapshot.visibleHeight));
|
|
74030
74249
|
const nextViewportScrollTop = clamp$2(panelDocumentTop(elements.panel, elements.viewport) - normalizedSnapshot.topInset, 0, maxViewportScroll(elements.viewport));
|
|
74031
74250
|
const previousStyles = applyFrozenStyles(elements.panel, normalizedSnapshot);
|
|
74032
74251
|
elements.viewport.scrollTop = nextViewportScrollTop;
|
|
74252
|
+
if (elements.contentScrollRoot && elements.contentScrollRoot !== elements.panel) restoreContentScrollRoot(elements.contentScrollRoot, normalizedSnapshot.contentScrollTop);
|
|
74033
74253
|
elements.panel.scrollTop = normalizedSnapshot.innerScrollTop;
|
|
74034
74254
|
return {
|
|
74255
|
+
contentScrollRoot: elements.contentScrollRoot && elements.contentScrollRoot !== elements.panel ? elements.contentScrollRoot : null,
|
|
74256
|
+
contentScrollTop: normalizedSnapshot.contentScrollTop,
|
|
74257
|
+
finalViewportScrollTop: snapshot.viewportScrollTop,
|
|
74035
74258
|
panel: elements.panel,
|
|
74036
74259
|
previousStyles,
|
|
74037
74260
|
viewport: elements.viewport
|
|
74038
74261
|
};
|
|
74039
74262
|
}
|
|
74040
74263
|
function finalizeFrozenIncomingTab(state) {
|
|
74041
|
-
const transferScrollTop = state.panel.scrollTop;
|
|
74042
74264
|
restorePanel(state.panel, state.previousStyles);
|
|
74043
|
-
state.viewport
|
|
74265
|
+
restoreViewportScroll(state.viewport, state.panel, state.finalViewportScrollTop);
|
|
74044
74266
|
state.panel.scrollTop = 0;
|
|
74267
|
+
if (state.contentScrollRoot) restoreContentScrollRoot(state.contentScrollRoot, state.contentScrollTop);
|
|
74045
74268
|
}
|
|
74046
74269
|
function cleanupFrozenTab(state) {
|
|
74047
74270
|
restorePanel(state.panel, state.previousStyles);
|
|
@@ -74072,6 +74295,11 @@ function resolveTabArea(pathname, area) {
|
|
|
74072
74295
|
if (area) return area;
|
|
74073
74296
|
return isStaticMode() ? "main" : navController.getAreaForPath(pathname);
|
|
74074
74297
|
}
|
|
74298
|
+
function normalizeViewportSelectorOption(viewportSelector) {
|
|
74299
|
+
if (!viewportSelector) return;
|
|
74300
|
+
const normalized = (typeof viewportSelector === "string" ? viewportSelector.split(",") : [...viewportSelector]).map((selector) => selector.trim()).filter((selector) => selector.length > 0);
|
|
74301
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
74302
|
+
}
|
|
74075
74303
|
function readWindowLocation() {
|
|
74076
74304
|
if (typeof window === "undefined") return SERVER_LOCATION;
|
|
74077
74305
|
return {
|
|
@@ -74126,6 +74354,12 @@ function useRoutedTabsLocation() {
|
|
|
74126
74354
|
function collectTabEntries(handle, tabId) {
|
|
74127
74355
|
if (!handle) return [];
|
|
74128
74356
|
const entries = [];
|
|
74357
|
+
const headerShell = handle.getHeaderShell();
|
|
74358
|
+
if (headerShell) entries.push([headerShell, "vt-tab-header-shell"]);
|
|
74359
|
+
const selectionIndicator = handle.getSelectionIndicator();
|
|
74360
|
+
if (selectionIndicator) entries.push([selectionIndicator, "vt-tab-edge"]);
|
|
74361
|
+
const headerForeground = handle.getHeaderForeground();
|
|
74362
|
+
if (headerForeground) entries.push([headerForeground, "vt-tab-header-foreground"]);
|
|
74129
74363
|
const panel = handle.getPanel(tabId);
|
|
74130
74364
|
if (panel) entries.push([panel, "vt-tab-panel"]);
|
|
74131
74365
|
return entries;
|
|
@@ -74133,8 +74367,11 @@ function collectTabEntries(handle, tabId) {
|
|
|
74133
74367
|
function useRoutedCarouselTabs({ queryKey, tabs, initialTab, area, history = "replace", allowUnknownSelection = false, viewportSelector }) {
|
|
74134
74368
|
const { location, router } = useRoutedTabsLocation();
|
|
74135
74369
|
const tabsRef = (0, import_react.useRef)(null);
|
|
74370
|
+
const viewportSelectorValue = (0, import_react.useMemo)(() => normalizeViewportSelectorOption(viewportSelector), [typeof viewportSelector === "string" ? viewportSelector : (viewportSelector ?? []).join("\0")]);
|
|
74136
74371
|
const scrollMemoryByTabRef = (0, import_react.useRef)(/* @__PURE__ */ new Map());
|
|
74137
74372
|
const frozenTabsRef = (0, import_react.useRef)(/* @__PURE__ */ new Map());
|
|
74373
|
+
const frozenTabTokenRef = (0, import_react.useRef)(0);
|
|
74374
|
+
const skipNextRestoreTabRef = (0, import_react.useRef)(null);
|
|
74138
74375
|
const selectedFromLocation = (0, import_react.useMemo)(() => resolveSelectedTab({
|
|
74139
74376
|
tabs,
|
|
74140
74377
|
queryKey,
|
|
@@ -74159,7 +74396,7 @@ function useRoutedCarouselTabs({ queryKey, tabs, initialTab, area, history = "re
|
|
|
74159
74396
|
selectedFromLocation,
|
|
74160
74397
|
selectedTab,
|
|
74161
74398
|
tabs,
|
|
74162
|
-
viewportSelector
|
|
74399
|
+
viewportSelector: viewportSelectorValue
|
|
74163
74400
|
});
|
|
74164
74401
|
latestRef.current = {
|
|
74165
74402
|
allowUnknownSelection,
|
|
@@ -74171,45 +74408,89 @@ function useRoutedCarouselTabs({ queryKey, tabs, initialTab, area, history = "re
|
|
|
74171
74408
|
selectedFromLocation,
|
|
74172
74409
|
selectedTab,
|
|
74173
74410
|
tabs,
|
|
74174
|
-
viewportSelector
|
|
74411
|
+
viewportSelector: viewportSelectorValue
|
|
74175
74412
|
};
|
|
74176
|
-
const cleanupFrozenTabById = (0, import_react.useCallback)((tabId) => {
|
|
74177
|
-
const
|
|
74178
|
-
if (!
|
|
74179
|
-
cleanupFrozenTab(
|
|
74413
|
+
const cleanupFrozenTabById = (0, import_react.useCallback)((tabId, token) => {
|
|
74414
|
+
const frozenEntry = frozenTabsRef.current.get(tabId);
|
|
74415
|
+
if (!frozenEntry || token != null && frozenEntry.token !== token) return;
|
|
74416
|
+
cleanupFrozenTab(frozenEntry.state);
|
|
74180
74417
|
frozenTabsRef.current.delete(tabId);
|
|
74181
74418
|
}, []);
|
|
74182
74419
|
const cleanupAllFrozenTabs = (0, import_react.useCallback)(() => {
|
|
74183
|
-
for (const
|
|
74420
|
+
for (const frozenEntry of frozenTabsRef.current.values()) cleanupFrozenTab(frozenEntry.state);
|
|
74184
74421
|
frozenTabsRef.current.clear();
|
|
74185
74422
|
}, []);
|
|
74186
|
-
const
|
|
74423
|
+
const captureTabSnapshot = (0, import_react.useCallback)((tabId, nextViewportSelector) => {
|
|
74424
|
+
const elements = resolveTabScrollElements(tabsRef.current, tabId, nextViewportSelector);
|
|
74425
|
+
if (!elements) return null;
|
|
74426
|
+
return captureTabScrollMemory(elements);
|
|
74427
|
+
}, []);
|
|
74428
|
+
const captureOutgoingTab = (0, import_react.useCallback)((tabId, nextViewportSelector, snapshotOverride) => {
|
|
74187
74429
|
const elements = resolveTabScrollElements(tabsRef.current, tabId, nextViewportSelector);
|
|
74188
74430
|
if (!elements) return;
|
|
74189
|
-
const snapshot = captureTabScrollMemory(elements);
|
|
74431
|
+
const snapshot = snapshotOverride ?? captureTabScrollMemory(elements);
|
|
74190
74432
|
if (!snapshot) return;
|
|
74191
74433
|
scrollMemoryByTabRef.current.set(tabId, snapshot);
|
|
74192
74434
|
cleanupFrozenTabById(tabId);
|
|
74193
|
-
|
|
74435
|
+
const token = ++frozenTabTokenRef.current;
|
|
74436
|
+
frozenTabsRef.current.set(tabId, {
|
|
74437
|
+
token,
|
|
74438
|
+
state: freezeOutgoingTab(elements, snapshot)
|
|
74439
|
+
});
|
|
74440
|
+
return token;
|
|
74194
74441
|
}, [cleanupFrozenTabById]);
|
|
74195
|
-
const prepareIncomingTab = (0, import_react.useCallback)((tabId, nextViewportSelector) => {
|
|
74442
|
+
const prepareIncomingTab = (0, import_react.useCallback)((tabId, nextViewportSelector, fallbackSnapshot) => {
|
|
74196
74443
|
const elements = resolveTabScrollElements(tabsRef.current, tabId, nextViewportSelector);
|
|
74197
|
-
if (!elements) return
|
|
74198
|
-
const snapshot = scrollMemoryByTabRef.current.get(tabId) ?? captureTabScrollMemory(elements);
|
|
74199
|
-
if (!snapshot) return
|
|
74444
|
+
if (!elements) return null;
|
|
74445
|
+
const snapshot = scrollMemoryByTabRef.current.get(tabId) ?? fallbackSnapshot ?? captureTabScrollMemory(elements);
|
|
74446
|
+
if (!snapshot) return null;
|
|
74447
|
+
if (!scrollMemoryByTabRef.current.has(tabId)) scrollMemoryByTabRef.current.set(tabId, snapshot);
|
|
74200
74448
|
cleanupFrozenTabById(tabId);
|
|
74201
|
-
|
|
74202
|
-
|
|
74449
|
+
const token = ++frozenTabTokenRef.current;
|
|
74450
|
+
frozenTabsRef.current.set(tabId, {
|
|
74451
|
+
token,
|
|
74452
|
+
state: freezeIncomingTab(elements, snapshot)
|
|
74453
|
+
});
|
|
74454
|
+
return token;
|
|
74203
74455
|
}, [cleanupFrozenTabById]);
|
|
74204
|
-
const finalizeIncomingTab = (0, import_react.useCallback)((tabId) => {
|
|
74205
|
-
const
|
|
74206
|
-
if (!
|
|
74207
|
-
finalizeFrozenIncomingTab(
|
|
74456
|
+
const finalizeIncomingTab = (0, import_react.useCallback)((tabId, token) => {
|
|
74457
|
+
const frozenEntry = frozenTabsRef.current.get(tabId);
|
|
74458
|
+
if (!frozenEntry || token != null && frozenEntry.token !== token) return;
|
|
74459
|
+
finalizeFrozenIncomingTab(frozenEntry.state);
|
|
74208
74460
|
frozenTabsRef.current.delete(tabId);
|
|
74209
74461
|
}, []);
|
|
74210
74462
|
(0, import_react.useEffect)(() => {
|
|
74211
74463
|
setSelectedTabState((current) => current === selectedFromLocation ? current : selectedFromLocation);
|
|
74212
74464
|
}, [selectedFromLocation]);
|
|
74465
|
+
(0, import_react.useLayoutEffect)(() => {
|
|
74466
|
+
if (skipNextRestoreTabRef.current === selectedTab) {
|
|
74467
|
+
skipNextRestoreTabRef.current = null;
|
|
74468
|
+
return;
|
|
74469
|
+
}
|
|
74470
|
+
const snapshot = scrollMemoryByTabRef.current.get(selectedTab);
|
|
74471
|
+
const elements = resolveTabScrollElements(tabsRef.current, selectedTab, viewportSelectorValue);
|
|
74472
|
+
const panel = elements?.panel ?? tabsRef.current?.getPanel(selectedTab) ?? null;
|
|
74473
|
+
restorePanelContentScroll(panel, snapshot);
|
|
74474
|
+
restorePanelViewportScroll(panel, elements?.viewport ?? null, snapshot);
|
|
74475
|
+
}, [selectedTab, viewportSelectorValue]);
|
|
74476
|
+
(0, import_react.useEffect)(() => {
|
|
74477
|
+
const elements = resolveTabScrollElements(tabsRef.current, selectedTab, viewportSelectorValue);
|
|
74478
|
+
const contentScrollRoot = elements?.contentScrollRoot;
|
|
74479
|
+
if (!elements || !contentScrollRoot || contentScrollRoot === elements.panel) return;
|
|
74480
|
+
const rememberContentScroll = () => {
|
|
74481
|
+
const existingSnapshot = scrollMemoryByTabRef.current.get(selectedTab);
|
|
74482
|
+
if (!existingSnapshot) return;
|
|
74483
|
+
scrollMemoryByTabRef.current.set(selectedTab, {
|
|
74484
|
+
...existingSnapshot,
|
|
74485
|
+
contentScrollTop: contentScrollRoot.scrollTop
|
|
74486
|
+
});
|
|
74487
|
+
};
|
|
74488
|
+
rememberContentScroll();
|
|
74489
|
+
contentScrollRoot.addEventListener("scroll", rememberContentScroll, { passive: true });
|
|
74490
|
+
return () => {
|
|
74491
|
+
contentScrollRoot.removeEventListener("scroll", rememberContentScroll);
|
|
74492
|
+
};
|
|
74493
|
+
}, [selectedTab, viewportSelectorValue]);
|
|
74213
74494
|
(0, import_react.useEffect)(() => {
|
|
74214
74495
|
const validIds = new Set(tabs.map((tab) => tab.id));
|
|
74215
74496
|
for (const tabId of scrollMemoryByTabRef.current.keys()) if (!validIds.has(tabId)) scrollMemoryByTabRef.current.delete(tabId);
|
|
@@ -74226,6 +74507,7 @@ function useRoutedCarouselTabs({ queryKey, tabs, initialTab, area, history = "re
|
|
|
74226
74507
|
const { allowUnknownSelection: allowUnknown, area: latestArea, history: defaultHistory, location: latestLocation, queryKey: latestQueryKey, router: latestRouter, selectedFromLocation: latestSelectedFromLocation, selectedTab: currentTab, tabs: latestTabs, viewportSelector: latestViewportSelector } = latestRef.current;
|
|
74227
74508
|
if (!new Set(latestTabs.map((tab) => tab.id)).has(nextTabId) && !allowUnknown) return;
|
|
74228
74509
|
const nextHistory = options?.history ?? defaultHistory;
|
|
74510
|
+
const transferScroll = options?.transferScroll ?? true;
|
|
74229
74511
|
if (currentTab === nextTabId && latestSelectedFromLocation === nextTabId) return;
|
|
74230
74512
|
const commitSelection = () => {
|
|
74231
74513
|
setSelectedTabState(nextTabId);
|
|
@@ -74249,18 +74531,40 @@ function useRoutedCarouselTabs({ queryKey, tabs, initialTab, area, history = "re
|
|
|
74249
74531
|
}
|
|
74250
74532
|
navController.push(nextArea, href, latestLocation.state);
|
|
74251
74533
|
};
|
|
74534
|
+
if (!transferScroll) {
|
|
74535
|
+
const outgoingSnapshot = captureTabSnapshot(currentTab, latestViewportSelector);
|
|
74536
|
+
if (outgoingSnapshot) scrollMemoryByTabRef.current.set(currentTab, outgoingSnapshot);
|
|
74537
|
+
skipNextRestoreTabRef.current = nextTabId;
|
|
74538
|
+
if (!options?.animate || currentTab === nextTabId) {
|
|
74539
|
+
commitSelection();
|
|
74540
|
+
return;
|
|
74541
|
+
}
|
|
74542
|
+
runViewTransition({
|
|
74543
|
+
intent: {
|
|
74544
|
+
area: resolveTabArea(latestLocation.pathname, latestArea),
|
|
74545
|
+
kind: "tab-carousel",
|
|
74546
|
+
direction: "forward"
|
|
74547
|
+
},
|
|
74548
|
+
collectBeforeEntries: () => collectTabEntries(tabsRef.current, currentTab),
|
|
74549
|
+
collectAfterEntries: () => collectTabEntries(tabsRef.current, nextTabId),
|
|
74550
|
+
update: commitSelection
|
|
74551
|
+
});
|
|
74552
|
+
return;
|
|
74553
|
+
}
|
|
74252
74554
|
const runSelectionWithScrollTransfer = (animated) => {
|
|
74253
|
-
|
|
74555
|
+
const outgoingSnapshot = captureTabSnapshot(currentTab, latestViewportSelector);
|
|
74556
|
+
const incomingSeedSnapshot = scrollMemoryByTabRef.current.get(nextTabId) ?? outgoingSnapshot ?? captureTabSnapshot(nextTabId, latestViewportSelector);
|
|
74557
|
+
const outgoingToken = captureOutgoingTab(currentTab, latestViewportSelector, outgoingSnapshot);
|
|
74254
74558
|
if (!animated) {
|
|
74255
74559
|
(0, import_react_dom.flushSync)(() => {
|
|
74256
74560
|
commitSelection();
|
|
74257
74561
|
});
|
|
74258
|
-
prepareIncomingTab(nextTabId, latestViewportSelector);
|
|
74259
|
-
finalizeIncomingTab(nextTabId);
|
|
74260
|
-
cleanupFrozenTabById(currentTab);
|
|
74562
|
+
const incomingToken = prepareIncomingTab(nextTabId, latestViewportSelector, incomingSeedSnapshot);
|
|
74563
|
+
if (incomingToken != null) finalizeIncomingTab(nextTabId, incomingToken);
|
|
74564
|
+
if (outgoingToken != null) cleanupFrozenTabById(currentTab, outgoingToken);
|
|
74261
74565
|
return;
|
|
74262
74566
|
}
|
|
74263
|
-
let
|
|
74567
|
+
let incomingToken = null;
|
|
74264
74568
|
runViewTransition({
|
|
74265
74569
|
intent: {
|
|
74266
74570
|
area: resolveTabArea(latestLocation.pathname, latestArea),
|
|
@@ -74269,14 +74573,14 @@ function useRoutedCarouselTabs({ queryKey, tabs, initialTab, area, history = "re
|
|
|
74269
74573
|
},
|
|
74270
74574
|
collectBeforeEntries: () => collectTabEntries(tabsRef.current, currentTab),
|
|
74271
74575
|
collectAfterEntries: () => {
|
|
74272
|
-
if (
|
|
74576
|
+
if (incomingToken == null) incomingToken = prepareIncomingTab(nextTabId, latestViewportSelector, incomingSeedSnapshot);
|
|
74273
74577
|
return collectTabEntries(tabsRef.current, nextTabId);
|
|
74274
74578
|
},
|
|
74275
74579
|
update: commitSelection
|
|
74276
74580
|
}).finally(() => {
|
|
74277
|
-
if (
|
|
74278
|
-
finalizeIncomingTab(nextTabId);
|
|
74279
|
-
cleanupFrozenTabById(currentTab);
|
|
74581
|
+
if (incomingToken == null) incomingToken = prepareIncomingTab(nextTabId, latestViewportSelector, incomingSeedSnapshot);
|
|
74582
|
+
if (incomingToken != null) finalizeIncomingTab(nextTabId, incomingToken);
|
|
74583
|
+
if (outgoingToken != null) cleanupFrozenTabById(currentTab, outgoingToken);
|
|
74280
74584
|
});
|
|
74281
74585
|
};
|
|
74282
74586
|
if (!options?.animate || currentTab === nextTabId) {
|
|
@@ -74293,6 +74597,7 @@ function useRoutedCarouselTabs({ queryKey, tabs, initialTab, area, history = "re
|
|
|
74293
74597
|
runSelectionWithScrollTransfer(true);
|
|
74294
74598
|
}, [
|
|
74295
74599
|
captureOutgoingTab,
|
|
74600
|
+
captureTabSnapshot,
|
|
74296
74601
|
cleanupFrozenTabById,
|
|
74297
74602
|
finalizeIncomingTab,
|
|
74298
74603
|
prepareIncomingTab
|