@salt-ds/lab 1.0.0-alpha.87 → 1.0.0-alpha.89

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 (177) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/css/salt-lab.css +64 -45
  3. package/dist-cjs/calendar/internal/CalendarDay.css.js +1 -1
  4. package/dist-cjs/contact-details/ContactDetails.css.js +1 -1
  5. package/dist-cjs/list-deprecated/ListStateContext.js +1 -1
  6. package/dist-cjs/list-deprecated/ListStateContext.js.map +1 -1
  7. package/dist-cjs/tabs-next/TabBar.css.js +1 -1
  8. package/dist-cjs/tabs-next/TabBar.js +1 -1
  9. package/dist-cjs/tabs-next/TabBar.js.map +1 -1
  10. package/dist-cjs/tabs-next/TabListLayoutContext.js +13 -0
  11. package/dist-cjs/tabs-next/TabListLayoutContext.js.map +1 -0
  12. package/dist-cjs/tabs-next/TabListNext.css.js +1 -1
  13. package/dist-cjs/tabs-next/TabListNext.js +179 -33
  14. package/dist-cjs/tabs-next/TabListNext.js.map +1 -1
  15. package/dist-cjs/tabs-next/TabNext.js +111 -7
  16. package/dist-cjs/tabs-next/TabNext.js.map +1 -1
  17. package/dist-cjs/tabs-next/TabNextAction.js +25 -2
  18. package/dist-cjs/tabs-next/TabNextAction.js.map +1 -1
  19. package/dist-cjs/tabs-next/TabNextPanel.js +31 -16
  20. package/dist-cjs/tabs-next/TabNextPanel.js.map +1 -1
  21. package/dist-cjs/tabs-next/TabNextTrigger.js +110 -9
  22. package/dist-cjs/tabs-next/TabNextTrigger.js.map +1 -1
  23. package/dist-cjs/tabs-next/TabOverflowList.css.js +1 -1
  24. package/dist-cjs/tabs-next/TabOverflowList.js +168 -64
  25. package/dist-cjs/tabs-next/TabOverflowList.js.map +1 -1
  26. package/dist-cjs/tabs-next/TabSlot.js +30 -0
  27. package/dist-cjs/tabs-next/TabSlot.js.map +1 -0
  28. package/dist-cjs/tabs-next/TabSlotRegistryContext.js +16 -0
  29. package/dist-cjs/tabs-next/TabSlotRegistryContext.js.map +1 -0
  30. package/dist-cjs/tabs-next/TabsNext.css.js +6 -0
  31. package/dist-cjs/tabs-next/TabsNext.css.js.map +1 -0
  32. package/dist-cjs/tabs-next/TabsNext.js +113 -47
  33. package/dist-cjs/tabs-next/TabsNext.js.map +1 -1
  34. package/dist-cjs/tabs-next/TabsNextContext.js +17 -3
  35. package/dist-cjs/tabs-next/TabsNextContext.js.map +1 -1
  36. package/dist-cjs/tabs-next/domUtils.js +13 -0
  37. package/dist-cjs/tabs-next/domUtils.js.map +1 -0
  38. package/dist-cjs/tabs-next/hooks/overflowMath.js +86 -0
  39. package/dist-cjs/tabs-next/hooks/overflowMath.js.map +1 -0
  40. package/dist-cjs/tabs-next/hooks/useCollection.js +147 -41
  41. package/dist-cjs/tabs-next/hooks/useCollection.js.map +1 -1
  42. package/dist-cjs/tabs-next/hooks/useFocusWithRetry.js +64 -0
  43. package/dist-cjs/tabs-next/hooks/useFocusWithRetry.js.map +1 -0
  44. package/dist-cjs/tabs-next/hooks/useOverflow.js +240 -156
  45. package/dist-cjs/tabs-next/hooks/useOverflow.js.map +1 -1
  46. package/dist-cjs/tabs-next/hooks/useOverflowLayoutState.js +99 -0
  47. package/dist-cjs/tabs-next/hooks/useOverflowLayoutState.js.map +1 -0
  48. package/dist-cjs/tabs-next/hooks/useOverflowSelectionState.js +60 -0
  49. package/dist-cjs/tabs-next/hooks/useOverflowSelectionState.js.map +1 -0
  50. package/dist-cjs/tabs-next/hooks/useRenderedTabWidth.js +92 -0
  51. package/dist-cjs/tabs-next/hooks/useRenderedTabWidth.js.map +1 -0
  52. package/dist-cjs/tabs-next/hooks/useRenderedTabsRegistry.js +200 -0
  53. package/dist-cjs/tabs-next/hooks/useRenderedTabsRegistry.js.map +1 -0
  54. package/dist-cjs/tabs-next/hooks/useTabListRecovery.js +76 -0
  55. package/dist-cjs/tabs-next/hooks/useTabListRecovery.js.map +1 -0
  56. package/dist-cjs/tabs-next/hooks/useTabRemovalHandler.js +165 -0
  57. package/dist-cjs/tabs-next/hooks/useTabRemovalHandler.js.map +1 -0
  58. package/dist-cjs/tabs-next/hooks/useTabSelectionFocus.js +80 -0
  59. package/dist-cjs/tabs-next/hooks/useTabSelectionFocus.js.map +1 -0
  60. package/dist-cjs/tabs-next/widthMeasurement.js +42 -0
  61. package/dist-cjs/tabs-next/widthMeasurement.js.map +1 -0
  62. package/dist-cjs/tree/Tree.css.js +1 -1
  63. package/dist-cjs/tree/TreeNode.css.js +1 -1
  64. package/dist-cjs/tree/TreeNode.js +1 -1
  65. package/dist-cjs/tree/TreeNode.js.map +1 -1
  66. package/dist-cjs/tree/TreeNodeExpansionIcon.css.js +1 -1
  67. package/dist-cjs/tree/TreeNodeTrigger.css.js +1 -1
  68. package/dist-cjs/tree/TreeNodeTrigger.js +2 -2
  69. package/dist-cjs/tree/TreeNodeTrigger.js.map +1 -1
  70. package/dist-cjs/utils/useEventCallback.js +5 -5
  71. package/dist-cjs/utils/useEventCallback.js.map +1 -1
  72. package/dist-es/calendar/internal/CalendarDay.css.js +1 -1
  73. package/dist-es/contact-details/ContactDetails.css.js +1 -1
  74. package/dist-es/list-deprecated/ListStateContext.js +1 -1
  75. package/dist-es/list-deprecated/ListStateContext.js.map +1 -1
  76. package/dist-es/tabs-next/TabBar.css.js +1 -1
  77. package/dist-es/tabs-next/TabBar.js +1 -1
  78. package/dist-es/tabs-next/TabBar.js.map +1 -1
  79. package/dist-es/tabs-next/TabListLayoutContext.js +10 -0
  80. package/dist-es/tabs-next/TabListLayoutContext.js.map +1 -0
  81. package/dist-es/tabs-next/TabListNext.css.js +1 -1
  82. package/dist-es/tabs-next/TabListNext.js +182 -36
  83. package/dist-es/tabs-next/TabListNext.js.map +1 -1
  84. package/dist-es/tabs-next/TabNext.js +113 -9
  85. package/dist-es/tabs-next/TabNext.js.map +1 -1
  86. package/dist-es/tabs-next/TabNextAction.js +25 -2
  87. package/dist-es/tabs-next/TabNextAction.js.map +1 -1
  88. package/dist-es/tabs-next/TabNextPanel.js +31 -16
  89. package/dist-es/tabs-next/TabNextPanel.js.map +1 -1
  90. package/dist-es/tabs-next/TabNextTrigger.js +110 -9
  91. package/dist-es/tabs-next/TabNextTrigger.js.map +1 -1
  92. package/dist-es/tabs-next/TabOverflowList.css.js +1 -1
  93. package/dist-es/tabs-next/TabOverflowList.js +172 -68
  94. package/dist-es/tabs-next/TabOverflowList.js.map +1 -1
  95. package/dist-es/tabs-next/TabSlot.js +28 -0
  96. package/dist-es/tabs-next/TabSlot.js.map +1 -0
  97. package/dist-es/tabs-next/TabSlotRegistryContext.js +13 -0
  98. package/dist-es/tabs-next/TabSlotRegistryContext.js.map +1 -0
  99. package/dist-es/tabs-next/TabsNext.css.js +4 -0
  100. package/dist-es/tabs-next/TabsNext.css.js.map +1 -0
  101. package/dist-es/tabs-next/TabsNext.js +114 -48
  102. package/dist-es/tabs-next/TabsNext.js.map +1 -1
  103. package/dist-es/tabs-next/TabsNextContext.js +17 -3
  104. package/dist-es/tabs-next/TabsNextContext.js.map +1 -1
  105. package/dist-es/tabs-next/domUtils.js +11 -0
  106. package/dist-es/tabs-next/domUtils.js.map +1 -0
  107. package/dist-es/tabs-next/hooks/overflowMath.js +82 -0
  108. package/dist-es/tabs-next/hooks/overflowMath.js.map +1 -0
  109. package/dist-es/tabs-next/hooks/useCollection.js +148 -42
  110. package/dist-es/tabs-next/hooks/useCollection.js.map +1 -1
  111. package/dist-es/tabs-next/hooks/useFocusWithRetry.js +62 -0
  112. package/dist-es/tabs-next/hooks/useFocusWithRetry.js.map +1 -0
  113. package/dist-es/tabs-next/hooks/useOverflow.js +242 -158
  114. package/dist-es/tabs-next/hooks/useOverflow.js.map +1 -1
  115. package/dist-es/tabs-next/hooks/useOverflowLayoutState.js +97 -0
  116. package/dist-es/tabs-next/hooks/useOverflowLayoutState.js.map +1 -0
  117. package/dist-es/tabs-next/hooks/useOverflowSelectionState.js +58 -0
  118. package/dist-es/tabs-next/hooks/useOverflowSelectionState.js.map +1 -0
  119. package/dist-es/tabs-next/hooks/useRenderedTabWidth.js +90 -0
  120. package/dist-es/tabs-next/hooks/useRenderedTabWidth.js.map +1 -0
  121. package/dist-es/tabs-next/hooks/useRenderedTabsRegistry.js +198 -0
  122. package/dist-es/tabs-next/hooks/useRenderedTabsRegistry.js.map +1 -0
  123. package/dist-es/tabs-next/hooks/useTabListRecovery.js +74 -0
  124. package/dist-es/tabs-next/hooks/useTabListRecovery.js.map +1 -0
  125. package/dist-es/tabs-next/hooks/useTabRemovalHandler.js +163 -0
  126. package/dist-es/tabs-next/hooks/useTabRemovalHandler.js.map +1 -0
  127. package/dist-es/tabs-next/hooks/useTabSelectionFocus.js +78 -0
  128. package/dist-es/tabs-next/hooks/useTabSelectionFocus.js.map +1 -0
  129. package/dist-es/tabs-next/widthMeasurement.js +36 -0
  130. package/dist-es/tabs-next/widthMeasurement.js.map +1 -0
  131. package/dist-es/tree/Tree.css.js +1 -1
  132. package/dist-es/tree/TreeNode.css.js +1 -1
  133. package/dist-es/tree/TreeNode.js +1 -1
  134. package/dist-es/tree/TreeNode.js.map +1 -1
  135. package/dist-es/tree/TreeNodeExpansionIcon.css.js +1 -1
  136. package/dist-es/tree/TreeNodeTrigger.css.js +1 -1
  137. package/dist-es/tree/TreeNodeTrigger.js +2 -2
  138. package/dist-es/tree/TreeNodeTrigger.js.map +1 -1
  139. package/dist-es/utils/useEventCallback.js +5 -5
  140. package/dist-es/utils/useEventCallback.js.map +1 -1
  141. package/dist-types/cascading-menu/internal/useMenuTriggerHandlers.d.ts +1 -1
  142. package/dist-types/list-deprecated/ListStateContext.d.ts +7 -2
  143. package/dist-types/tabs-next/TabListLayoutContext.d.ts +9 -0
  144. package/dist-types/tabs-next/TabNext.d.ts +1 -1
  145. package/dist-types/tabs-next/TabNextPanel.d.ts +2 -1
  146. package/dist-types/tabs-next/TabOverflowList.d.ts +3 -4
  147. package/dist-types/tabs-next/TabSlot.d.ts +6 -0
  148. package/dist-types/tabs-next/TabSlotRegistryContext.d.ts +5 -0
  149. package/dist-types/tabs-next/TabsNext.d.ts +2 -1
  150. package/dist-types/tabs-next/TabsNextContext.d.ts +26 -4
  151. package/dist-types/tabs-next/domUtils.d.ts +1 -0
  152. package/dist-types/tabs-next/hooks/overflowMath.d.ts +18 -0
  153. package/dist-types/tabs-next/hooks/useCollection.d.ts +15 -3
  154. package/dist-types/tabs-next/hooks/useFocusWithRetry.d.ts +9 -0
  155. package/dist-types/tabs-next/hooks/useOverflow.d.ts +5 -5
  156. package/dist-types/tabs-next/hooks/useOverflowLayoutState.d.ts +13 -0
  157. package/dist-types/tabs-next/hooks/useOverflowSelectionState.d.ts +13 -0
  158. package/dist-types/tabs-next/hooks/useRenderedTabWidth.d.ts +12 -0
  159. package/dist-types/tabs-next/hooks/useRenderedTabsRegistry.d.ts +12 -0
  160. package/dist-types/tabs-next/hooks/useTabListRecovery.d.ts +12 -0
  161. package/dist-types/tabs-next/hooks/useTabRemovalHandler.d.ts +32 -0
  162. package/dist-types/tabs-next/hooks/useTabSelectionFocus.d.ts +15 -0
  163. package/dist-types/tabs-next/widthMeasurement.d.ts +5 -0
  164. package/dist-types/tokenized-input/internal/InputPill.d.ts +1 -1
  165. package/dist-types/tokenized-input-next/internal/InputPill.d.ts +1 -1
  166. package/dist-types/utils/useEventCallback.d.ts +1 -1
  167. package/package.json +3 -3
  168. package/dist-cjs/tabs-next/hooks/useFocusOutside.js +0 -25
  169. package/dist-cjs/tabs-next/hooks/useFocusOutside.js.map +0 -1
  170. package/dist-cjs/tabs-next/hooks/useRestoreActiveTab.js +0 -93
  171. package/dist-cjs/tabs-next/hooks/useRestoreActiveTab.js.map +0 -1
  172. package/dist-es/tabs-next/hooks/useFocusOutside.js +0 -23
  173. package/dist-es/tabs-next/hooks/useFocusOutside.js.map +0 -1
  174. package/dist-es/tabs-next/hooks/useRestoreActiveTab.js +0 -91
  175. package/dist-es/tabs-next/hooks/useRestoreActiveTab.js.map +0 -1
  176. package/dist-types/tabs-next/hooks/useFocusOutside.d.ts +0 -2
  177. package/dist-types/tabs-next/hooks/useRestoreActiveTab.d.ts +0 -10
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useOverflowSelectionState.js","sources":["../src/tabs-next/hooks/useOverflowSelectionState.ts"],"sourcesContent":["import { useIsomorphicLayoutEffect, usePrevious } from \"@salt-ds/core\";\nimport {\n type Dispatch,\n type MutableRefObject,\n type SetStateAction,\n type SyntheticEvent,\n useCallback,\n useEffect,\n useRef,\n} from \"react\";\n\ninterface PendingOverflowSelection {\n event: SyntheticEvent | null;\n value: string;\n}\n\ninterface UseOverflowSelectionStateArgs {\n commitSelection: (event: SyntheticEvent | null, value: string) => void;\n menuOpen: boolean;\n selected?: string;\n setMenuOpen: Dispatch<SetStateAction<boolean>>;\n}\n\ninterface UseOverflowSelectionStateResult {\n selectionFromOverflowValueRef: MutableRefObject<string | null>;\n setSelected: (\n event: SyntheticEvent | null,\n value: string,\n source?: \"main\" | \"overflow\",\n ) => void;\n}\n\nexport function useOverflowSelectionState({\n commitSelection,\n menuOpen,\n selected,\n setMenuOpen,\n}: UseOverflowSelectionStateArgs): UseOverflowSelectionStateResult {\n const previousSelected = usePrevious(selected, [selected]);\n const selectionFromOverflowValueRef = useRef<string | null>(null);\n const pendingOverflowSelectionRef = useRef<PendingOverflowSelection | null>(\n null,\n );\n\n const setSelected = useCallback(\n (\n event: SyntheticEvent | null,\n value: string,\n source: \"main\" | \"overflow\" = \"main\",\n ) => {\n const selectedFromOverflow = source === \"overflow\";\n selectionFromOverflowValueRef.current = selectedFromOverflow\n ? value\n : null;\n\n if (selectedFromOverflow) {\n pendingOverflowSelectionRef.current = { event, value };\n setMenuOpen(false);\n return;\n }\n\n pendingOverflowSelectionRef.current = null;\n setMenuOpen(false);\n commitSelection(event, value);\n },\n [commitSelection, setMenuOpen],\n );\n\n useIsomorphicLayoutEffect(() => {\n if (menuOpen) {\n return;\n }\n\n const pendingSelection = pendingOverflowSelectionRef.current;\n if (!pendingSelection) {\n return;\n }\n\n pendingOverflowSelectionRef.current = null;\n commitSelection(pendingSelection.event, pendingSelection.value);\n }, [commitSelection, menuOpen]);\n\n useEffect(() => {\n const selectedFromOverflow = selectionFromOverflowValueRef.current;\n if (selectedFromOverflow == null || pendingOverflowSelectionRef.current) {\n return;\n }\n\n if (selected === selectedFromOverflow && selected !== previousSelected) {\n return;\n }\n\n selectionFromOverflowValueRef.current = null;\n }, [previousSelected, selected]);\n\n return {\n selectionFromOverflowValueRef,\n setSelected,\n };\n}\n"],"names":[],"mappings":";;;AAgCO,SAAS,yBAAA,CAA0B;AAAA,EACxC,eAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,EAAmE;AACjE,EAAA,MAAM,gBAAA,GAAmB,WAAA,CAAY,QAAA,EAAU,CAAC,QAAQ,CAAC,CAAA;AACzD,EAAA,MAAM,6BAAA,GAAgC,OAAsB,IAAI,CAAA;AAChE,EAAA,MAAM,2BAAA,GAA8B,MAAA;AAAA,IAClC;AAAA,GACF;AAEA,EAAA,MAAM,WAAA,GAAc,WAAA;AAAA,IAClB,CACE,KAAA,EACA,KAAA,EACA,MAAA,GAA8B,MAAA,KAC3B;AACH,MAAA,MAAM,uBAAuB,MAAA,KAAW,UAAA;AACxC,MAAA,6BAAA,CAA8B,OAAA,GAAU,uBACpC,KAAA,GACA,IAAA;AAEJ,MAAA,IAAI,oBAAA,EAAsB;AACxB,QAAA,2BAAA,CAA4B,OAAA,GAAU,EAAE,KAAA,EAAO,KAAA,EAAM;AACrD,QAAA,WAAA,CAAY,KAAK,CAAA;AACjB,QAAA;AAAA,MACF;AAEA,MAAA,2BAAA,CAA4B,OAAA,GAAU,IAAA;AACtC,MAAA,WAAA,CAAY,KAAK,CAAA;AACjB,MAAA,eAAA,CAAgB,OAAO,KAAK,CAAA;AAAA,IAC9B,CAAA;AAAA,IACA,CAAC,iBAAiB,WAAW;AAAA,GAC/B;AAEA,EAAA,yBAAA,CAA0B,MAAM;AAC9B,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,mBAAmB,2BAAA,CAA4B,OAAA;AACrD,IAAA,IAAI,CAAC,gBAAA,EAAkB;AACrB,MAAA;AAAA,IACF;AAEA,IAAA,2BAAA,CAA4B,OAAA,GAAU,IAAA;AACtC,IAAA,eAAA,CAAgB,gBAAA,CAAiB,KAAA,EAAO,gBAAA,CAAiB,KAAK,CAAA;AAAA,EAChE,CAAA,EAAG,CAAC,eAAA,EAAiB,QAAQ,CAAC,CAAA;AAE9B,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,uBAAuB,6BAAA,CAA8B,OAAA;AAC3D,IAAA,IAAI,oBAAA,IAAwB,IAAA,IAAQ,2BAAA,CAA4B,OAAA,EAAS;AACvE,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,QAAA,KAAa,oBAAA,IAAwB,QAAA,KAAa,gBAAA,EAAkB;AACtE,MAAA;AAAA,IACF;AAEA,IAAA,6BAAA,CAA8B,OAAA,GAAU,IAAA;AAAA,EAC1C,CAAA,EAAG,CAAC,gBAAA,EAAkB,QAAQ,CAAC,CAAA;AAE/B,EAAA,OAAO;AAAA,IACL,6BAAA;AAAA,IACA;AAAA,GACF;AACF;;;;"}
@@ -0,0 +1,90 @@
1
+ import { useEffect } from 'react';
2
+ import { getIntrinsicMeasuredWidth } from '../widthMeasurement.js';
3
+
4
+ const MIN_TRUSTED_RENDERED_TAB_WIDTH = 0.5;
5
+ function isSecondaryMeasurementContext(element) {
6
+ return element.closest(".saltTabOverflow-list") || element.closest(".saltTabListNext-measureContainer");
7
+ }
8
+ function useRenderedTabWidth({
9
+ hostElement,
10
+ renderMode,
11
+ tabRootRef,
12
+ targetWindow,
13
+ updateRenderedTab,
14
+ value
15
+ }) {
16
+ useEffect(() => {
17
+ if (!hostElement) {
18
+ return;
19
+ }
20
+ const element = tabRootRef.current;
21
+ const resizeObserverCtor = targetWindow == null ? void 0 : targetWindow.ResizeObserver;
22
+ const mutationObserverCtor = targetWindow == null ? void 0 : targetWindow.MutationObserver;
23
+ if (!element || !resizeObserverCtor) {
24
+ return;
25
+ }
26
+ const updateWidth = (allowSecondaryMeasurementContext = false) => {
27
+ if (!element.isConnected) {
28
+ return;
29
+ }
30
+ if (!allowSecondaryMeasurementContext && isSecondaryMeasurementContext(element)) {
31
+ return;
32
+ }
33
+ const width = getIntrinsicMeasuredWidth(element);
34
+ if (width <= MIN_TRUSTED_RENDERED_TAB_WIDTH) {
35
+ return;
36
+ }
37
+ updateRenderedTab(value, {
38
+ width
39
+ });
40
+ };
41
+ let animationFrameId = null;
42
+ const scheduleWidthUpdate = (allowSecondaryMeasurementContext = false) => {
43
+ if (!(targetWindow == null ? void 0 : targetWindow.requestAnimationFrame)) {
44
+ updateWidth(allowSecondaryMeasurementContext);
45
+ return;
46
+ }
47
+ if (animationFrameId != null) {
48
+ targetWindow.cancelAnimationFrame(animationFrameId);
49
+ }
50
+ animationFrameId = targetWindow.requestAnimationFrame(() => {
51
+ animationFrameId = null;
52
+ updateWidth(allowSecondaryMeasurementContext);
53
+ });
54
+ };
55
+ if (renderMode === "portal") {
56
+ scheduleWidthUpdate(true);
57
+ } else {
58
+ updateWidth(true);
59
+ }
60
+ const resizeObserver = new resizeObserverCtor(() => {
61
+ updateWidth();
62
+ });
63
+ resizeObserver.observe(element);
64
+ const mutationObserver = mutationObserverCtor ? new mutationObserverCtor(() => {
65
+ scheduleWidthUpdate();
66
+ }) : null;
67
+ mutationObserver == null ? void 0 : mutationObserver.observe(element, {
68
+ childList: true,
69
+ characterData: true,
70
+ subtree: true
71
+ });
72
+ return () => {
73
+ if (animationFrameId != null && targetWindow) {
74
+ targetWindow.cancelAnimationFrame(animationFrameId);
75
+ }
76
+ mutationObserver == null ? void 0 : mutationObserver.disconnect();
77
+ resizeObserver.disconnect();
78
+ };
79
+ }, [
80
+ hostElement,
81
+ renderMode,
82
+ tabRootRef,
83
+ targetWindow,
84
+ updateRenderedTab,
85
+ value
86
+ ]);
87
+ }
88
+
89
+ export { useRenderedTabWidth };
90
+ //# sourceMappingURL=useRenderedTabWidth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useRenderedTabWidth.js","sources":["../src/tabs-next/hooks/useRenderedTabWidth.ts"],"sourcesContent":["import { type RefObject, useEffect } from \"react\";\nimport type {\n TabsNextContextValue,\n TabsNextRenderMode,\n} from \"../TabsNextContext\";\nimport { getIntrinsicMeasuredWidth } from \"../widthMeasurement\";\n\nconst MIN_TRUSTED_RENDERED_TAB_WIDTH = 0.5;\n\ninterface UseRenderedTabWidthProps {\n hostElement: HTMLDivElement | null;\n renderMode: TabsNextRenderMode;\n tabRootRef: RefObject<HTMLDivElement>;\n targetWindow: Window | null | undefined;\n updateRenderedTab: TabsNextContextValue[\"updateRenderedTab\"];\n value: string;\n}\n\nfunction isSecondaryMeasurementContext(element: HTMLElement) {\n return (\n element.closest(\".saltTabOverflow-list\") ||\n element.closest(\".saltTabListNext-measureContainer\")\n );\n}\n\nexport function useRenderedTabWidth({\n hostElement,\n renderMode,\n tabRootRef,\n targetWindow,\n updateRenderedTab,\n value,\n}: UseRenderedTabWidthProps) {\n useEffect(() => {\n if (!hostElement) {\n return;\n }\n\n const element = tabRootRef.current;\n const resizeObserverCtor = (\n targetWindow as\n | (Window & { ResizeObserver?: typeof ResizeObserver })\n | undefined\n )?.ResizeObserver;\n const mutationObserverCtor = (\n targetWindow as\n | (Window & { MutationObserver?: typeof MutationObserver })\n | undefined\n )?.MutationObserver;\n if (!element || !resizeObserverCtor) {\n return;\n }\n\n const updateWidth = (allowSecondaryMeasurementContext = false) => {\n if (!element.isConnected) {\n return;\n }\n\n // Preserve the strip width while a tab is rendered in the overflow menu.\n // Overflow items stretch to the menu width, and hidden measurement tabs\n // can collapse to a different intrinsic size. Neither width is suitable\n // for deciding whether the tab fits back in the main strip once the tab\n // is already established. A one-time seeded width is still useful for\n // newly mounted tabs before they have ever appeared in the main strip.\n if (\n !allowSecondaryMeasurementContext &&\n isSecondaryMeasurementContext(element)\n ) {\n return;\n }\n\n const width = getIntrinsicMeasuredWidth(element);\n if (width <= MIN_TRUSTED_RENDERED_TAB_WIDTH) {\n return;\n }\n\n updateRenderedTab(value, {\n width,\n });\n };\n\n let animationFrameId: number | null = null;\n const scheduleWidthUpdate = (allowSecondaryMeasurementContext = false) => {\n if (!targetWindow?.requestAnimationFrame) {\n updateWidth(allowSecondaryMeasurementContext);\n return;\n }\n\n if (animationFrameId != null) {\n targetWindow.cancelAnimationFrame(animationFrameId);\n }\n\n animationFrameId = targetWindow.requestAnimationFrame(() => {\n animationFrameId = null;\n updateWidth(allowSecondaryMeasurementContext);\n });\n };\n\n if (renderMode === \"portal\") {\n scheduleWidthUpdate(true);\n } else {\n updateWidth(true);\n }\n\n const resizeObserver = new resizeObserverCtor(() => {\n updateWidth();\n });\n\n resizeObserver.observe(element);\n const mutationObserver = mutationObserverCtor\n ? new mutationObserverCtor(() => {\n scheduleWidthUpdate();\n })\n : null;\n\n mutationObserver?.observe(element, {\n childList: true,\n characterData: true,\n subtree: true,\n });\n\n return () => {\n if (animationFrameId != null && targetWindow) {\n targetWindow.cancelAnimationFrame(animationFrameId);\n }\n mutationObserver?.disconnect();\n resizeObserver.disconnect();\n };\n }, [\n hostElement,\n renderMode,\n tabRootRef,\n targetWindow,\n updateRenderedTab,\n value,\n ]);\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,198 @@
1
+ import { useIsomorphicLayoutEffect } from '@salt-ds/core';
2
+ import { useState, useCallback, useMemo } from 'react';
3
+ import { getMeasuredWidth } from '../widthMeasurement.js';
4
+
5
+ function sortRenderedTabs(tabs) {
6
+ return [...tabs].sort((tabA, tabB) => {
7
+ if (tabA.marker === tabB.marker) {
8
+ return 0;
9
+ }
10
+ if (!tabA.marker || !tabB.marker) {
11
+ return 0;
12
+ }
13
+ const position = tabA.marker.compareDocumentPosition(tabB.marker);
14
+ if (position & Node.DOCUMENT_POSITION_FOLLOWING) {
15
+ return -1;
16
+ }
17
+ if (position & Node.DOCUMENT_POSITION_PRECEDING) {
18
+ return 1;
19
+ }
20
+ return 0;
21
+ });
22
+ }
23
+ function useRenderedTabsRegistry() {
24
+ const [renderedTabMap, setRenderedTabMap] = useState(
25
+ () => /* @__PURE__ */ new Map()
26
+ );
27
+ const [renderMode, setRenderMode] = useState("inline");
28
+ const [bootstrapTabs, setBootstrapTabs] = useState(() => /* @__PURE__ */ new Set());
29
+ const [readyBootstrapTabs, setReadyBootstrapTabs] = useState(
30
+ () => /* @__PURE__ */ new Set()
31
+ );
32
+ const [bootstrapOverflowReady, setBootstrapOverflowReadyState] = useState(false);
33
+ const registerBootstrapTab = useCallback((tabValue) => {
34
+ setBootstrapTabs((currentTabs) => {
35
+ if (currentTabs.has(tabValue)) {
36
+ return currentTabs;
37
+ }
38
+ const nextTabs = new Set(currentTabs);
39
+ nextTabs.add(tabValue);
40
+ return nextTabs;
41
+ });
42
+ return () => {
43
+ setBootstrapTabs((currentTabs) => {
44
+ if (!currentTabs.has(tabValue)) {
45
+ return currentTabs;
46
+ }
47
+ const nextTabs = new Set(currentTabs);
48
+ nextTabs.delete(tabValue);
49
+ return nextTabs;
50
+ });
51
+ setReadyBootstrapTabs((currentTabs) => {
52
+ if (!currentTabs.has(tabValue)) {
53
+ return currentTabs;
54
+ }
55
+ const nextTabs = new Set(currentTabs);
56
+ nextTabs.delete(tabValue);
57
+ return nextTabs;
58
+ });
59
+ };
60
+ }, []);
61
+ const setBootstrapTabReady = useCallback(
62
+ (tabValue, ready) => {
63
+ setReadyBootstrapTabs((currentTabs) => {
64
+ const hasTab = currentTabs.has(tabValue);
65
+ if (ready === hasTab) {
66
+ return currentTabs;
67
+ }
68
+ const nextTabs = new Set(currentTabs);
69
+ if (ready) {
70
+ nextTabs.add(tabValue);
71
+ } else {
72
+ nextTabs.delete(tabValue);
73
+ }
74
+ return nextTabs;
75
+ });
76
+ },
77
+ []
78
+ );
79
+ const setBootstrapOverflowReady = useCallback((ready) => {
80
+ setBootstrapOverflowReadyState((currentReady) => {
81
+ if (currentReady === ready) {
82
+ return currentReady;
83
+ }
84
+ return ready;
85
+ });
86
+ }, []);
87
+ useIsomorphicLayoutEffect(() => {
88
+ if (renderMode === "portal" || bootstrapTabs.size < 1) {
89
+ return;
90
+ }
91
+ if (!bootstrapOverflowReady) {
92
+ return;
93
+ }
94
+ for (const tabValue of bootstrapTabs) {
95
+ if (!readyBootstrapTabs.has(tabValue)) {
96
+ return;
97
+ }
98
+ const renderedTab = renderedTabMap.get(tabValue);
99
+ if (!renderedTab || getMeasuredWidth(renderedTab.root) <= 0) {
100
+ return;
101
+ }
102
+ }
103
+ setRenderMode("portal");
104
+ }, [
105
+ bootstrapOverflowReady,
106
+ bootstrapTabs,
107
+ readyBootstrapTabs,
108
+ renderMode,
109
+ renderedTabMap
110
+ ]);
111
+ const registerRenderedTab = useCallback((tab) => {
112
+ setRenderedTabMap((map) => {
113
+ const existing = map.get(tab.value);
114
+ if (process.env.NODE_ENV !== "production" && existing && existing.id !== tab.id) {
115
+ console.warn(
116
+ `TabsNext received duplicate tab value "${tab.value}". Tab values must be unique within a TabsNext instance.`
117
+ );
118
+ }
119
+ if (existing === tab) {
120
+ return map;
121
+ }
122
+ const next = new Map(map);
123
+ next.set(tab.value, tab);
124
+ return next;
125
+ });
126
+ return () => {
127
+ setRenderedTabMap((map) => {
128
+ const existing = map.get(tab.value);
129
+ if (!existing || existing.id !== tab.id) {
130
+ return map;
131
+ }
132
+ const next = new Map(map);
133
+ next.delete(tab.value);
134
+ return next;
135
+ });
136
+ };
137
+ }, []);
138
+ const updateRenderedTab = useCallback(
139
+ (value, updates) => {
140
+ setRenderedTabMap((map) => {
141
+ const existing = map.get(value);
142
+ if (!existing) {
143
+ return map;
144
+ }
145
+ let changed = false;
146
+ const nextRecord = { ...existing };
147
+ for (const [key, nextValue] of Object.entries(updates)) {
148
+ const typedKey = key;
149
+ if (nextRecord[typedKey] !== nextValue) {
150
+ changed = true;
151
+ nextRecord[typedKey] = nextValue;
152
+ }
153
+ }
154
+ if (!changed) {
155
+ return map;
156
+ }
157
+ const next = new Map(map);
158
+ next.set(value, nextRecord);
159
+ return next;
160
+ });
161
+ },
162
+ []
163
+ );
164
+ const getRenderedTab = useCallback(
165
+ (value) => {
166
+ return renderedTabMap.get(value);
167
+ },
168
+ [renderedTabMap]
169
+ );
170
+ const renderedTabs = useMemo(() => {
171
+ return sortRenderedTabs(Array.from(renderedTabMap.values()));
172
+ }, [renderedTabMap]);
173
+ const renderedTabOrderMap = useMemo(() => {
174
+ return new Map(
175
+ renderedTabs.map((tab, index) => [tab.value, index])
176
+ );
177
+ }, [renderedTabs]);
178
+ const getRenderedTabOrder = useCallback(
179
+ (value) => {
180
+ return renderedTabOrderMap.get(value) ?? -1;
181
+ },
182
+ [renderedTabOrderMap]
183
+ );
184
+ return {
185
+ renderMode,
186
+ registerBootstrapTab,
187
+ setBootstrapTabReady,
188
+ setBootstrapOverflowReady,
189
+ registerRenderedTab,
190
+ updateRenderedTab,
191
+ getRenderedTab,
192
+ getRenderedTabOrder,
193
+ renderedTabs
194
+ };
195
+ }
196
+
197
+ export { useRenderedTabsRegistry };
198
+ //# sourceMappingURL=useRenderedTabsRegistry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useRenderedTabsRegistry.js","sources":["../src/tabs-next/hooks/useRenderedTabsRegistry.ts"],"sourcesContent":["import { useIsomorphicLayoutEffect } from \"@salt-ds/core\";\nimport { useCallback, useMemo, useState } from \"react\";\nimport type { RenderedTab, TabsNextRenderMode } from \"../TabsNextContext\";\nimport { getMeasuredWidth } from \"../widthMeasurement\";\n\nfunction sortRenderedTabs(tabs: RenderedTab[]) {\n return [...tabs].sort((tabA, tabB) => {\n if (tabA.marker === tabB.marker) {\n return 0;\n }\n if (!tabA.marker || !tabB.marker) {\n return 0;\n }\n\n const position = tabA.marker.compareDocumentPosition(tabB.marker);\n if (position & Node.DOCUMENT_POSITION_FOLLOWING) {\n return -1;\n }\n if (position & Node.DOCUMENT_POSITION_PRECEDING) {\n return 1;\n }\n return 0;\n });\n}\n\nexport function useRenderedTabsRegistry() {\n const [renderedTabMap, setRenderedTabMap] = useState(\n () => new Map<string, RenderedTab>(),\n );\n const [renderMode, setRenderMode] = useState<TabsNextRenderMode>(\"inline\");\n const [bootstrapTabs, setBootstrapTabs] = useState(() => new Set<string>());\n const [readyBootstrapTabs, setReadyBootstrapTabs] = useState(\n () => new Set<string>(),\n );\n const [bootstrapOverflowReady, setBootstrapOverflowReadyState] =\n useState(false);\n\n const registerBootstrapTab = useCallback((tabValue: string) => {\n setBootstrapTabs((currentTabs) => {\n if (currentTabs.has(tabValue)) {\n return currentTabs;\n }\n\n const nextTabs = new Set(currentTabs);\n nextTabs.add(tabValue);\n return nextTabs;\n });\n\n return () => {\n setBootstrapTabs((currentTabs) => {\n if (!currentTabs.has(tabValue)) {\n return currentTabs;\n }\n\n const nextTabs = new Set(currentTabs);\n nextTabs.delete(tabValue);\n return nextTabs;\n });\n setReadyBootstrapTabs((currentTabs) => {\n if (!currentTabs.has(tabValue)) {\n return currentTabs;\n }\n\n const nextTabs = new Set(currentTabs);\n nextTabs.delete(tabValue);\n return nextTabs;\n });\n };\n }, []);\n\n const setBootstrapTabReady = useCallback(\n (tabValue: string, ready: boolean) => {\n setReadyBootstrapTabs((currentTabs) => {\n const hasTab = currentTabs.has(tabValue);\n if (ready === hasTab) {\n return currentTabs;\n }\n\n const nextTabs = new Set(currentTabs);\n if (ready) {\n nextTabs.add(tabValue);\n } else {\n nextTabs.delete(tabValue);\n }\n return nextTabs;\n });\n },\n [],\n );\n\n const setBootstrapOverflowReady = useCallback((ready: boolean) => {\n setBootstrapOverflowReadyState((currentReady) => {\n if (currentReady === ready) {\n return currentReady;\n }\n\n return ready;\n });\n }, []);\n\n useIsomorphicLayoutEffect(() => {\n if (renderMode === \"portal\" || bootstrapTabs.size < 1) {\n return;\n }\n\n if (!bootstrapOverflowReady) {\n return;\n }\n\n for (const tabValue of bootstrapTabs) {\n if (!readyBootstrapTabs.has(tabValue)) {\n return;\n }\n\n const renderedTab = renderedTabMap.get(tabValue);\n if (!renderedTab || getMeasuredWidth(renderedTab.root) <= 0) {\n return;\n }\n }\n\n setRenderMode(\"portal\");\n }, [\n bootstrapOverflowReady,\n bootstrapTabs,\n readyBootstrapTabs,\n renderMode,\n renderedTabMap,\n ]);\n\n const registerRenderedTab = useCallback((tab: RenderedTab) => {\n setRenderedTabMap((map) => {\n const existing = map.get(tab.value);\n if (\n process.env.NODE_ENV !== \"production\" &&\n existing &&\n existing.id !== tab.id\n ) {\n console.warn(\n `TabsNext received duplicate tab value \"${tab.value}\". Tab values must be unique within a TabsNext instance.`,\n );\n }\n\n if (existing === tab) {\n return map;\n }\n\n const next = new Map(map);\n next.set(tab.value, tab);\n return next;\n });\n\n return () => {\n setRenderedTabMap((map) => {\n const existing = map.get(tab.value);\n if (!existing || existing.id !== tab.id) {\n return map;\n }\n\n const next = new Map(map);\n next.delete(tab.value);\n return next;\n });\n };\n }, []);\n\n const updateRenderedTab = useCallback(\n (value: string, updates: Partial<Omit<RenderedTab, \"value\">>) => {\n setRenderedTabMap((map) => {\n const existing = map.get(value);\n if (!existing) {\n return map;\n }\n\n let changed = false;\n const nextRecord = { ...existing };\n for (const [key, nextValue] of Object.entries(updates)) {\n const typedKey = key as keyof Omit<RenderedTab, \"value\">;\n if (nextRecord[typedKey] !== nextValue) {\n changed = true;\n nextRecord[typedKey] = nextValue as never;\n }\n }\n\n if (!changed) {\n return map;\n }\n\n const next = new Map(map);\n next.set(value, nextRecord);\n return next;\n });\n },\n [],\n );\n\n const getRenderedTab = useCallback(\n (value: string) => {\n return renderedTabMap.get(value);\n },\n [renderedTabMap],\n );\n\n const renderedTabs = useMemo(() => {\n return sortRenderedTabs(Array.from(renderedTabMap.values()));\n }, [renderedTabMap]);\n\n const renderedTabOrderMap = useMemo(() => {\n return new Map(\n renderedTabs.map((tab, index) => [tab.value, index] as const),\n );\n }, [renderedTabs]);\n\n const getRenderedTabOrder = useCallback(\n (value: string) => {\n return renderedTabOrderMap.get(value) ?? -1;\n },\n [renderedTabOrderMap],\n );\n\n return {\n renderMode,\n registerBootstrapTab,\n setBootstrapTabReady,\n setBootstrapOverflowReady,\n registerRenderedTab,\n updateRenderedTab,\n getRenderedTab,\n getRenderedTabOrder,\n renderedTabs,\n };\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ import { useEffect } from 'react';
2
+ import { isHTMLElement } from '../domUtils.js';
3
+
4
+ function useTabListRecovery({
5
+ removalVersion,
6
+ targetWindow,
7
+ tabstripRef,
8
+ overflowListRef,
9
+ handleTabRemoval,
10
+ pendingRemovalRecoveryRef,
11
+ pendingRemovalRecoveryRetriesRef
12
+ }) {
13
+ useEffect(() => {
14
+ if (removalVersion < 1) {
15
+ return;
16
+ }
17
+ pendingRemovalRecoveryRef.current = true;
18
+ pendingRemovalRecoveryRetriesRef.current = 0;
19
+ const raf = targetWindow == null ? void 0 : targetWindow.requestAnimationFrame(() => {
20
+ handleTabRemoval();
21
+ });
22
+ return () => {
23
+ if (raf != null) {
24
+ targetWindow == null ? void 0 : targetWindow.cancelAnimationFrame(raf);
25
+ }
26
+ };
27
+ }, [
28
+ handleTabRemoval,
29
+ pendingRemovalRecoveryRef,
30
+ pendingRemovalRecoveryRetriesRef,
31
+ removalVersion,
32
+ targetWindow
33
+ ]);
34
+ useEffect(() => {
35
+ const isInTabList = (node) => {
36
+ var _a, _b;
37
+ if (!node) {
38
+ return false;
39
+ }
40
+ return (((_a = tabstripRef.current) == null ? void 0 : _a.contains(node)) ?? false) || (((_b = overflowListRef.current) == null ? void 0 : _b.contains(node)) ?? false);
41
+ };
42
+ const handleFocusOut = (event) => {
43
+ if (!pendingRemovalRecoveryRef.current) {
44
+ return;
45
+ }
46
+ const wasInTabList = isHTMLElement(event.target) && isInTabList(event.target);
47
+ const stillInTabList = isHTMLElement(event.relatedTarget) && isInTabList(event.relatedTarget);
48
+ if (wasInTabList && !stillInTabList) {
49
+ if (targetWindow == null ? void 0 : targetWindow.requestAnimationFrame) {
50
+ targetWindow.requestAnimationFrame(() => handleTabRemoval());
51
+ } else {
52
+ queueMicrotask(() => handleTabRemoval());
53
+ }
54
+ }
55
+ };
56
+ targetWindow == null ? void 0 : targetWindow.document.addEventListener("focusout", handleFocusOut, true);
57
+ return () => {
58
+ targetWindow == null ? void 0 : targetWindow.document.removeEventListener(
59
+ "focusout",
60
+ handleFocusOut,
61
+ true
62
+ );
63
+ };
64
+ }, [
65
+ handleTabRemoval,
66
+ overflowListRef,
67
+ pendingRemovalRecoveryRef,
68
+ tabstripRef,
69
+ targetWindow
70
+ ]);
71
+ }
72
+
73
+ export { useTabListRecovery };
74
+ //# sourceMappingURL=useTabListRecovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTabListRecovery.js","sources":["../src/tabs-next/hooks/useTabListRecovery.ts"],"sourcesContent":["import { type MutableRefObject, type RefObject, useEffect } from \"react\";\nimport { isHTMLElement } from \"../domUtils\";\n\ninterface UseTabListRecoveryArgs {\n removalVersion: number;\n targetWindow: Window | null | undefined;\n tabstripRef: RefObject<HTMLDivElement | null>;\n overflowListRef: RefObject<HTMLDivElement | null>;\n handleTabRemoval: () => void;\n pendingRemovalRecoveryRef: MutableRefObject<boolean>;\n pendingRemovalRecoveryRetriesRef: MutableRefObject<number>;\n}\n\nexport function useTabListRecovery({\n removalVersion,\n targetWindow,\n tabstripRef,\n overflowListRef,\n handleTabRemoval,\n pendingRemovalRecoveryRef,\n pendingRemovalRecoveryRetriesRef,\n}: UseTabListRecoveryArgs) {\n useEffect(() => {\n if (removalVersion < 1) {\n return;\n }\n\n pendingRemovalRecoveryRef.current = true;\n pendingRemovalRecoveryRetriesRef.current = 0;\n\n const raf = targetWindow?.requestAnimationFrame(() => {\n handleTabRemoval();\n });\n\n return () => {\n if (raf != null) {\n targetWindow?.cancelAnimationFrame(raf);\n }\n };\n }, [\n handleTabRemoval,\n pendingRemovalRecoveryRef,\n pendingRemovalRecoveryRetriesRef,\n removalVersion,\n targetWindow,\n ]);\n\n useEffect(() => {\n const isInTabList = (node: HTMLElement | null) => {\n if (!node) {\n return false;\n }\n\n return (\n (tabstripRef.current?.contains(node) ?? false) ||\n (overflowListRef.current?.contains(node) ?? false)\n );\n };\n\n const handleFocusOut = (event: FocusEvent) => {\n if (!pendingRemovalRecoveryRef.current) {\n return;\n }\n\n const wasInTabList =\n isHTMLElement(event.target) && isInTabList(event.target);\n const stillInTabList =\n isHTMLElement(event.relatedTarget) && isInTabList(event.relatedTarget);\n\n if (wasInTabList && !stillInTabList) {\n if (targetWindow?.requestAnimationFrame) {\n targetWindow.requestAnimationFrame(() => handleTabRemoval());\n } else {\n queueMicrotask(() => handleTabRemoval());\n }\n }\n };\n\n targetWindow?.document.addEventListener(\"focusout\", handleFocusOut, true);\n\n return () => {\n targetWindow?.document.removeEventListener(\n \"focusout\",\n handleFocusOut,\n true,\n );\n };\n }, [\n handleTabRemoval,\n overflowListRef,\n pendingRemovalRecoveryRef,\n tabstripRef,\n targetWindow,\n ]);\n}\n"],"names":[],"mappings":";;;AAaO,SAAS,kBAAA,CAAmB;AAAA,EACjC,cAAA;AAAA,EACA,YAAA;AAAA,EACA,WAAA;AAAA,EACA,eAAA;AAAA,EACA,gBAAA;AAAA,EACA,yBAAA;AAAA,EACA;AACF,CAAA,EAA2B;AACzB,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,iBAAiB,CAAA,EAAG;AACtB,MAAA;AAAA,IACF;AAEA,IAAA,yBAAA,CAA0B,OAAA,GAAU,IAAA;AACpC,IAAA,gCAAA,CAAiC,OAAA,GAAU,CAAA;AAE3C,IAAA,MAAM,GAAA,GAAM,YAAA,IAAA,IAAA,GAAA,MAAA,GAAA,YAAA,CAAc,qBAAA,CAAsB,MAAM;AACpD,MAAA,gBAAA,EAAiB;AAAA,IACnB,CAAA,CAAA;AAEA,IAAA,OAAO,MAAM;AACX,MAAA,IAAI,OAAO,IAAA,EAAM;AACf,QAAA,YAAA,IAAA,IAAA,GAAA,MAAA,GAAA,YAAA,CAAc,oBAAA,CAAqB,GAAA,CAAA;AAAA,MACrC;AAAA,IACF,CAAA;AAAA,EACF,CAAA,EAAG;AAAA,IACD,gBAAA;AAAA,IACA,yBAAA;AAAA,IACA,gCAAA;AAAA,IACA,cAAA;AAAA,IACA;AAAA,GACD,CAAA;AAED,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,WAAA,GAAc,CAAC,IAAA,KAA6B;AAhDtD,MAAA,IAAA,EAAA,EAAA,EAAA;AAiDM,MAAA,IAAI,CAAC,IAAA,EAAM;AACT,QAAA,OAAO,KAAA;AAAA,MACT;AAEA,MAAA,OAAA,CAAA,CAAA,CACG,EAAA,GAAA,WAAA,CAAY,OAAA,KAAZ,IAAA,GAAA,MAAA,GAAA,EAAA,CAAqB,QAAA,CAAS,IAAA,CAAA,KAAS,aACvC,EAAA,GAAA,eAAA,CAAgB,OAAA,KAAhB,IAAA,GAAA,MAAA,GAAA,EAAA,CAAyB,QAAA,CAAS,IAAA,CAAA,KAAS,KAAA,CAAA;AAAA,IAEhD,CAAA;AAEA,IAAA,MAAM,cAAA,GAAiB,CAAC,KAAA,KAAsB;AAC5C,MAAA,IAAI,CAAC,0BAA0B,OAAA,EAAS;AACtC,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,eACJ,aAAA,CAAc,KAAA,CAAM,MAAM,CAAA,IAAK,WAAA,CAAY,MAAM,MAAM,CAAA;AACzD,MAAA,MAAM,iBACJ,aAAA,CAAc,KAAA,CAAM,aAAa,CAAA,IAAK,WAAA,CAAY,MAAM,aAAa,CAAA;AAEvE,MAAA,IAAI,YAAA,IAAgB,CAAC,cAAA,EAAgB;AACnC,QAAA,IAAI,6CAAc,qBAAA,EAAuB;AACvC,UAAA,YAAA,CAAa,qBAAA,CAAsB,MAAM,gBAAA,EAAkB,CAAA;AAAA,QAC7D,CAAA,MAAO;AACL,UAAA,cAAA,CAAe,MAAM,kBAAkB,CAAA;AAAA,QACzC;AAAA,MACF;AAAA,IACF,CAAA;AAEA,IAAA,YAAA,IAAA,IAAA,GAAA,MAAA,GAAA,YAAA,CAAc,QAAA,CAAS,gBAAA,CAAiB,UAAA,EAAY,cAAA,EAAgB,IAAA,CAAA;AAEpE,IAAA,OAAO,MAAM;AACX,MAAA,YAAA,IAAA,IAAA,GAAA,MAAA,GAAA,YAAA,CAAc,QAAA,CAAS,mBAAA;AAAA,QACrB,UAAA;AAAA,QACA,cAAA;AAAA,QACA;AAAA,OAAA;AAAA,IAEJ,CAAA;AAAA,EACF,CAAA,EAAG;AAAA,IACD,gBAAA;AAAA,IACA,eAAA;AAAA,IACA,yBAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GACD,CAAA;AACH;;;;"}
@@ -0,0 +1,163 @@
1
+ import { useCallback, useEffect } from 'react';
2
+ import { useEventCallback } from '../../utils/useEventCallback.js';
3
+ import { isHTMLElement } from '../domUtils.js';
4
+
5
+ function hasLostDocumentFocus(doc) {
6
+ const activeElement = doc.activeElement;
7
+ return !activeElement || activeElement === doc.body || activeElement === doc.documentElement || !activeElement.isConnected;
8
+ }
9
+ function getVisibleSelectedTab(tabstrip, excludedId) {
10
+ if (!tabstrip) {
11
+ return null;
12
+ }
13
+ const tabs = tabstrip.querySelectorAll(
14
+ ':scope > [data-tabslot] [role="tab"][aria-selected="true"]'
15
+ );
16
+ return Array.from(tabs).find((tab) => {
17
+ if (excludedId && tab.id === excludedId) {
18
+ return false;
19
+ }
20
+ return tab.isConnected;
21
+ }) ?? null;
22
+ }
23
+ function useTabRemovalHandler({
24
+ activeTab,
25
+ focusElementWithRetry,
26
+ getFirst,
27
+ getIndex,
28
+ getLast,
29
+ getRemovedItems,
30
+ getRenderedTab,
31
+ getSelectedTabElement,
32
+ item,
33
+ itemAt,
34
+ maxRetryAttempts,
35
+ menuOpen,
36
+ overflowButtonRef,
37
+ overflowListRef,
38
+ pendingRemovalRecoveryRef,
39
+ pendingRemovalRecoveryRetriesRef,
40
+ removalRecoveryRafRef,
41
+ selected,
42
+ setSelected,
43
+ tabstripRef,
44
+ targetWindow
45
+ }) {
46
+ const clearPendingRemovalRecovery = useCallback(() => {
47
+ pendingRemovalRecoveryRef.current = false;
48
+ pendingRemovalRecoveryRetriesRef.current = 0;
49
+ }, [pendingRemovalRecoveryRef, pendingRemovalRecoveryRetriesRef]);
50
+ const handleTabRemoval = useEventCallback(() => {
51
+ var _a;
52
+ const doc = targetWindow == null ? void 0 : targetWindow.document;
53
+ if (!doc) return;
54
+ const activeTabWasSelected = ((_a = activeTab.current) == null ? void 0 : _a.value) === selected;
55
+ const shouldRecoverFocus = () => {
56
+ var _a2, _b;
57
+ if (hasLostDocumentFocus(doc)) return true;
58
+ const activeElement = doc.activeElement;
59
+ if (!isHTMLElement(activeElement)) return false;
60
+ if (!menuOpen) {
61
+ if (activeElement === overflowButtonRef.current) {
62
+ return activeTabWasSelected;
63
+ }
64
+ return ((_a2 = tabstripRef.current) == null ? void 0 : _a2.contains(activeElement)) && activeElement.getAttribute("role") !== "tab";
65
+ }
66
+ if (activeElement === overflowButtonRef.current) {
67
+ return true;
68
+ }
69
+ if ((_b = overflowListRef.current) == null ? void 0 : _b.contains(activeElement)) {
70
+ return activeElement.getAttribute("role") !== "tab";
71
+ }
72
+ return false;
73
+ };
74
+ if (!shouldRecoverFocus()) {
75
+ if (pendingRemovalRecoveryRef.current && removalRecoveryRafRef.current == null) {
76
+ if (pendingRemovalRecoveryRetriesRef.current < maxRetryAttempts) {
77
+ pendingRemovalRecoveryRetriesRef.current += 1;
78
+ if (!(targetWindow == null ? void 0 : targetWindow.requestAnimationFrame)) {
79
+ handleTabRemoval();
80
+ return;
81
+ }
82
+ removalRecoveryRafRef.current = targetWindow.requestAnimationFrame(
83
+ () => {
84
+ removalRecoveryRafRef.current = null;
85
+ handleTabRemoval();
86
+ }
87
+ );
88
+ } else {
89
+ clearPendingRemovalRecovery();
90
+ }
91
+ }
92
+ return;
93
+ }
94
+ if (!activeTab.current) {
95
+ clearPendingRemovalRecovery();
96
+ return;
97
+ }
98
+ const removedItems = getRemovedItems();
99
+ const removed = removedItems.get(activeTab.current.id);
100
+ if (!removed) {
101
+ clearPendingRemovalRecovery();
102
+ return;
103
+ }
104
+ clearPendingRemovalRecovery();
105
+ const removedWasSelected = removed.value === selected;
106
+ const baseIndex = removed.staleIndex ?? -1;
107
+ const removedId = removed.id;
108
+ const restoreFocus = () => {
109
+ var _a2;
110
+ const restoredTab = item(removedId);
111
+ const restoredRenderedTab = getRenderedTab(removed.value);
112
+ const focusMovedToOverflowButton = doc.activeElement === overflowButtonRef.current;
113
+ if (((_a2 = restoredTab == null ? void 0 : restoredTab.element) == null ? void 0 : _a2.isConnected) && (restoredRenderedTab == null ? void 0 : restoredRenderedTab.trigger) === restoredTab.element && !(removedWasSelected && focusMovedToOverflowButton)) {
114
+ if (shouldRecoverFocus()) {
115
+ focusElementWithRetry(() => {
116
+ var _a3;
117
+ return (_a3 = item(removedId)) == null ? void 0 : _a3.element;
118
+ });
119
+ }
120
+ return;
121
+ }
122
+ if (!shouldRecoverFocus()) {
123
+ return;
124
+ }
125
+ let nextTab = (baseIndex >= 0 ? itemAt(baseIndex) : null) ?? (baseIndex > 0 ? itemAt(baseIndex - 1) : null) ?? getLast() ?? getFirst();
126
+ if ((nextTab == null ? void 0 : nextTab.element) === overflowButtonRef.current) {
127
+ const overflowIndex = getIndex(nextTab.id);
128
+ nextTab = (overflowIndex > 0 ? itemAt(overflowIndex - 1) : null) ?? (baseIndex > 0 ? itemAt(baseIndex - 1) : null) ?? getFirst();
129
+ }
130
+ if (!(nextTab == null ? void 0 : nextTab.element)) return;
131
+ if (removedWasSelected && !menuOpen && !getVisibleSelectedTab(tabstripRef.current, removedId)) {
132
+ activeTab.current = { id: nextTab.id, value: nextTab.value };
133
+ setSelected(null, nextTab.value);
134
+ }
135
+ focusElementWithRetry(() => {
136
+ if (removedWasSelected) {
137
+ return getSelectedTabElement() ?? (nextTab == null ? void 0 : nextTab.element);
138
+ }
139
+ return nextTab == null ? void 0 : nextTab.element;
140
+ });
141
+ };
142
+ if (!(targetWindow == null ? void 0 : targetWindow.requestAnimationFrame)) {
143
+ restoreFocus();
144
+ return;
145
+ }
146
+ targetWindow.requestAnimationFrame(() => {
147
+ targetWindow.requestAnimationFrame(() => {
148
+ restoreFocus();
149
+ });
150
+ });
151
+ });
152
+ useEffect(() => {
153
+ return () => {
154
+ if (removalRecoveryRafRef.current != null && targetWindow) {
155
+ targetWindow.cancelAnimationFrame(removalRecoveryRafRef.current);
156
+ }
157
+ };
158
+ }, [removalRecoveryRafRef, targetWindow]);
159
+ return handleTabRemoval;
160
+ }
161
+
162
+ export { useTabRemovalHandler };
163
+ //# sourceMappingURL=useTabRemovalHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTabRemovalHandler.js","sources":["../src/tabs-next/hooks/useTabRemovalHandler.ts"],"sourcesContent":["import {\n type MutableRefObject,\n type RefObject,\n useCallback,\n useEffect,\n} from \"react\";\nimport { useEventCallback } from \"../../utils/useEventCallback\";\nimport { isHTMLElement } from \"../domUtils\";\nimport type { Item, TabsNextContextValue } from \"../TabsNextContext\";\n\ninterface RemovedItem {\n id: string;\n value: string;\n staleIndex?: number;\n}\n\ninterface UseTabRemovalHandlerArgs {\n activeTab: MutableRefObject<Pick<Item, \"id\" | \"value\"> | undefined>;\n focusElementWithRetry: (\n getElement: () => HTMLElement | null | undefined,\n ) => void;\n getFirst: TabsNextContextValue[\"getFirst\"];\n getIndex: TabsNextContextValue[\"getIndex\"];\n getLast: TabsNextContextValue[\"getLast\"];\n getRemovedItems: () => Map<string, RemovedItem>;\n getRenderedTab: TabsNextContextValue[\"getRenderedTab\"];\n getSelectedTabElement: () => HTMLElement | null | undefined;\n item: TabsNextContextValue[\"item\"];\n itemAt: TabsNextContextValue[\"itemAt\"];\n maxRetryAttempts: number;\n menuOpen: boolean;\n overflowButtonRef: RefObject<HTMLButtonElement | null>;\n overflowListRef: RefObject<HTMLDivElement | null>;\n pendingRemovalRecoveryRef: MutableRefObject<boolean>;\n pendingRemovalRecoveryRetriesRef: MutableRefObject<number>;\n removalRecoveryRafRef: MutableRefObject<number | null>;\n selected?: string;\n setSelected: TabsNextContextValue[\"setSelected\"];\n tabstripRef: RefObject<HTMLDivElement | null>;\n targetWindow: Window | null | undefined;\n}\n\nfunction hasLostDocumentFocus(doc: Document) {\n const activeElement = doc.activeElement;\n return (\n !activeElement ||\n activeElement === doc.body ||\n activeElement === doc.documentElement ||\n !activeElement.isConnected\n );\n}\n\nfunction getVisibleSelectedTab(\n tabstrip: HTMLDivElement | null,\n excludedId?: string,\n) {\n if (!tabstrip) {\n return null;\n }\n\n const tabs = tabstrip.querySelectorAll<HTMLElement>(\n ':scope > [data-tabslot] [role=\"tab\"][aria-selected=\"true\"]',\n );\n\n return (\n Array.from(tabs).find((tab) => {\n if (excludedId && tab.id === excludedId) {\n return false;\n }\n\n return tab.isConnected;\n }) ?? null\n );\n}\n\nexport function useTabRemovalHandler({\n activeTab,\n focusElementWithRetry,\n getFirst,\n getIndex,\n getLast,\n getRemovedItems,\n getRenderedTab,\n getSelectedTabElement,\n item,\n itemAt,\n maxRetryAttempts,\n menuOpen,\n overflowButtonRef,\n overflowListRef,\n pendingRemovalRecoveryRef,\n pendingRemovalRecoveryRetriesRef,\n removalRecoveryRafRef,\n selected,\n setSelected,\n tabstripRef,\n targetWindow,\n}: UseTabRemovalHandlerArgs) {\n const clearPendingRemovalRecovery = useCallback(() => {\n pendingRemovalRecoveryRef.current = false;\n pendingRemovalRecoveryRetriesRef.current = 0;\n }, [pendingRemovalRecoveryRef, pendingRemovalRecoveryRetriesRef]);\n\n const handleTabRemoval = useEventCallback(() => {\n const doc = targetWindow?.document;\n if (!doc) return;\n\n const activeTabWasSelected = activeTab.current?.value === selected;\n\n const shouldRecoverFocus = () => {\n if (hasLostDocumentFocus(doc)) return true;\n\n const activeElement = doc.activeElement;\n if (!isHTMLElement(activeElement)) return false;\n\n if (!menuOpen) {\n if (activeElement === overflowButtonRef.current) {\n return activeTabWasSelected;\n }\n\n return (\n tabstripRef.current?.contains(activeElement) &&\n activeElement.getAttribute(\"role\") !== \"tab\"\n );\n }\n\n if (activeElement === overflowButtonRef.current) {\n return true;\n }\n\n if (overflowListRef.current?.contains(activeElement)) {\n // When closing tabs from the overflow menu, focus can remain within\n // the floating UI rather than falling back to body.\n return activeElement.getAttribute(\"role\") !== \"tab\";\n }\n\n return false;\n };\n\n // If focus was lost due to deletion, browsers may report body/html or a\n // disconnected active element depending on browser behavior.\n if (!shouldRecoverFocus()) {\n if (\n pendingRemovalRecoveryRef.current &&\n removalRecoveryRafRef.current == null\n ) {\n if (pendingRemovalRecoveryRetriesRef.current < maxRetryAttempts) {\n pendingRemovalRecoveryRetriesRef.current += 1;\n if (!targetWindow?.requestAnimationFrame) {\n handleTabRemoval();\n return;\n }\n\n removalRecoveryRafRef.current = targetWindow.requestAnimationFrame(\n () => {\n removalRecoveryRafRef.current = null;\n handleTabRemoval();\n },\n );\n } else {\n clearPendingRemovalRecovery();\n }\n }\n return;\n }\n\n if (!activeTab.current) {\n clearPendingRemovalRecovery();\n return;\n }\n\n const removedItems = getRemovedItems();\n const removed = removedItems.get(activeTab.current.id);\n if (!removed) {\n clearPendingRemovalRecovery();\n return;\n }\n\n clearPendingRemovalRecovery();\n const removedWasSelected = removed.value === selected;\n const baseIndex = removed.staleIndex ?? -1;\n const removedId = removed.id;\n\n const restoreFocus = () => {\n const restoredTab = item(removedId);\n const restoredRenderedTab = getRenderedTab(removed.value);\n const focusMovedToOverflowButton =\n doc.activeElement === overflowButtonRef.current;\n\n // Overflow menu updates can temporarily remount tabs. If the tab is\n // back and focus was lost to a disconnected node, restore focus to the\n // remounted tab rather than treating it as a real deletion.\n if (\n restoredTab?.element?.isConnected &&\n restoredRenderedTab?.trigger === restoredTab.element &&\n !(removedWasSelected && focusMovedToOverflowButton)\n ) {\n if (shouldRecoverFocus()) {\n focusElementWithRetry(() => item(removedId)?.element);\n }\n return;\n }\n\n if (!shouldRecoverFocus()) {\n return;\n }\n\n let nextTab =\n (baseIndex >= 0 ? itemAt(baseIndex) : null) ??\n (baseIndex > 0 ? itemAt(baseIndex - 1) : null) ??\n getLast() ??\n getFirst();\n\n if (nextTab?.element === overflowButtonRef.current) {\n const overflowIndex = getIndex(nextTab.id);\n nextTab =\n (overflowIndex > 0 ? itemAt(overflowIndex - 1) : null) ??\n (baseIndex > 0 ? itemAt(baseIndex - 1) : null) ??\n getFirst();\n }\n\n if (!nextTab?.element) return;\n\n if (\n removedWasSelected &&\n !menuOpen &&\n !getVisibleSelectedTab(tabstripRef.current, removedId)\n ) {\n activeTab.current = { id: nextTab.id, value: nextTab.value };\n setSelected(null, nextTab.value);\n }\n\n focusElementWithRetry(() => {\n if (removedWasSelected) {\n return getSelectedTabElement() ?? nextTab?.element;\n }\n\n return nextTab?.element;\n });\n };\n\n if (!targetWindow?.requestAnimationFrame) {\n restoreFocus();\n return;\n }\n\n targetWindow.requestAnimationFrame(() => {\n targetWindow.requestAnimationFrame(() => {\n restoreFocus();\n });\n });\n });\n\n useEffect(() => {\n return () => {\n if (removalRecoveryRafRef.current != null && targetWindow) {\n targetWindow.cancelAnimationFrame(removalRecoveryRafRef.current);\n }\n };\n }, [removalRecoveryRafRef, targetWindow]);\n\n return handleTabRemoval;\n}\n"],"names":["_a"],"mappings":"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"}