@openspecui/web 2.3.4 → 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.
Files changed (70) hide show
  1. package/dist/assets/CanvasRenderer-DLCesp1A.js +1 -0
  2. package/dist/assets/WebGLRenderer-DYT9IbsA.js +1 -0
  3. package/dist/assets/WebGPURenderer-CYfC6MR9.js +1 -0
  4. package/dist/assets/browserAll-CmR4zgGr.js +1 -0
  5. package/dist/assets/{dist-CyMw4R35.js → dist-5fi0H1tv.js} +1 -1
  6. package/dist/assets/{dist-BURffNKn.js → dist-9w-ZAZ0x.js} +1 -1
  7. package/dist/assets/{dist-EecJWaiB.js → dist-AstaMS2N.js} +1 -1
  8. package/dist/assets/{dist-C4qVWCwa.js → dist-BY07yBep.js} +1 -1
  9. package/dist/assets/dist-BkrPETxD.js +1 -0
  10. package/dist/assets/dist-DABwUepA.js +1 -0
  11. package/dist/assets/{dist-0r-fEysT.js → dist-DDChZc3A.js} +1 -1
  12. package/dist/assets/{dist-C_hvHrdB.js → dist-DQMVt2X6.js} +1 -1
  13. package/dist/assets/{dist-Dw21sB44.js → dist-DTgAMGJk.js} +1 -1
  14. package/dist/assets/{dist-BkfyzqOP.js → dist-DtkkWh_t.js} +1 -1
  15. package/dist/assets/dist-hgHsmBgz.js +1 -0
  16. package/dist/assets/{dist-D5aqbpvI.js → dist-j40sCais.js} +1 -1
  17. package/dist/assets/{ghostty-web-Dz4JIhSO.js → ghostty-web-BRCaoYqS.js} +1 -1
  18. package/dist/assets/index-C0tlID-0.css +1 -0
  19. package/dist/assets/index-CUgehjti.js +1578 -0
  20. package/dist/assets/{init-B8PdfdJA.js → init-CIIgfU1P.js} +1 -1
  21. package/dist/assets/trpc-2zCd4YGO.js +1 -0
  22. package/dist/assets/webworkerAll-CwuSdyaU.js +1 -0
  23. package/dist/index.html +2 -2
  24. package/dist-ssg/client/.vite/ssr-manifest.json +15 -15
  25. package/dist-ssg/client/assets/CanvasRenderer-vRzYl9FZ.js +1 -0
  26. package/dist-ssg/client/assets/WebGLRenderer-BrfpRfdk.js +1 -0
  27. package/dist-ssg/client/assets/WebGPURenderer-r7TRWUkD.js +1 -0
  28. package/dist-ssg/client/assets/browserAll-D7igzN7y.js +1 -0
  29. package/dist-ssg/client/assets/{dist-Djq8HFE5.js → dist-BFqpuvkT.js} +1 -1
  30. package/dist-ssg/client/assets/{dist-D9LLad4O.js → dist-BNNep2NV.js} +1 -1
  31. package/dist-ssg/client/assets/{dist-BTUS8_Kw.js → dist-B_u-l1Yw.js} +1 -1
  32. package/dist-ssg/client/assets/{dist-DXnJ5xkX.js → dist-CRvuTuq9.js} +1 -1
  33. package/dist-ssg/client/assets/{dist-C77YNQqE.js → dist-CXGBVAg6.js} +1 -1
  34. package/dist-ssg/client/assets/{dist-DTnge_6G.js → dist-ClTBYSyP.js} +1 -1
  35. package/dist-ssg/client/assets/{dist-BARr54Cb.js → dist-CmH6Ad9e.js} +1 -1
  36. package/dist-ssg/client/assets/{dist-B7XHcG34.js → dist-DBjExBIn.js} +1 -1
  37. package/dist-ssg/client/assets/{dist-CXFa4KDE.js → dist-DKZbBcYn.js} +1 -1
  38. package/dist-ssg/client/assets/dist-Ky-fb63H.js +1 -0
  39. package/dist-ssg/client/assets/dist-tjvftgmy.js +1 -0
  40. package/dist-ssg/client/assets/dist-y9aZTMms.js +1 -0
  41. package/dist-ssg/client/assets/{ghostty-web-BUrM4LmE.js → ghostty-web-PY5w9Rgq.js} +1 -1
  42. package/dist-ssg/client/assets/index-DvpLdKST.css +2 -0
  43. package/dist-ssg/client/assets/{index.ssg-BU1Brmat.js → index.ssg-yS5IzoBe.js} +94 -104
  44. package/dist-ssg/client/assets/{init-C5vrHUuy.js → init-zJql3EoS.js} +1 -1
  45. package/dist-ssg/client/assets/trpc-Z2U-lHEj.js +1 -0
  46. package/dist-ssg/client/assets/webworkerAll-_OODBDte.js +1 -0
  47. package/dist-ssg/client/index.ssg.html +2 -2
  48. package/dist-ssg/server/entry-server.js +409 -107
  49. package/package.json +1 -1
  50. package/dist/assets/CanvasRenderer-yznXxqwr.js +0 -1
  51. package/dist/assets/WebGLRenderer-B23oVGNL.js +0 -1
  52. package/dist/assets/WebGPURenderer-Cug1nwkB.js +0 -1
  53. package/dist/assets/browserAll-u3VqlriV.js +0 -1
  54. package/dist/assets/dist-COUYL3BZ.js +0 -1
  55. package/dist/assets/dist-hmhW0TeA.js +0 -1
  56. package/dist/assets/dist-zq2gg3Qj.js +0 -1
  57. package/dist/assets/index-C5SoNGIA.css +0 -1
  58. package/dist/assets/index-CEpXtWXm.js +0 -1588
  59. package/dist/assets/trpc-BYEnVZ4c.js +0 -1
  60. package/dist/assets/webworkerAll-BiDEVq-n.js +0 -1
  61. package/dist-ssg/client/assets/CanvasRenderer-BCXK2PVZ.js +0 -1
  62. package/dist-ssg/client/assets/WebGLRenderer-i-T4B6u4.js +0 -1
  63. package/dist-ssg/client/assets/WebGPURenderer-H88EZaPN.js +0 -1
  64. package/dist-ssg/client/assets/browserAll-Ae_1KSeb.js +0 -1
  65. package/dist-ssg/client/assets/dist-D_3RMJZl.js +0 -1
  66. package/dist-ssg/client/assets/dist-ENBjyU2l.js +0 -1
  67. package/dist-ssg/client/assets/dist-VCVOuFg2.js +0 -1
  68. package/dist-ssg/client/assets/index-BE9cyYzu.css +0 -2
  69. package/dist-ssg/client/assets/trpc-3tg7hkky.js +0 -1
  70. 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$5 = typeof window !== "undefined" ? import_react.useLayoutEffect : import_react.useEffect;
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$5(() => {
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$5(() => {
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$5(() => {
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$5(() => {
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 filterDistinctEntries(entries, beforeEntries) {
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: () => filterDistinctEntries(collectAfterEntries(), beforeEntries)
39507
+ collectEntries: () => filterAfterEntries(collectAfterEntries(), beforeEntries, intent)
39507
39508
  });
39508
39509
  for (let attempt = 0; attempt < 4; attempt += 1) {
39509
- const entries = filterDistinctEntries(collectAfterEntries(), beforeEntries);
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 filterDistinctEntries(collectAfterEntries(), beforeEntries);
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 bg-card/95 sticky top-0 z-20 flex min-w-0 items-stretch rounded-md border border-zinc-500/15 shadow-[inset_0_-1px_0_color-mix(in_srgb,var(--border)_85%,transparent)] backdrop-blur-sm";
73839
- const stripClassName = variant === "terminal" ? "tabs-strip min-w-0 flex-1 bg-terminal px-4" : "tabs-strip bg-card/95 min-w-0 flex-1 rounded-l-md px-4";
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 bg-background/70 text-foreground";
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 bg-card/95 border-zinc-500/15 flex shrink-0 items-center rounded-r-md border-l px-1";
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.jsxs)("div", {
73950
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
73951
+ ref: headerRef,
73856
73952
  className: headerClassName,
73857
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
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: tabs.map((tab) => {
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", {
@@ -73935,6 +74029,10 @@ var Tabs = (0, import_react.forwardRef)(TabsImpl);
73935
74029
  var DATA_VISIBLE_HEIGHT = "tabVisibleHeight";
73936
74030
  var DATA_TOP_INSET = "tabTopInset";
73937
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\"]";
73938
74036
  function clamp$2(value, min, max) {
73939
74037
  return Math.min(Math.max(value, min), max);
73940
74038
  }
@@ -73944,6 +74042,63 @@ function maxViewportScroll(viewport) {
73944
74042
  function maxPanelScroll(panel, visibleHeight) {
73945
74043
  return Math.max(panel.scrollHeight - visibleHeight, 0);
73946
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
+ }
73947
74102
  function panelDocumentTop(panel, viewport) {
73948
74103
  const panelRect = panel.getBoundingClientRect();
73949
74104
  const viewportRect = viewport.getBoundingClientRect();
@@ -73981,40 +74136,99 @@ function restorePanel(panel, previousStyles) {
73981
74136
  panel.style.overflowY = previousStyles.overflowY;
73982
74137
  clearFrozenMetrics(panel);
73983
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
+ }
73984
74182
  function resolveTabScrollElements(handle, tabId, viewportSelector) {
73985
74183
  if (!viewportSelector) return null;
73986
74184
  const panel = handle?.getPanel(tabId);
73987
74185
  if (!(panel instanceof HTMLElement)) return null;
73988
- let viewport = null;
73989
- try {
73990
- viewport = panel.closest(viewportSelector);
73991
- } catch {
73992
- return null;
73993
- }
74186
+ const viewport = resolveScrollViewport(panel, resolveViewportBoundary(panel, viewportSelector));
73994
74187
  if (!(viewport instanceof HTMLElement)) return null;
73995
74188
  return {
73996
74189
  panel,
74190
+ contentScrollRoot: resolveContentScrollRoot(panel),
73997
74191
  viewport
73998
74192
  };
73999
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
+ }
74000
74207
  function captureTabScrollMemory(elements) {
74001
- const { panel, viewport } = elements;
74208
+ const { panel, contentScrollRoot, viewport } = elements;
74002
74209
  const panelRect = panel.getBoundingClientRect();
74003
74210
  const viewportRect = viewport.getBoundingClientRect();
74004
74211
  const visibleHeight = clamp$2(Math.min(panelRect.bottom, viewportRect.bottom) - Math.max(panelRect.top, viewportRect.top), 0, viewport.clientHeight);
74005
74212
  if (visibleHeight <= 0) return null;
74006
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));
74007
74215
  return {
74008
- innerScrollTop: clamp$2(Math.max(viewportRect.top - panelRect.top, 0), 0, maxPanelScroll(panel, visibleHeight)),
74216
+ contentScrollTop: contentScrollRoot && contentScrollRoot !== panel ? contentScrollRoot.scrollTop : 0,
74217
+ innerScrollTop,
74009
74218
  topInset,
74010
- visibleHeight
74219
+ visibleHeight,
74220
+ viewportScrollTop: viewport.scrollTop
74011
74221
  };
74012
74222
  }
74013
74223
  function freezeOutgoingTab(elements, snapshot) {
74014
74224
  const previousStyles = applyFrozenStyles(elements.panel, snapshot);
74225
+ if (elements.contentScrollRoot && elements.contentScrollRoot !== elements.panel) restoreContentScrollRoot(elements.contentScrollRoot, snapshot.contentScrollTop);
74015
74226
  elements.panel.scrollTop = snapshot.innerScrollTop;
74016
74227
  if (snapshot.innerScrollTop > 0) elements.viewport.scrollTop = clamp$2(elements.viewport.scrollTop - snapshot.innerScrollTop, 0, maxViewportScroll(elements.viewport));
74017
74228
  return {
74229
+ contentScrollRoot: elements.contentScrollRoot && elements.contentScrollRoot !== elements.panel ? elements.contentScrollRoot : null,
74230
+ contentScrollTop: snapshot.contentScrollTop,
74231
+ finalViewportScrollTop: snapshot.viewportScrollTop,
74018
74232
  panel: elements.panel,
74019
74233
  previousStyles,
74020
74234
  viewport: elements.viewport
@@ -74022,26 +74236,32 @@ function freezeOutgoingTab(elements, snapshot) {
74022
74236
  }
74023
74237
  function freezeIncomingTab(elements, snapshot) {
74024
74238
  const normalizedSnapshot = {
74239
+ contentScrollTop: elements.contentScrollRoot && elements.contentScrollRoot !== elements.panel ? snapshot.contentScrollTop : 0,
74025
74240
  topInset: clamp$2(snapshot.topInset, 0, elements.viewport.clientHeight),
74026
74241
  visibleHeight: clamp$2(snapshot.visibleHeight, 1, elements.viewport.clientHeight),
74027
- innerScrollTop: 0
74242
+ innerScrollTop: 0,
74243
+ viewportScrollTop: snapshot.viewportScrollTop
74028
74244
  };
74029
74245
  normalizedSnapshot.innerScrollTop = clamp$2(snapshot.innerScrollTop, 0, maxPanelScroll(elements.panel, normalizedSnapshot.visibleHeight));
74030
74246
  const nextViewportScrollTop = clamp$2(panelDocumentTop(elements.panel, elements.viewport) - normalizedSnapshot.topInset, 0, maxViewportScroll(elements.viewport));
74031
74247
  const previousStyles = applyFrozenStyles(elements.panel, normalizedSnapshot);
74032
74248
  elements.viewport.scrollTop = nextViewportScrollTop;
74249
+ if (elements.contentScrollRoot && elements.contentScrollRoot !== elements.panel) restoreContentScrollRoot(elements.contentScrollRoot, normalizedSnapshot.contentScrollTop);
74033
74250
  elements.panel.scrollTop = normalizedSnapshot.innerScrollTop;
74034
74251
  return {
74252
+ contentScrollRoot: elements.contentScrollRoot && elements.contentScrollRoot !== elements.panel ? elements.contentScrollRoot : null,
74253
+ contentScrollTop: normalizedSnapshot.contentScrollTop,
74254
+ finalViewportScrollTop: snapshot.viewportScrollTop,
74035
74255
  panel: elements.panel,
74036
74256
  previousStyles,
74037
74257
  viewport: elements.viewport
74038
74258
  };
74039
74259
  }
74040
74260
  function finalizeFrozenIncomingTab(state) {
74041
- const transferScrollTop = state.panel.scrollTop;
74042
74261
  restorePanel(state.panel, state.previousStyles);
74043
- state.viewport.scrollTop = clamp$2(state.viewport.scrollTop + transferScrollTop, 0, maxViewportScroll(state.viewport));
74262
+ restoreViewportScroll(state.viewport, state.panel, state.finalViewportScrollTop);
74044
74263
  state.panel.scrollTop = 0;
74264
+ if (state.contentScrollRoot) restoreContentScrollRoot(state.contentScrollRoot, state.contentScrollTop);
74045
74265
  }
74046
74266
  function cleanupFrozenTab(state) {
74047
74267
  restorePanel(state.panel, state.previousStyles);
@@ -74072,6 +74292,11 @@ function resolveTabArea(pathname, area) {
74072
74292
  if (area) return area;
74073
74293
  return isStaticMode() ? "main" : navController.getAreaForPath(pathname);
74074
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
+ }
74075
74300
  function readWindowLocation() {
74076
74301
  if (typeof window === "undefined") return SERVER_LOCATION;
74077
74302
  return {
@@ -74126,6 +74351,12 @@ function useRoutedTabsLocation() {
74126
74351
  function collectTabEntries(handle, tabId) {
74127
74352
  if (!handle) return [];
74128
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"]);
74129
74360
  const panel = handle.getPanel(tabId);
74130
74361
  if (panel) entries.push([panel, "vt-tab-panel"]);
74131
74362
  return entries;
@@ -74133,8 +74364,11 @@ function collectTabEntries(handle, tabId) {
74133
74364
  function useRoutedCarouselTabs({ queryKey, tabs, initialTab, area, history = "replace", allowUnknownSelection = false, viewportSelector }) {
74134
74365
  const { location, router } = useRoutedTabsLocation();
74135
74366
  const tabsRef = (0, import_react.useRef)(null);
74367
+ const viewportSelectorValue = (0, import_react.useMemo)(() => normalizeViewportSelectorOption(viewportSelector), [typeof viewportSelector === "string" ? viewportSelector : (viewportSelector ?? []).join("\0")]);
74136
74368
  const scrollMemoryByTabRef = (0, import_react.useRef)(/* @__PURE__ */ new Map());
74137
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);
74138
74372
  const selectedFromLocation = (0, import_react.useMemo)(() => resolveSelectedTab({
74139
74373
  tabs,
74140
74374
  queryKey,
@@ -74159,7 +74393,7 @@ function useRoutedCarouselTabs({ queryKey, tabs, initialTab, area, history = "re
74159
74393
  selectedFromLocation,
74160
74394
  selectedTab,
74161
74395
  tabs,
74162
- viewportSelector
74396
+ viewportSelector: viewportSelectorValue
74163
74397
  });
74164
74398
  latestRef.current = {
74165
74399
  allowUnknownSelection,
@@ -74171,45 +74405,89 @@ function useRoutedCarouselTabs({ queryKey, tabs, initialTab, area, history = "re
74171
74405
  selectedFromLocation,
74172
74406
  selectedTab,
74173
74407
  tabs,
74174
- viewportSelector
74408
+ viewportSelector: viewportSelectorValue
74175
74409
  };
74176
- const cleanupFrozenTabById = (0, import_react.useCallback)((tabId) => {
74177
- const frozenState = frozenTabsRef.current.get(tabId);
74178
- if (!frozenState) return;
74179
- cleanupFrozenTab(frozenState);
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);
74180
74414
  frozenTabsRef.current.delete(tabId);
74181
74415
  }, []);
74182
74416
  const cleanupAllFrozenTabs = (0, import_react.useCallback)(() => {
74183
- for (const frozenState of frozenTabsRef.current.values()) cleanupFrozenTab(frozenState);
74417
+ for (const frozenEntry of frozenTabsRef.current.values()) cleanupFrozenTab(frozenEntry.state);
74184
74418
  frozenTabsRef.current.clear();
74185
74419
  }, []);
74186
- const captureOutgoingTab = (0, import_react.useCallback)((tabId, nextViewportSelector) => {
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) => {
74187
74426
  const elements = resolveTabScrollElements(tabsRef.current, tabId, nextViewportSelector);
74188
74427
  if (!elements) return;
74189
- const snapshot = captureTabScrollMemory(elements);
74428
+ const snapshot = snapshotOverride ?? captureTabScrollMemory(elements);
74190
74429
  if (!snapshot) return;
74191
74430
  scrollMemoryByTabRef.current.set(tabId, snapshot);
74192
74431
  cleanupFrozenTabById(tabId);
74193
- frozenTabsRef.current.set(tabId, freezeOutgoingTab(elements, snapshot));
74432
+ const token = ++frozenTabTokenRef.current;
74433
+ frozenTabsRef.current.set(tabId, {
74434
+ token,
74435
+ state: freezeOutgoingTab(elements, snapshot)
74436
+ });
74437
+ return token;
74194
74438
  }, [cleanupFrozenTabById]);
74195
- const prepareIncomingTab = (0, import_react.useCallback)((tabId, nextViewportSelector) => {
74439
+ const prepareIncomingTab = (0, import_react.useCallback)((tabId, nextViewportSelector, fallbackSnapshot) => {
74196
74440
  const elements = resolveTabScrollElements(tabsRef.current, tabId, nextViewportSelector);
74197
- if (!elements) return false;
74198
- const snapshot = scrollMemoryByTabRef.current.get(tabId) ?? captureTabScrollMemory(elements);
74199
- if (!snapshot) return false;
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);
74200
74445
  cleanupFrozenTabById(tabId);
74201
- frozenTabsRef.current.set(tabId, freezeIncomingTab(elements, snapshot));
74202
- return true;
74446
+ const token = ++frozenTabTokenRef.current;
74447
+ frozenTabsRef.current.set(tabId, {
74448
+ token,
74449
+ state: freezeIncomingTab(elements, snapshot)
74450
+ });
74451
+ return token;
74203
74452
  }, [cleanupFrozenTabById]);
74204
- const finalizeIncomingTab = (0, import_react.useCallback)((tabId) => {
74205
- const frozenState = frozenTabsRef.current.get(tabId);
74206
- if (!frozenState) return;
74207
- finalizeFrozenIncomingTab(frozenState);
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);
74208
74457
  frozenTabsRef.current.delete(tabId);
74209
74458
  }, []);
74210
74459
  (0, import_react.useEffect)(() => {
74211
74460
  setSelectedTabState((current) => current === selectedFromLocation ? current : selectedFromLocation);
74212
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]);
74213
74491
  (0, import_react.useEffect)(() => {
74214
74492
  const validIds = new Set(tabs.map((tab) => tab.id));
74215
74493
  for (const tabId of scrollMemoryByTabRef.current.keys()) if (!validIds.has(tabId)) scrollMemoryByTabRef.current.delete(tabId);
@@ -74226,6 +74504,7 @@ function useRoutedCarouselTabs({ queryKey, tabs, initialTab, area, history = "re
74226
74504
  const { allowUnknownSelection: allowUnknown, area: latestArea, history: defaultHistory, location: latestLocation, queryKey: latestQueryKey, router: latestRouter, selectedFromLocation: latestSelectedFromLocation, selectedTab: currentTab, tabs: latestTabs, viewportSelector: latestViewportSelector } = latestRef.current;
74227
74505
  if (!new Set(latestTabs.map((tab) => tab.id)).has(nextTabId) && !allowUnknown) return;
74228
74506
  const nextHistory = options?.history ?? defaultHistory;
74507
+ const transferScroll = options?.transferScroll ?? true;
74229
74508
  if (currentTab === nextTabId && latestSelectedFromLocation === nextTabId) return;
74230
74509
  const commitSelection = () => {
74231
74510
  setSelectedTabState(nextTabId);
@@ -74249,18 +74528,40 @@ function useRoutedCarouselTabs({ queryKey, tabs, initialTab, area, history = "re
74249
74528
  }
74250
74529
  navController.push(nextArea, href, latestLocation.state);
74251
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
+ }
74252
74551
  const runSelectionWithScrollTransfer = (animated) => {
74253
- captureOutgoingTab(currentTab, latestViewportSelector);
74552
+ const outgoingSnapshot = captureTabSnapshot(currentTab, latestViewportSelector);
74553
+ const incomingSeedSnapshot = scrollMemoryByTabRef.current.get(nextTabId) ?? outgoingSnapshot ?? captureTabSnapshot(nextTabId, latestViewportSelector);
74554
+ const outgoingToken = captureOutgoingTab(currentTab, latestViewportSelector, outgoingSnapshot);
74254
74555
  if (!animated) {
74255
74556
  (0, import_react_dom.flushSync)(() => {
74256
74557
  commitSelection();
74257
74558
  });
74258
- prepareIncomingTab(nextTabId, latestViewportSelector);
74259
- finalizeIncomingTab(nextTabId);
74260
- cleanupFrozenTabById(currentTab);
74559
+ const incomingToken = prepareIncomingTab(nextTabId, latestViewportSelector, incomingSeedSnapshot);
74560
+ if (incomingToken != null) finalizeIncomingTab(nextTabId, incomingToken);
74561
+ if (outgoingToken != null) cleanupFrozenTabById(currentTab, outgoingToken);
74261
74562
  return;
74262
74563
  }
74263
- let hasPreparedIncoming = false;
74564
+ let incomingToken = null;
74264
74565
  runViewTransition({
74265
74566
  intent: {
74266
74567
  area: resolveTabArea(latestLocation.pathname, latestArea),
@@ -74269,14 +74570,14 @@ function useRoutedCarouselTabs({ queryKey, tabs, initialTab, area, history = "re
74269
74570
  },
74270
74571
  collectBeforeEntries: () => collectTabEntries(tabsRef.current, currentTab),
74271
74572
  collectAfterEntries: () => {
74272
- if (!hasPreparedIncoming) hasPreparedIncoming = prepareIncomingTab(nextTabId, latestViewportSelector);
74573
+ if (incomingToken == null) incomingToken = prepareIncomingTab(nextTabId, latestViewportSelector, incomingSeedSnapshot);
74273
74574
  return collectTabEntries(tabsRef.current, nextTabId);
74274
74575
  },
74275
74576
  update: commitSelection
74276
74577
  }).finally(() => {
74277
- if (!hasPreparedIncoming) prepareIncomingTab(nextTabId, latestViewportSelector);
74278
- finalizeIncomingTab(nextTabId);
74279
- cleanupFrozenTabById(currentTab);
74578
+ if (incomingToken == null) incomingToken = prepareIncomingTab(nextTabId, latestViewportSelector, incomingSeedSnapshot);
74579
+ if (incomingToken != null) finalizeIncomingTab(nextTabId, incomingToken);
74580
+ if (outgoingToken != null) cleanupFrozenTabById(currentTab, outgoingToken);
74280
74581
  });
74281
74582
  };
74282
74583
  if (!options?.animate || currentTab === nextTabId) {
@@ -74293,6 +74594,7 @@ function useRoutedCarouselTabs({ queryKey, tabs, initialTab, area, history = "re
74293
74594
  runSelectionWithScrollTransfer(true);
74294
74595
  }, [
74295
74596
  captureOutgoingTab,
74597
+ captureTabSnapshot,
74296
74598
  cleanupFrozenTabById,
74297
74599
  finalizeIncomingTab,
74298
74600
  prepareIncomingTab