@salt-ds/lab 1.0.0-alpha.88 → 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 (171) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/css/salt-lab.css +53 -25
  3. package/dist-cjs/list-deprecated/ListStateContext.js +1 -1
  4. package/dist-cjs/list-deprecated/ListStateContext.js.map +1 -1
  5. package/dist-cjs/tabs-next/TabBar.css.js +1 -1
  6. package/dist-cjs/tabs-next/TabBar.js +1 -1
  7. package/dist-cjs/tabs-next/TabBar.js.map +1 -1
  8. package/dist-cjs/tabs-next/TabListLayoutContext.js +13 -0
  9. package/dist-cjs/tabs-next/TabListLayoutContext.js.map +1 -0
  10. package/dist-cjs/tabs-next/TabListNext.css.js +1 -1
  11. package/dist-cjs/tabs-next/TabListNext.js +179 -33
  12. package/dist-cjs/tabs-next/TabListNext.js.map +1 -1
  13. package/dist-cjs/tabs-next/TabNext.js +111 -7
  14. package/dist-cjs/tabs-next/TabNext.js.map +1 -1
  15. package/dist-cjs/tabs-next/TabNextAction.js +25 -2
  16. package/dist-cjs/tabs-next/TabNextAction.js.map +1 -1
  17. package/dist-cjs/tabs-next/TabNextPanel.js +31 -16
  18. package/dist-cjs/tabs-next/TabNextPanel.js.map +1 -1
  19. package/dist-cjs/tabs-next/TabNextTrigger.js +110 -9
  20. package/dist-cjs/tabs-next/TabNextTrigger.js.map +1 -1
  21. package/dist-cjs/tabs-next/TabOverflowList.css.js +1 -1
  22. package/dist-cjs/tabs-next/TabOverflowList.js +168 -64
  23. package/dist-cjs/tabs-next/TabOverflowList.js.map +1 -1
  24. package/dist-cjs/tabs-next/TabSlot.js +30 -0
  25. package/dist-cjs/tabs-next/TabSlot.js.map +1 -0
  26. package/dist-cjs/tabs-next/TabSlotRegistryContext.js +16 -0
  27. package/dist-cjs/tabs-next/TabSlotRegistryContext.js.map +1 -0
  28. package/dist-cjs/tabs-next/TabsNext.css.js +6 -0
  29. package/dist-cjs/tabs-next/TabsNext.css.js.map +1 -0
  30. package/dist-cjs/tabs-next/TabsNext.js +113 -47
  31. package/dist-cjs/tabs-next/TabsNext.js.map +1 -1
  32. package/dist-cjs/tabs-next/TabsNextContext.js +17 -3
  33. package/dist-cjs/tabs-next/TabsNextContext.js.map +1 -1
  34. package/dist-cjs/tabs-next/domUtils.js +13 -0
  35. package/dist-cjs/tabs-next/domUtils.js.map +1 -0
  36. package/dist-cjs/tabs-next/hooks/overflowMath.js +86 -0
  37. package/dist-cjs/tabs-next/hooks/overflowMath.js.map +1 -0
  38. package/dist-cjs/tabs-next/hooks/useCollection.js +147 -41
  39. package/dist-cjs/tabs-next/hooks/useCollection.js.map +1 -1
  40. package/dist-cjs/tabs-next/hooks/useFocusWithRetry.js +64 -0
  41. package/dist-cjs/tabs-next/hooks/useFocusWithRetry.js.map +1 -0
  42. package/dist-cjs/tabs-next/hooks/useOverflow.js +240 -156
  43. package/dist-cjs/tabs-next/hooks/useOverflow.js.map +1 -1
  44. package/dist-cjs/tabs-next/hooks/useOverflowLayoutState.js +99 -0
  45. package/dist-cjs/tabs-next/hooks/useOverflowLayoutState.js.map +1 -0
  46. package/dist-cjs/tabs-next/hooks/useOverflowSelectionState.js +60 -0
  47. package/dist-cjs/tabs-next/hooks/useOverflowSelectionState.js.map +1 -0
  48. package/dist-cjs/tabs-next/hooks/useRenderedTabWidth.js +92 -0
  49. package/dist-cjs/tabs-next/hooks/useRenderedTabWidth.js.map +1 -0
  50. package/dist-cjs/tabs-next/hooks/useRenderedTabsRegistry.js +200 -0
  51. package/dist-cjs/tabs-next/hooks/useRenderedTabsRegistry.js.map +1 -0
  52. package/dist-cjs/tabs-next/hooks/useTabListRecovery.js +76 -0
  53. package/dist-cjs/tabs-next/hooks/useTabListRecovery.js.map +1 -0
  54. package/dist-cjs/tabs-next/hooks/useTabRemovalHandler.js +165 -0
  55. package/dist-cjs/tabs-next/hooks/useTabRemovalHandler.js.map +1 -0
  56. package/dist-cjs/tabs-next/hooks/useTabSelectionFocus.js +80 -0
  57. package/dist-cjs/tabs-next/hooks/useTabSelectionFocus.js.map +1 -0
  58. package/dist-cjs/tabs-next/widthMeasurement.js +42 -0
  59. package/dist-cjs/tabs-next/widthMeasurement.js.map +1 -0
  60. package/dist-cjs/tree/Tree.css.js +1 -1
  61. package/dist-cjs/tree/TreeNode.css.js +1 -1
  62. package/dist-cjs/tree/TreeNode.js +1 -1
  63. package/dist-cjs/tree/TreeNode.js.map +1 -1
  64. package/dist-cjs/tree/TreeNodeExpansionIcon.css.js +1 -1
  65. package/dist-cjs/tree/TreeNodeTrigger.css.js +1 -1
  66. package/dist-cjs/tree/TreeNodeTrigger.js +2 -2
  67. package/dist-cjs/tree/TreeNodeTrigger.js.map +1 -1
  68. package/dist-cjs/utils/useEventCallback.js +5 -5
  69. package/dist-cjs/utils/useEventCallback.js.map +1 -1
  70. package/dist-es/list-deprecated/ListStateContext.js +1 -1
  71. package/dist-es/list-deprecated/ListStateContext.js.map +1 -1
  72. package/dist-es/tabs-next/TabBar.css.js +1 -1
  73. package/dist-es/tabs-next/TabBar.js +1 -1
  74. package/dist-es/tabs-next/TabBar.js.map +1 -1
  75. package/dist-es/tabs-next/TabListLayoutContext.js +10 -0
  76. package/dist-es/tabs-next/TabListLayoutContext.js.map +1 -0
  77. package/dist-es/tabs-next/TabListNext.css.js +1 -1
  78. package/dist-es/tabs-next/TabListNext.js +182 -36
  79. package/dist-es/tabs-next/TabListNext.js.map +1 -1
  80. package/dist-es/tabs-next/TabNext.js +113 -9
  81. package/dist-es/tabs-next/TabNext.js.map +1 -1
  82. package/dist-es/tabs-next/TabNextAction.js +25 -2
  83. package/dist-es/tabs-next/TabNextAction.js.map +1 -1
  84. package/dist-es/tabs-next/TabNextPanel.js +31 -16
  85. package/dist-es/tabs-next/TabNextPanel.js.map +1 -1
  86. package/dist-es/tabs-next/TabNextTrigger.js +110 -9
  87. package/dist-es/tabs-next/TabNextTrigger.js.map +1 -1
  88. package/dist-es/tabs-next/TabOverflowList.css.js +1 -1
  89. package/dist-es/tabs-next/TabOverflowList.js +172 -68
  90. package/dist-es/tabs-next/TabOverflowList.js.map +1 -1
  91. package/dist-es/tabs-next/TabSlot.js +28 -0
  92. package/dist-es/tabs-next/TabSlot.js.map +1 -0
  93. package/dist-es/tabs-next/TabSlotRegistryContext.js +13 -0
  94. package/dist-es/tabs-next/TabSlotRegistryContext.js.map +1 -0
  95. package/dist-es/tabs-next/TabsNext.css.js +4 -0
  96. package/dist-es/tabs-next/TabsNext.css.js.map +1 -0
  97. package/dist-es/tabs-next/TabsNext.js +114 -48
  98. package/dist-es/tabs-next/TabsNext.js.map +1 -1
  99. package/dist-es/tabs-next/TabsNextContext.js +17 -3
  100. package/dist-es/tabs-next/TabsNextContext.js.map +1 -1
  101. package/dist-es/tabs-next/domUtils.js +11 -0
  102. package/dist-es/tabs-next/domUtils.js.map +1 -0
  103. package/dist-es/tabs-next/hooks/overflowMath.js +82 -0
  104. package/dist-es/tabs-next/hooks/overflowMath.js.map +1 -0
  105. package/dist-es/tabs-next/hooks/useCollection.js +148 -42
  106. package/dist-es/tabs-next/hooks/useCollection.js.map +1 -1
  107. package/dist-es/tabs-next/hooks/useFocusWithRetry.js +62 -0
  108. package/dist-es/tabs-next/hooks/useFocusWithRetry.js.map +1 -0
  109. package/dist-es/tabs-next/hooks/useOverflow.js +242 -158
  110. package/dist-es/tabs-next/hooks/useOverflow.js.map +1 -1
  111. package/dist-es/tabs-next/hooks/useOverflowLayoutState.js +97 -0
  112. package/dist-es/tabs-next/hooks/useOverflowLayoutState.js.map +1 -0
  113. package/dist-es/tabs-next/hooks/useOverflowSelectionState.js +58 -0
  114. package/dist-es/tabs-next/hooks/useOverflowSelectionState.js.map +1 -0
  115. package/dist-es/tabs-next/hooks/useRenderedTabWidth.js +90 -0
  116. package/dist-es/tabs-next/hooks/useRenderedTabWidth.js.map +1 -0
  117. package/dist-es/tabs-next/hooks/useRenderedTabsRegistry.js +198 -0
  118. package/dist-es/tabs-next/hooks/useRenderedTabsRegistry.js.map +1 -0
  119. package/dist-es/tabs-next/hooks/useTabListRecovery.js +74 -0
  120. package/dist-es/tabs-next/hooks/useTabListRecovery.js.map +1 -0
  121. package/dist-es/tabs-next/hooks/useTabRemovalHandler.js +163 -0
  122. package/dist-es/tabs-next/hooks/useTabRemovalHandler.js.map +1 -0
  123. package/dist-es/tabs-next/hooks/useTabSelectionFocus.js +78 -0
  124. package/dist-es/tabs-next/hooks/useTabSelectionFocus.js.map +1 -0
  125. package/dist-es/tabs-next/widthMeasurement.js +36 -0
  126. package/dist-es/tabs-next/widthMeasurement.js.map +1 -0
  127. package/dist-es/tree/Tree.css.js +1 -1
  128. package/dist-es/tree/TreeNode.css.js +1 -1
  129. package/dist-es/tree/TreeNode.js +1 -1
  130. package/dist-es/tree/TreeNode.js.map +1 -1
  131. package/dist-es/tree/TreeNodeExpansionIcon.css.js +1 -1
  132. package/dist-es/tree/TreeNodeTrigger.css.js +1 -1
  133. package/dist-es/tree/TreeNodeTrigger.js +2 -2
  134. package/dist-es/tree/TreeNodeTrigger.js.map +1 -1
  135. package/dist-es/utils/useEventCallback.js +5 -5
  136. package/dist-es/utils/useEventCallback.js.map +1 -1
  137. package/dist-types/cascading-menu/internal/useMenuTriggerHandlers.d.ts +1 -1
  138. package/dist-types/list-deprecated/ListStateContext.d.ts +7 -2
  139. package/dist-types/tabs-next/TabListLayoutContext.d.ts +9 -0
  140. package/dist-types/tabs-next/TabNext.d.ts +1 -1
  141. package/dist-types/tabs-next/TabNextPanel.d.ts +2 -1
  142. package/dist-types/tabs-next/TabOverflowList.d.ts +3 -4
  143. package/dist-types/tabs-next/TabSlot.d.ts +6 -0
  144. package/dist-types/tabs-next/TabSlotRegistryContext.d.ts +5 -0
  145. package/dist-types/tabs-next/TabsNext.d.ts +2 -1
  146. package/dist-types/tabs-next/TabsNextContext.d.ts +26 -4
  147. package/dist-types/tabs-next/domUtils.d.ts +1 -0
  148. package/dist-types/tabs-next/hooks/overflowMath.d.ts +18 -0
  149. package/dist-types/tabs-next/hooks/useCollection.d.ts +15 -3
  150. package/dist-types/tabs-next/hooks/useFocusWithRetry.d.ts +9 -0
  151. package/dist-types/tabs-next/hooks/useOverflow.d.ts +5 -5
  152. package/dist-types/tabs-next/hooks/useOverflowLayoutState.d.ts +13 -0
  153. package/dist-types/tabs-next/hooks/useOverflowSelectionState.d.ts +13 -0
  154. package/dist-types/tabs-next/hooks/useRenderedTabWidth.d.ts +12 -0
  155. package/dist-types/tabs-next/hooks/useRenderedTabsRegistry.d.ts +12 -0
  156. package/dist-types/tabs-next/hooks/useTabListRecovery.d.ts +12 -0
  157. package/dist-types/tabs-next/hooks/useTabRemovalHandler.d.ts +32 -0
  158. package/dist-types/tabs-next/hooks/useTabSelectionFocus.d.ts +15 -0
  159. package/dist-types/tabs-next/widthMeasurement.d.ts +5 -0
  160. package/dist-types/utils/useEventCallback.d.ts +1 -1
  161. package/package.json +2 -2
  162. package/dist-cjs/tabs-next/hooks/useFocusOutside.js +0 -25
  163. package/dist-cjs/tabs-next/hooks/useFocusOutside.js.map +0 -1
  164. package/dist-cjs/tabs-next/hooks/useRestoreActiveTab.js +0 -93
  165. package/dist-cjs/tabs-next/hooks/useRestoreActiveTab.js.map +0 -1
  166. package/dist-es/tabs-next/hooks/useFocusOutside.js +0 -23
  167. package/dist-es/tabs-next/hooks/useFocusOutside.js.map +0 -1
  168. package/dist-es/tabs-next/hooks/useRestoreActiveTab.js +0 -91
  169. package/dist-es/tabs-next/hooks/useRestoreActiveTab.js.map +0 -1
  170. package/dist-types/tabs-next/hooks/useFocusOutside.d.ts +0 -2
  171. package/dist-types/tabs-next/hooks/useRestoreActiveTab.d.ts +0 -10
@@ -1 +1 @@
1
- {"version":3,"file":"TabsNext.js","sources":["../src/tabs-next/TabsNext.tsx"],"sourcesContent":["import { makePrefixer, useControlled, useEventCallback } from \"@salt-ds/core\";\nimport { clsx } from \"clsx\";\nimport {\n type ComponentPropsWithoutRef,\n forwardRef,\n type ReactNode,\n type SyntheticEvent,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { useCollection } from \"./hooks/useCollection\";\nimport { type Item, TabsNextContext } from \"./TabsNextContext\";\n\nexport interface TabsNextProps\n extends Omit<ComponentPropsWithoutRef<\"div\">, \"onChange\"> {\n children?: ReactNode;\n /**\n * The default value. Use when the component is not controlled.\n */\n defaultValue?: string;\n /**\n * The value. Use when the component is controlled.\n */\n value?: string;\n /**\n * Callback fired when the selection changes. The event will be null when selection is moved automatically.\n */\n onChange?: (event: SyntheticEvent | null, value: string) => void;\n}\n\nconst withBaseName = makePrefixer(\"saltTabsNext\");\n\nexport const TabsNext = forwardRef<HTMLDivElement, TabsNextProps>(\n function TabsNext(props, ref) {\n const { className, children, value, defaultValue, onChange, ...rest } =\n props;\n\n const [valueToTabIdMap, setValueToIdMap] = useState({\n map: new Map<string, string>(),\n });\n const [valueToPanelIdMap, setValueToPanelIdMap] = useState({\n map: new Map<string, string>(),\n });\n\n const {\n registerItem,\n item,\n getNext,\n getPrevious,\n getFirst,\n getLast,\n items,\n } = useCollection({ wrap: true });\n\n const activeTab = useRef<Pick<Item, \"id\" | \"value\">>();\n const removedActiveTabRef = useRef<string | undefined>(undefined);\n\n const [menuOpen, setMenuOpen] = useState(false);\n\n const [selected, setSelectedState] = useControlled({\n controlled: value,\n default: defaultValue,\n name: \"TabListNext\",\n state: \"selected\",\n });\n\n const setSelected = useCallback(\n (event: SyntheticEvent | null, value: string) => {\n setMenuOpen(false);\n setSelectedState(value);\n onChange?.(event, value);\n },\n [onChange],\n );\n\n const registerTab = useEventCallback((item: Item) => {\n const cleanup = registerItem(item);\n setValueToIdMap(({ map }) => {\n map.set(item.value, item.id);\n return { map };\n });\n\n return () => {\n cleanup();\n setValueToIdMap(({ map }) => {\n map.delete(item.value);\n return { map };\n });\n\n if (activeTab.current?.value !== item.value) {\n return;\n }\n\n removedActiveTabRef.current = item.value;\n };\n });\n\n const registerPanel = useCallback((id: string, value: string) => {\n setValueToPanelIdMap(({ map }) => {\n map.set(value, id);\n return { map };\n });\n return () => {\n setValueToIdMap(({ map }) => {\n map.delete(value);\n return { map };\n });\n };\n }, []);\n\n const getPanelId = useCallback(\n (value: string) => {\n return valueToPanelIdMap.map.get(value);\n },\n [valueToPanelIdMap],\n );\n\n const getTabId = useCallback(\n (value: string) => {\n return valueToTabIdMap.map.get(value);\n },\n [valueToTabIdMap],\n );\n\n const context = useMemo(\n () => ({\n registerTab,\n registerPanel,\n getPanelId,\n getTabId,\n selected,\n setSelected,\n item,\n getNext,\n getPrevious,\n getFirst,\n getLast,\n items,\n activeTab,\n menuOpen,\n setMenuOpen,\n removedActiveTabRef,\n }),\n [\n registerPanel,\n registerTab,\n getPanelId,\n getTabId,\n selected,\n setSelected,\n item,\n getNext,\n getPrevious,\n getFirst,\n getLast,\n items,\n menuOpen,\n ],\n );\n\n return (\n <TabsNextContext.Provider value={context}>\n <div className={clsx(withBaseName(), className)} ref={ref} {...rest}>\n {children}\n </div>\n </TabsNextContext.Provider>\n );\n },\n);\n"],"names":["makePrefixer","forwardRef","TabsNext","useState","useCollection","useRef","useControlled","useCallback","value","useEventCallback","item","useMemo","TabsNextContext","clsx"],"mappings":"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"}
1
+ {"version":3,"file":"TabsNext.js","sources":["../src/tabs-next/TabsNext.tsx"],"sourcesContent":["import { makePrefixer, useControlled } from \"@salt-ds/core\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n type ComponentPropsWithoutRef,\n forwardRef,\n type ReactNode,\n type SyntheticEvent,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { useCollection } from \"./hooks/useCollection\";\nimport { useOverflowSelectionState } from \"./hooks/useOverflowSelectionState\";\nimport { useRenderedTabsRegistry } from \"./hooks/useRenderedTabsRegistry\";\nimport tabsNextCss from \"./TabsNext.css\";\nimport { type Item, TabsNextContext } from \"./TabsNextContext\";\n\nexport interface TabsNextProps\n extends Omit<ComponentPropsWithoutRef<\"div\">, \"onChange\"> {\n children?: ReactNode;\n /**\n * The default value. Use when the component is not controlled.\n */\n defaultValue?: string;\n /**\n * The value. Use when the component is controlled.\n */\n value?: string;\n /**\n * Callback fired when the selection changes. The event will be null when\n * selection is moved automatically.\n */\n onChange?: (event: SyntheticEvent | null, value: string) => void;\n}\n\nconst withBaseName = makePrefixer(\"saltTabsNext\");\n\nfunction setValueIdMapEntry(\n map: Map<string, string>,\n value: string,\n id: string,\n) {\n if (map.get(value) === id) {\n return map;\n }\n\n const next = new Map(map);\n next.set(value, id);\n return next;\n}\n\nfunction removeValueIdMapEntry(\n map: Map<string, string>,\n value: string,\n id: string,\n) {\n if (map.get(value) !== id) {\n return map;\n }\n\n const next = new Map(map);\n next.delete(value);\n return next;\n}\n\nexport const TabsNext = forwardRef<HTMLDivElement, TabsNextProps>(\n function TabsNext(props, ref) {\n const { className, children, value, defaultValue, onChange, ...rest } =\n props;\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-tabs-next\",\n css: tabsNextCss,\n window: targetWindow,\n });\n\n const [valueToTabIdMap, setValueToIdMap] = useState(\n () => new Map<string, string>(),\n );\n const [valueToPanelIdMap, setValueToPanelIdMap] = useState(\n () => new Map<string, string>(),\n );\n const {\n renderMode,\n registerBootstrapTab,\n setBootstrapTabReady,\n setBootstrapOverflowReady,\n registerRenderedTab,\n updateRenderedTab,\n getRenderedTab,\n getRenderedTabOrder,\n renderedTabs,\n } = useRenderedTabsRegistry();\n\n const {\n registerItem,\n updateItem,\n item,\n getNext,\n getPrevious,\n getFirst,\n getLast,\n itemAt,\n getIndex,\n sortItems,\n removalVersion,\n getRemovedItems,\n } = useCollection({ targetWindow, wrap: true });\n\n const activeTab = useRef<Pick<Item, \"id\" | \"value\">>();\n\n const [menuOpen, setMenuOpen] = useState(false);\n\n const [selected, setSelectedState] = useControlled({\n controlled: value,\n default: defaultValue,\n name: \"TabsNext\",\n state: \"selected\",\n });\n\n const commitSelection = useCallback(\n (event: SyntheticEvent | null, newValue: string) => {\n setSelectedState(newValue);\n if (selected !== newValue) {\n onChange?.(event, newValue);\n }\n },\n [onChange, selected],\n );\n const { selectionFromOverflowValueRef, setSelected } =\n useOverflowSelectionState({\n commitSelection,\n menuOpen,\n selected,\n setMenuOpen,\n });\n\n const registerTab = useCallback(\n (tab: Item) => {\n const cleanup = registerItem(tab);\n setValueToIdMap((map) => setValueIdMapEntry(map, tab.value, tab.id));\n\n return () => {\n cleanup();\n setValueToIdMap((map) =>\n removeValueIdMapEntry(map, tab.value, tab.id),\n );\n };\n },\n [registerItem],\n );\n\n const registerPanel = useCallback((id: string, value: string) => {\n setValueToPanelIdMap((map) => setValueIdMapEntry(map, value, id));\n return () => {\n setValueToPanelIdMap((map) => removeValueIdMapEntry(map, value, id));\n };\n }, []);\n\n const getPanelId = useCallback(\n (value: string) => {\n return valueToPanelIdMap.get(value);\n },\n [valueToPanelIdMap],\n );\n\n const getTabId = useCallback(\n (value: string) => {\n return valueToTabIdMap.get(value);\n },\n [valueToTabIdMap],\n );\n\n const context = useMemo(\n () => ({\n renderMode,\n registerBootstrapTab,\n setBootstrapTabReady,\n setBootstrapOverflowReady,\n registerTab,\n updateTab: updateItem,\n registerRenderedTab,\n updateRenderedTab,\n getRenderedTab,\n getRenderedTabOrder,\n renderedTabs,\n registerPanel,\n getPanelId,\n getTabId,\n selected,\n setSelected,\n item,\n getNext,\n getPrevious,\n getFirst,\n getLast,\n activeTab,\n selectionFromOverflowValueRef,\n menuOpen,\n setMenuOpen,\n itemAt,\n getIndex,\n sortItems,\n removalVersion,\n getRemovedItems,\n }),\n [\n renderMode,\n registerBootstrapTab,\n setBootstrapTabReady,\n setBootstrapOverflowReady,\n registerPanel,\n registerTab,\n updateItem,\n registerRenderedTab,\n updateRenderedTab,\n getRenderedTab,\n getRenderedTabOrder,\n renderedTabs,\n getPanelId,\n getTabId,\n selected,\n setSelected,\n item,\n getNext,\n getPrevious,\n getFirst,\n getLast,\n menuOpen,\n itemAt,\n getIndex,\n sortItems,\n removalVersion,\n getRemovedItems,\n selectionFromOverflowValueRef,\n ],\n );\n\n return (\n <TabsNextContext.Provider value={context}>\n <div className={clsx(withBaseName(), className)} ref={ref} {...rest}>\n {children}\n </div>\n </TabsNextContext.Provider>\n );\n },\n);\n"],"names":["makePrefixer","forwardRef","TabsNext","useWindow","useComponentCssInjection","tabsNextCss","useState","useRenderedTabsRegistry","useCollection","useRef","useControlled","useCallback","useOverflowSelectionState","value","useMemo","TabsNextContext","clsx"],"mappings":"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"}
@@ -11,17 +11,31 @@ const TabsNextContext = core.createContext(
11
11
  getNext: () => null,
12
12
  getPrevious: () => null,
13
13
  item: () => null,
14
- items: [],
14
+ getIndex: () => -1,
15
+ itemAt: () => null,
16
+ sortItems: () => void 0,
17
+ renderMode: "inline",
18
+ registerBootstrapTab: () => () => void 0,
19
+ setBootstrapTabReady: () => void 0,
20
+ setBootstrapOverflowReady: () => void 0,
15
21
  selected: void 0,
16
22
  registerTab: () => () => void 0,
23
+ updateTab: () => void 0,
24
+ registerRenderedTab: () => () => void 0,
25
+ updateRenderedTab: () => void 0,
26
+ getRenderedTab: () => void 0,
27
+ getRenderedTabOrder: () => -1,
28
+ renderedTabs: [],
17
29
  registerPanel: () => () => void 0,
18
30
  getPanelId: () => void 0,
19
31
  getTabId: () => void 0,
20
32
  setSelected: () => void 0,
21
33
  activeTab: { current: void 0 },
22
- removedActiveTabRef: { current: void 0 },
34
+ selectionFromOverflowValueRef: { current: null },
23
35
  menuOpen: false,
24
- setMenuOpen: () => void 0
36
+ setMenuOpen: () => void 0,
37
+ removalVersion: 0,
38
+ getRemovedItems: () => /* @__PURE__ */ new Map()
25
39
  }
26
40
  );
27
41
  function useTabsNext() {
@@ -1 +1 @@
1
- {"version":3,"file":"TabsNextContext.js","sources":["../src/tabs-next/TabsNextContext.tsx"],"sourcesContent":["import { createContext } from \"@salt-ds/core\";\nimport {\n type Dispatch,\n type MutableRefObject,\n type SetStateAction,\n type SyntheticEvent,\n useContext,\n} from \"react\";\nimport type { useCollection } from \"./hooks/useCollection\";\n\nexport interface Item {\n id: string;\n value: string;\n element: HTMLElement;\n}\n\nexport interface TabsNextContextValue\n extends Omit<ReturnType<typeof useCollection>, \"registerItem\"> {\n registerTab: (item: Item) => () => void;\n registerPanel: (id: string, value: string) => () => void;\n getPanelId: (value: string) => string | undefined;\n getTabId: (value: string) => string | undefined;\n selected?: string;\n setSelected: (event: SyntheticEvent, value: string) => void;\n activeTab: MutableRefObject<Pick<Item, \"id\" | \"value\"> | undefined>;\n removedActiveTabRef: MutableRefObject<string | undefined>;\n menuOpen: boolean;\n setMenuOpen: Dispatch<SetStateAction<boolean>>;\n}\n\nexport const TabsNextContext = createContext<TabsNextContextValue>(\n \"TabsNextContext\",\n {\n getFirst: () => null,\n getLast: () => null,\n getNext: () => null,\n getPrevious: () => null,\n item: () => null,\n items: [],\n selected: undefined,\n registerTab: () => () => undefined,\n registerPanel: () => () => undefined,\n getPanelId: () => undefined,\n getTabId: () => undefined,\n setSelected: () => undefined,\n activeTab: { current: undefined },\n removedActiveTabRef: { current: undefined },\n menuOpen: false,\n setMenuOpen: () => undefined,\n },\n);\n\nexport function useTabsNext() {\n return useContext(TabsNextContext);\n}\n"],"names":["createContext","useContext"],"mappings":";;;;;AA8BO,MAAM,eAAA,GAAkBA,kBAAA;AAAA,EAC7B,iBAAA;AAAA,EACA;AAAA,IACE,UAAU,MAAM,IAAA;AAAA,IAChB,SAAS,MAAM,IAAA;AAAA,IACf,SAAS,MAAM,IAAA;AAAA,IACf,aAAa,MAAM,IAAA;AAAA,IACnB,MAAM,MAAM,IAAA;AAAA,IACZ,OAAO,EAAC;AAAA,IACR,QAAA,EAAU,MAAA;AAAA,IACV,WAAA,EAAa,MAAM,MAAM,MAAA;AAAA,IACzB,aAAA,EAAe,MAAM,MAAM,MAAA;AAAA,IAC3B,YAAY,MAAM,MAAA;AAAA,IAClB,UAAU,MAAM,MAAA;AAAA,IAChB,aAAa,MAAM,MAAA;AAAA,IACnB,SAAA,EAAW,EAAE,OAAA,EAAS,MAAA,EAAU;AAAA,IAChC,mBAAA,EAAqB,EAAE,OAAA,EAAS,MAAA,EAAU;AAAA,IAC1C,QAAA,EAAU,KAAA;AAAA,IACV,aAAa,MAAM;AAAA;AAEvB;AAEO,SAAS,WAAA,GAAc;AAC5B,EAAA,OAAOC,iBAAW,eAAe,CAAA;AACnC;;;;;"}
1
+ {"version":3,"file":"TabsNextContext.js","sources":["../src/tabs-next/TabsNextContext.tsx"],"sourcesContent":["import { createContext } from \"@salt-ds/core\";\nimport {\n type Dispatch,\n type MutableRefObject,\n type SetStateAction,\n type SyntheticEvent,\n useContext,\n} from \"react\";\nimport type { useCollection } from \"./hooks/useCollection\";\n\nexport interface Item {\n id: string;\n value: string;\n element: HTMLElement | null;\n location?: \"hidden\" | \"main\" | \"overflow\";\n order?: number;\n}\n\nexport interface RenderedTab {\n host: HTMLDivElement;\n id: string;\n marker: HTMLElement | null;\n root: HTMLElement | null;\n trigger: HTMLButtonElement | null;\n value: string;\n width: number;\n}\n\nexport type TabsNextRenderMode = \"inline\" | \"portal\";\n\nexport interface TabsNextContextValue\n extends Omit<\n ReturnType<typeof useCollection>,\n \"registerItem\" | \"updateItem\"\n > {\n renderMode: TabsNextRenderMode;\n registerBootstrapTab: (value: string) => () => void;\n setBootstrapTabReady: (value: string, ready: boolean) => void;\n setBootstrapOverflowReady: (ready: boolean) => void;\n registerTab: (item: Item) => () => void;\n updateTab: (id: string, updates: Partial<Omit<Item, \"id\" | \"value\">>) => void;\n registerRenderedTab: (tab: RenderedTab) => () => void;\n updateRenderedTab: (\n value: string,\n updates: Partial<Omit<RenderedTab, \"value\">>,\n ) => void;\n getRenderedTab: (value: string) => RenderedTab | undefined;\n getRenderedTabOrder: (value: string) => number;\n renderedTabs: RenderedTab[];\n registerPanel: (id: string, value: string) => () => void;\n getPanelId: (value: string) => string | undefined;\n getTabId: (value: string) => string | undefined;\n selected?: string;\n setSelected: (\n event: SyntheticEvent | null,\n value: string,\n source?: \"main\" | \"overflow\",\n ) => void;\n activeTab: MutableRefObject<Pick<Item, \"id\" | \"value\"> | undefined>;\n selectionFromOverflowValueRef: MutableRefObject<string | null>;\n menuOpen: boolean;\n setMenuOpen: Dispatch<SetStateAction<boolean>>;\n}\n\nexport const TabsNextContext = createContext<TabsNextContextValue>(\n \"TabsNextContext\",\n {\n getFirst: () => null,\n getLast: () => null,\n getNext: () => null,\n getPrevious: () => null,\n item: () => null,\n getIndex: () => -1,\n itemAt: () => null,\n sortItems: () => undefined,\n renderMode: \"inline\",\n registerBootstrapTab: () => () => undefined,\n setBootstrapTabReady: () => undefined,\n setBootstrapOverflowReady: () => undefined,\n selected: undefined,\n registerTab: () => () => undefined,\n updateTab: () => undefined,\n registerRenderedTab: () => () => undefined,\n updateRenderedTab: () => undefined,\n getRenderedTab: () => undefined,\n getRenderedTabOrder: () => -1,\n renderedTabs: [],\n registerPanel: () => () => undefined,\n getPanelId: () => undefined,\n getTabId: () => undefined,\n setSelected: () => undefined,\n activeTab: { current: undefined },\n selectionFromOverflowValueRef: { current: null },\n menuOpen: false,\n setMenuOpen: () => undefined,\n removalVersion: 0,\n getRemovedItems: () => new Map(),\n },\n);\n\nexport function useTabsNext() {\n return useContext(TabsNextContext);\n}\n"],"names":["createContext","useContext"],"mappings":";;;;;AAgEO,MAAM,eAAA,GAAkBA,kBAAA;AAAA,EAC7B,iBAAA;AAAA,EACA;AAAA,IACE,UAAU,MAAM,IAAA;AAAA,IAChB,SAAS,MAAM,IAAA;AAAA,IACf,SAAS,MAAM,IAAA;AAAA,IACf,aAAa,MAAM,IAAA;AAAA,IACnB,MAAM,MAAM,IAAA;AAAA,IACZ,UAAU,MAAM,EAAA;AAAA,IAChB,QAAQ,MAAM,IAAA;AAAA,IACd,WAAW,MAAM,MAAA;AAAA,IACjB,UAAA,EAAY,QAAA;AAAA,IACZ,oBAAA,EAAsB,MAAM,MAAM,MAAA;AAAA,IAClC,sBAAsB,MAAM,MAAA;AAAA,IAC5B,2BAA2B,MAAM,MAAA;AAAA,IACjC,QAAA,EAAU,MAAA;AAAA,IACV,WAAA,EAAa,MAAM,MAAM,MAAA;AAAA,IACzB,WAAW,MAAM,MAAA;AAAA,IACjB,mBAAA,EAAqB,MAAM,MAAM,MAAA;AAAA,IACjC,mBAAmB,MAAM,MAAA;AAAA,IACzB,gBAAgB,MAAM,MAAA;AAAA,IACtB,qBAAqB,MAAM,EAAA;AAAA,IAC3B,cAAc,EAAC;AAAA,IACf,aAAA,EAAe,MAAM,MAAM,MAAA;AAAA,IAC3B,YAAY,MAAM,MAAA;AAAA,IAClB,UAAU,MAAM,MAAA;AAAA,IAChB,aAAa,MAAM,MAAA;AAAA,IACnB,SAAA,EAAW,EAAE,OAAA,EAAS,MAAA,EAAU;AAAA,IAChC,6BAAA,EAA+B,EAAE,OAAA,EAAS,IAAA,EAAK;AAAA,IAC/C,QAAA,EAAU,KAAA;AAAA,IACV,aAAa,MAAM,MAAA;AAAA,IACnB,cAAA,EAAgB,CAAA;AAAA,IAChB,eAAA,EAAiB,sBAAM,IAAI,GAAA;AAAI;AAEnC;AAEO,SAAS,WAAA,GAAc;AAC5B,EAAA,OAAOC,iBAAW,eAAe,CAAA;AACnC;;;;;"}
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ function isHTMLElement(node) {
4
+ if (!node || typeof node !== "object") {
5
+ return false;
6
+ }
7
+ const ownerDocument = node.ownerDocument;
8
+ const defaultView = ownerDocument == null ? void 0 : ownerDocument.defaultView;
9
+ return !!defaultView && node instanceof defaultView.HTMLElement;
10
+ }
11
+
12
+ exports.isHTMLElement = isHTMLElement;
13
+ //# sourceMappingURL=domUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domUtils.js","sources":["../src/tabs-next/domUtils.ts"],"sourcesContent":["export function isHTMLElement(node: unknown): node is HTMLElement {\n if (!node || typeof node !== \"object\") {\n return false;\n }\n\n const ownerDocument = (node as { ownerDocument?: Document | null })\n .ownerDocument;\n const defaultView = ownerDocument?.defaultView;\n\n return !!defaultView && node instanceof defaultView.HTMLElement;\n}\n"],"names":[],"mappings":";;AAAO,SAAS,cAAc,IAAA,EAAoC;AAChE,EAAA,IAAI,CAAC,IAAA,IAAQ,OAAO,IAAA,KAAS,QAAA,EAAU;AACrC,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,gBAAiB,IAAA,CACpB,aAAA;AACH,EAAA,MAAM,cAAc,aAAA,IAAA,IAAA,GAAA,MAAA,GAAA,aAAA,CAAe,WAAA;AAEnC,EAAA,OAAO,CAAC,CAAC,WAAA,IAAe,IAAA,YAAgB,WAAA,CAAY,WAAA;AACtD;;;;"}
@@ -0,0 +1,86 @@
1
+ 'use strict';
2
+
3
+ const MIN_TRUSTED_TAB_WIDTH = 0.5;
4
+ function calculateVisibleCount({
5
+ gap,
6
+ maxWidth: initialMaxWidth,
7
+ overflowWidth,
8
+ pinnedValue,
9
+ tabs
10
+ }) {
11
+ let maxWidth = initialMaxWidth;
12
+ let currentWidth = 0;
13
+ let nextVisibleCount = 0;
14
+ const visibleItems = [];
15
+ while (nextVisibleCount < tabs.length) {
16
+ const item = tabs[nextVisibleCount];
17
+ if (!item) {
18
+ break;
19
+ }
20
+ if (item.width == null) {
21
+ return null;
22
+ }
23
+ const itemWidth = item.width + gap;
24
+ if (currentWidth + itemWidth > maxWidth) {
25
+ break;
26
+ }
27
+ currentWidth += itemWidth;
28
+ visibleItems.push(item);
29
+ nextVisibleCount += 1;
30
+ }
31
+ const allTabsFit = nextVisibleCount >= tabs.length;
32
+ if (allTabsFit) {
33
+ return nextVisibleCount;
34
+ }
35
+ maxWidth -= overflowWidth;
36
+ while (currentWidth > maxWidth) {
37
+ const removed = visibleItems.pop();
38
+ if (!removed) {
39
+ break;
40
+ }
41
+ if (removed.width == null) {
42
+ return null;
43
+ }
44
+ currentWidth -= removed.width + gap;
45
+ nextVisibleCount -= 1;
46
+ }
47
+ const pinnedItem = pinnedValue == null ? null : tabs.find((item) => item.value === pinnedValue) ?? null;
48
+ if (pinnedItem && !visibleItems.includes(pinnedItem)) {
49
+ if (pinnedItem.width == null) {
50
+ return null;
51
+ }
52
+ const pinnedWidth = pinnedItem.width + gap;
53
+ while (currentWidth + pinnedWidth > maxWidth) {
54
+ const removed = visibleItems.pop();
55
+ if (!removed) {
56
+ break;
57
+ }
58
+ if (removed.width == null) {
59
+ return null;
60
+ }
61
+ currentWidth -= removed.width + gap;
62
+ nextVisibleCount -= 1;
63
+ }
64
+ }
65
+ return Math.max(0, nextVisibleCount);
66
+ }
67
+ function partitionVisibleValues(orderedValues, visibleCount, pinnedValue) {
68
+ let visibleValues = orderedValues.slice(0, visibleCount);
69
+ let hiddenValues = orderedValues.slice(visibleCount);
70
+ const hiddenPinnedIndex = pinnedValue != null ? hiddenValues.indexOf(pinnedValue) : -1;
71
+ if (hiddenPinnedIndex !== -1) {
72
+ const pinnedHiddenValue = hiddenValues[hiddenPinnedIndex];
73
+ hiddenValues = hiddenValues.filter(
74
+ (_, index) => index !== hiddenPinnedIndex
75
+ );
76
+ if (pinnedHiddenValue !== void 0) {
77
+ visibleValues = [...visibleValues, pinnedHiddenValue];
78
+ }
79
+ }
80
+ return { visibleValues, hiddenValues };
81
+ }
82
+
83
+ exports.MIN_TRUSTED_TAB_WIDTH = MIN_TRUSTED_TAB_WIDTH;
84
+ exports.calculateVisibleCount = calculateVisibleCount;
85
+ exports.partitionVisibleValues = partitionVisibleValues;
86
+ //# sourceMappingURL=overflowMath.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overflowMath.js","sources":["../src/tabs-next/hooks/overflowMath.ts"],"sourcesContent":["export const MIN_TRUSTED_TAB_WIDTH = 0.5;\n\nexport interface MeasuredOverflowTab {\n value: string;\n width: number | null;\n}\n\ninterface CalculateVisibleCountProps {\n gap: number;\n maxWidth: number;\n overflowWidth: number;\n pinnedValue?: string;\n tabs: MeasuredOverflowTab[];\n}\n\nexport function calculateVisibleCount({\n gap,\n maxWidth: initialMaxWidth,\n overflowWidth,\n pinnedValue,\n tabs,\n}: CalculateVisibleCountProps) {\n let maxWidth = initialMaxWidth;\n let currentWidth = 0;\n let nextVisibleCount = 0;\n const visibleItems: MeasuredOverflowTab[] = [];\n\n while (nextVisibleCount < tabs.length) {\n const item = tabs[nextVisibleCount];\n if (!item) {\n break;\n }\n\n if (item.width == null) {\n return null;\n }\n\n const itemWidth = item.width + gap;\n if (currentWidth + itemWidth > maxWidth) {\n break;\n }\n\n currentWidth += itemWidth;\n visibleItems.push(item);\n nextVisibleCount += 1;\n }\n\n const allTabsFit = nextVisibleCount >= tabs.length;\n if (allTabsFit) {\n return nextVisibleCount;\n }\n\n maxWidth -= overflowWidth;\n\n while (currentWidth > maxWidth) {\n const removed = visibleItems.pop();\n if (!removed) {\n break;\n }\n if (removed.width == null) {\n return null;\n }\n currentWidth -= removed.width + gap;\n nextVisibleCount -= 1;\n }\n\n const pinnedItem =\n pinnedValue == null\n ? null\n : (tabs.find((item) => item.value === pinnedValue) ?? null);\n\n if (pinnedItem && !visibleItems.includes(pinnedItem)) {\n if (pinnedItem.width == null) {\n return null;\n }\n\n const pinnedWidth = pinnedItem.width + gap;\n while (currentWidth + pinnedWidth > maxWidth) {\n const removed = visibleItems.pop();\n if (!removed) {\n break;\n }\n if (removed.width == null) {\n return null;\n }\n currentWidth -= removed.width + gap;\n nextVisibleCount -= 1;\n }\n }\n\n return Math.max(0, nextVisibleCount);\n}\n\nexport function partitionVisibleValues(\n orderedValues: string[],\n visibleCount: number,\n pinnedValue?: string,\n) {\n let visibleValues = orderedValues.slice(0, visibleCount);\n let hiddenValues = orderedValues.slice(visibleCount);\n\n const hiddenPinnedIndex =\n pinnedValue != null ? hiddenValues.indexOf(pinnedValue) : -1;\n\n if (hiddenPinnedIndex !== -1) {\n const pinnedHiddenValue = hiddenValues[hiddenPinnedIndex];\n hiddenValues = hiddenValues.filter(\n (_, index) => index !== hiddenPinnedIndex,\n );\n if (pinnedHiddenValue !== undefined) {\n visibleValues = [...visibleValues, pinnedHiddenValue];\n }\n }\n\n return { visibleValues, hiddenValues };\n}\n"],"names":[],"mappings":"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"}
@@ -6,11 +6,19 @@ function sortBasedOnDOMPosition(items) {
6
6
  const indexedItems = items.map((item, index) => [index, item]);
7
7
  let orderChanged = false;
8
8
  indexedItems.sort(([itemAIndex, itemA], [itemBIndex, itemB]) => {
9
+ if (itemA.order != null && itemA.order >= 0 && itemB.order != null && itemB.order >= 0 && itemA.order !== itemB.order) {
10
+ if (itemA.order < itemB.order && itemAIndex > itemBIndex || itemA.order > itemB.order && itemAIndex < itemBIndex) {
11
+ orderChanged = true;
12
+ }
13
+ return itemA.order - itemB.order;
14
+ }
9
15
  const itemAElement = itemA.element;
10
16
  const itemBElement = itemB.element;
11
17
  if (itemAElement === itemBElement) return 0;
12
18
  if (!itemAElement || !itemBElement) return 0;
13
- if (itemAElement.compareDocumentPosition(itemBElement) & Node.DOCUMENT_POSITION_FOLLOWING) {
19
+ const pos = itemAElement.compareDocumentPosition(itemBElement);
20
+ if (pos & Node.DOCUMENT_POSITION_DISCONNECTED) return 0;
21
+ if (pos & Node.DOCUMENT_POSITION_FOLLOWING) {
14
22
  if (itemAIndex > itemBIndex) {
15
23
  orderChanged = true;
16
24
  }
@@ -26,64 +34,162 @@ function sortBasedOnDOMPosition(items) {
26
34
  }
27
35
  return items;
28
36
  }
29
- function useCollection({ wrap }) {
30
- const [items, setItems] = react.useState([]);
37
+ function useCollection({ wrap, targetWindow }) {
31
38
  const itemsRef = react.useRef([]);
32
39
  const itemMap = react.useRef(/* @__PURE__ */ new Map());
33
- const registerItem = react.useCallback((item) => {
34
- setItems((old) => {
35
- const newItems = old.slice();
36
- const index = newItems.findIndex(({ id }) => id === item.id);
37
- if (index !== -1) {
38
- const newItem = { ...newItems[index], ...item };
39
- newItems[index] = newItem;
40
- itemMap.current.set(item.id, newItem);
41
- } else {
42
- newItems.push(item);
43
- itemMap.current.set(item.id, item);
40
+ const removedItems = react.useRef(/* @__PURE__ */ new Map());
41
+ const [removalVersion, setRemovalVersion] = react.useState(0);
42
+ const getOrderedItems = react.useCallback(() => {
43
+ return sortBasedOnDOMPosition(Array.from(itemMap.current.values()));
44
+ }, []);
45
+ const getNavigableItems = react.useCallback(() => {
46
+ return getOrderedItems().filter((item) => {
47
+ if (item.location === "hidden") {
48
+ return false;
44
49
  }
45
- const value = sortBasedOnDOMPosition(newItems);
46
- itemsRef.current = value;
47
- return value;
50
+ return !!item.element;
48
51
  });
49
- return () => {
50
- setItems((old) => {
52
+ }, [getOrderedItems]);
53
+ const sortItems = react.useCallback(() => {
54
+ itemsRef.current = getOrderedItems();
55
+ }, [getOrderedItems]);
56
+ const getRemovedItems = react.useCallback(() => {
57
+ const items = new Map(removedItems.current);
58
+ removedItems.current.clear();
59
+ return items;
60
+ }, []);
61
+ const rafId = react.useRef(null);
62
+ const scheduleSort = react.useCallback(() => {
63
+ if (!(targetWindow == null ? void 0 : targetWindow.requestAnimationFrame)) {
64
+ sortItems();
65
+ return;
66
+ }
67
+ if (rafId.current != null) {
68
+ targetWindow.cancelAnimationFrame(rafId.current);
69
+ }
70
+ rafId.current = targetWindow.requestAnimationFrame(() => {
71
+ rafId.current = null;
72
+ sortItems();
73
+ });
74
+ }, [sortItems, targetWindow]);
75
+ const registerItem = react.useCallback(
76
+ (item) => {
77
+ itemMap.current.set(item.id, item);
78
+ removedItems.current.delete(item.id);
79
+ scheduleSort();
80
+ return () => {
81
+ const currentItems = getOrderedItems();
82
+ const currentItem = itemMap.current.get(item.id) ?? item;
83
+ const staleIndex = currentItems.findIndex(({ id }) => id === item.id);
84
+ removedItems.current.set(item.id, {
85
+ ...currentItem,
86
+ staleIndex
87
+ });
88
+ itemsRef.current = currentItems.filter(({ id }) => id !== item.id);
51
89
  itemMap.current.delete(item.id);
52
- return old.filter(({ id }) => id !== item.id);
90
+ setRemovalVersion((currentVersion) => currentVersion + 1);
91
+ };
92
+ },
93
+ [getOrderedItems, scheduleSort]
94
+ );
95
+ const updateItem = react.useCallback(
96
+ (id, updates) => {
97
+ const currentItem = itemMap.current.get(id);
98
+ if (!currentItem) {
99
+ return;
100
+ }
101
+ let changed = false;
102
+ const nextItem = { ...currentItem };
103
+ for (const [key, nextValue] of Object.entries(updates)) {
104
+ const typedKey = key;
105
+ if (nextItem[typedKey] !== nextValue) {
106
+ changed = true;
107
+ nextItem[typedKey] = nextValue;
108
+ }
109
+ }
110
+ if (!changed) {
111
+ return;
112
+ }
113
+ itemMap.current.set(id, nextItem);
114
+ itemsRef.current = itemsRef.current.map((item) => {
115
+ if (item.id !== id) {
116
+ return item;
117
+ }
118
+ return nextItem;
53
119
  });
54
- return itemsRef;
120
+ scheduleSort();
121
+ },
122
+ [scheduleSort]
123
+ );
124
+ react.useEffect(() => {
125
+ return () => {
126
+ if (rafId.current != null && targetWindow) {
127
+ targetWindow.cancelAnimationFrame(rafId.current);
128
+ }
55
129
  };
56
- }, []);
130
+ }, [targetWindow]);
57
131
  return {
58
132
  registerItem,
59
- item: (id) => {
133
+ item: react.useCallback((id) => {
60
134
  if (!id) return null;
61
135
  let item = itemMap.current.get(id);
62
136
  if (!item) {
63
- item = items.find((item2) => item2.id === id);
137
+ item = itemsRef.current.find((item2) => item2.id === id);
64
138
  if (item) {
65
139
  itemMap.current.set(item.id, item);
66
140
  }
67
141
  }
68
142
  return item ?? null;
69
- },
70
- getNext: (current) => {
71
- const index = items.findIndex(({ id }) => id === current);
72
- const newIndex = (index + 1) % items.length ;
73
- return items[newIndex] ?? null;
74
- },
75
- getPrevious: (current) => {
76
- const index = items.findIndex(({ id }) => id === current);
77
- const newIndex = (index - 1 + items.length) % items.length ;
78
- return items[newIndex] ?? null;
79
- },
80
- getFirst: () => {
81
- return items[0] ?? null;
82
- },
83
- getLast: () => {
143
+ }, []),
144
+ getNext: react.useCallback(
145
+ (current) => {
146
+ const items = getNavigableItems();
147
+ if (items.length === 0) return null;
148
+ const index = items.findIndex(({ id }) => id === current);
149
+ if (index === -1) {
150
+ return items[0] ;
151
+ }
152
+ const newIndex = (index + 1) % items.length ;
153
+ return items[newIndex] ?? null;
154
+ },
155
+ [getNavigableItems, wrap]
156
+ ),
157
+ getPrevious: react.useCallback(
158
+ (current) => {
159
+ const items = getNavigableItems();
160
+ if (items.length === 0) return null;
161
+ const index = items.findIndex(({ id }) => id === current);
162
+ if (index === -1) {
163
+ return items[items.length - 1] ;
164
+ }
165
+ const newIndex = (index - 1 + items.length) % items.length ;
166
+ return items[newIndex] ?? null;
167
+ },
168
+ [getNavigableItems, wrap]
169
+ ),
170
+ getFirst: react.useCallback(() => {
171
+ return getNavigableItems()[0] ?? null;
172
+ }, [getNavigableItems]),
173
+ getLast: react.useCallback(() => {
174
+ const items = getNavigableItems();
84
175
  return items[items.length - 1] ?? null;
85
- },
86
- items
176
+ }, [getNavigableItems]),
177
+ getIndex: react.useCallback(
178
+ (current) => {
179
+ return getNavigableItems().findIndex(({ id }) => id === current);
180
+ },
181
+ [getNavigableItems]
182
+ ),
183
+ itemAt: react.useCallback(
184
+ (index) => {
185
+ return getNavigableItems()[index] ?? null;
186
+ },
187
+ [getNavigableItems]
188
+ ),
189
+ updateItem,
190
+ getRemovedItems,
191
+ removalVersion,
192
+ sortItems
87
193
  };
88
194
  }
89
195
 
@@ -1 +1 @@
1
- {"version":3,"file":"useCollection.js","sources":["../src/tabs-next/hooks/useCollection.ts"],"sourcesContent":["import { useCallback, useRef, useState } from \"react\";\n\nexport interface Item {\n id: string;\n element?: HTMLElement | null;\n value: string;\n}\n\nfunction sortBasedOnDOMPosition(items: Item[]): Item[] {\n const indexedItems = items.map((item, index) => [index, item] as const);\n let orderChanged = false;\n indexedItems.sort(([itemAIndex, itemA], [itemBIndex, itemB]) => {\n const itemAElement = itemA.element;\n const itemBElement = itemB.element;\n if (itemAElement === itemBElement) return 0;\n if (!itemAElement || !itemBElement) return 0;\n\n if (\n itemAElement.compareDocumentPosition(itemBElement) &\n Node.DOCUMENT_POSITION_FOLLOWING\n ) {\n if (itemAIndex > itemBIndex) {\n orderChanged = true;\n }\n return -1;\n }\n\n if (itemAIndex < itemBIndex) {\n orderChanged = true;\n }\n return 1;\n });\n\n if (orderChanged) {\n return indexedItems.map(([_, item]) => item);\n }\n return items;\n}\n\ninterface UseCollectionProps {\n wrap: boolean;\n}\n\nexport function useCollection({ wrap }: UseCollectionProps) {\n const [items, setItems] = useState<Item[]>([]);\n const itemsRef = useRef<Item[]>([]);\n const itemMap = useRef<Map<string, Item>>(new Map());\n\n const registerItem = useCallback((item: Item) => {\n setItems((old) => {\n const newItems = old.slice();\n const index = newItems.findIndex(({ id }) => id === item.id);\n if (index !== -1) {\n const newItem = { ...newItems[index], ...item };\n newItems[index] = newItem;\n itemMap.current.set(item.id, newItem);\n } else {\n newItems.push(item);\n itemMap.current.set(item.id, item);\n }\n const value = sortBasedOnDOMPosition(newItems);\n itemsRef.current = value;\n return value;\n });\n\n return () => {\n setItems((old) => {\n itemMap.current.delete(item.id);\n return old.filter(({ id }) => id !== item.id);\n });\n return itemsRef;\n };\n }, []);\n\n return {\n registerItem,\n item: (id?: string | null): Item | null => {\n if (!id) return null;\n let item = itemMap.current.get(id);\n if (!item) {\n item = items.find((item) => item.id === id);\n if (item) {\n itemMap.current.set(item.id, item);\n }\n }\n return item ?? null;\n },\n getNext: (current: string): Item | null => {\n const index = items.findIndex(({ id }) => id === current);\n\n const newIndex = wrap\n ? (index + 1) % items.length\n : Math.min(index + 1, items.length - 1);\n\n return items[newIndex] ?? null;\n },\n getPrevious: (current: string): Item | null => {\n const index = items.findIndex(({ id }) => id === current);\n\n const newIndex = wrap\n ? (index - 1 + items.length) % items.length\n : Math.max(index - 1, 0);\n\n return items[newIndex] ?? null;\n },\n getFirst: (): Item | null => {\n return items[0] ?? null;\n },\n getLast: (): Item | null => {\n return items[items.length - 1] ?? null;\n },\n items,\n };\n}\n"],"names":["useState","useRef","useCallback","item"],"mappings":"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"}
1
+ {"version":3,"file":"useCollection.js","sources":["../src/tabs-next/hooks/useCollection.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\n\nexport interface Item {\n id: string;\n element?: HTMLElement | null;\n value: string;\n location?: \"hidden\" | \"main\" | \"overflow\";\n order?: number;\n stale?: boolean;\n}\n\ninterface StaleItem extends Item {\n staleIndex?: number;\n}\n\nfunction sortBasedOnDOMPosition(items: Item[]): Item[] {\n const indexedItems = items.map((item, index) => [index, item] as const);\n let orderChanged = false;\n indexedItems.sort(([itemAIndex, itemA], [itemBIndex, itemB]) => {\n if (\n itemA.order != null &&\n itemA.order >= 0 &&\n itemB.order != null &&\n itemB.order >= 0 &&\n itemA.order !== itemB.order\n ) {\n if (\n (itemA.order < itemB.order && itemAIndex > itemBIndex) ||\n (itemA.order > itemB.order && itemAIndex < itemBIndex)\n ) {\n orderChanged = true;\n }\n return itemA.order - itemB.order;\n }\n\n const itemAElement = itemA.element;\n const itemBElement = itemB.element;\n if (itemAElement === itemBElement) return 0;\n if (!itemAElement || !itemBElement) return 0;\n\n const pos = itemAElement.compareDocumentPosition(itemBElement);\n if (pos & Node.DOCUMENT_POSITION_DISCONNECTED) return 0;\n\n if (pos & Node.DOCUMENT_POSITION_FOLLOWING) {\n if (itemAIndex > itemBIndex) {\n orderChanged = true;\n }\n return -1;\n }\n\n if (itemAIndex < itemBIndex) {\n orderChanged = true;\n }\n return 1;\n });\n\n if (orderChanged) {\n return indexedItems.map(([_, item]) => item);\n }\n return items;\n}\n\ninterface UseCollectionProps {\n targetWindow: Window | null | undefined;\n wrap: boolean;\n}\n\nexport function useCollection({ wrap, targetWindow }: UseCollectionProps) {\n const itemsRef = useRef<Item[]>([]);\n const itemMap = useRef<Map<string, Item>>(new Map());\n const removedItems = useRef<Map<string, StaleItem>>(new Map());\n const [removalVersion, setRemovalVersion] = useState(0);\n\n const getOrderedItems = useCallback(() => {\n return sortBasedOnDOMPosition(Array.from(itemMap.current.values()));\n }, []);\n\n const getNavigableItems = useCallback(() => {\n return getOrderedItems().filter((item) => {\n if (item.location === \"hidden\") {\n return false;\n }\n\n return !!item.element;\n });\n }, [getOrderedItems]);\n\n const sortItems = useCallback(() => {\n itemsRef.current = getOrderedItems();\n }, [getOrderedItems]);\n\n const getRemovedItems = useCallback(() => {\n const items = new Map(removedItems.current);\n removedItems.current.clear();\n\n return items;\n }, []);\n\n const rafId = useRef<number | null>(null);\n\n const scheduleSort = useCallback(() => {\n if (!targetWindow?.requestAnimationFrame) {\n sortItems();\n return;\n }\n\n if (rafId.current != null) {\n targetWindow.cancelAnimationFrame(rafId.current);\n }\n\n rafId.current = targetWindow.requestAnimationFrame(() => {\n rafId.current = null;\n sortItems();\n });\n }, [sortItems, targetWindow]);\n\n const registerItem = useCallback(\n (item: Item) => {\n itemMap.current.set(item.id, item);\n removedItems.current.delete(item.id);\n scheduleSort();\n\n return () => {\n const currentItems = getOrderedItems();\n const currentItem = itemMap.current.get(item.id) ?? item;\n const staleIndex = currentItems.findIndex(({ id }) => id === item.id);\n\n removedItems.current.set(item.id, {\n ...currentItem,\n staleIndex,\n });\n\n itemsRef.current = currentItems.filter(({ id }) => id !== item.id);\n itemMap.current.delete(item.id);\n setRemovalVersion((currentVersion) => currentVersion + 1);\n };\n },\n [getOrderedItems, scheduleSort],\n );\n\n const updateItem = useCallback(\n (id: string, updates: Partial<Omit<Item, \"id\" | \"value\">>) => {\n const currentItem = itemMap.current.get(id);\n if (!currentItem) {\n return;\n }\n\n let changed = false;\n const nextItem = { ...currentItem };\n\n for (const [key, nextValue] of Object.entries(updates)) {\n const typedKey = key as keyof Omit<Item, \"id\" | \"value\">;\n if (nextItem[typedKey] !== nextValue) {\n changed = true;\n nextItem[typedKey] = nextValue as never;\n }\n }\n\n if (!changed) {\n return;\n }\n\n itemMap.current.set(id, nextItem);\n itemsRef.current = itemsRef.current.map((item) => {\n if (item.id !== id) {\n return item;\n }\n\n return nextItem;\n });\n scheduleSort();\n },\n [scheduleSort],\n );\n\n useEffect(() => {\n return () => {\n if (rafId.current != null && targetWindow) {\n targetWindow.cancelAnimationFrame(rafId.current);\n }\n };\n }, [targetWindow]);\n\n return {\n registerItem,\n item: useCallback((id?: string | null): Item | null => {\n if (!id) return null;\n let item = itemMap.current.get(id);\n if (!item) {\n item = itemsRef.current.find((item) => item.id === id);\n if (item) {\n itemMap.current.set(item.id, item);\n }\n }\n return item ?? null;\n }, []),\n getNext: useCallback(\n (current: string): Item | null => {\n const items = getNavigableItems();\n if (items.length === 0) return null;\n\n const index = items.findIndex(({ id }) => id === current);\n\n if (index === -1) {\n return wrap ? items[0] : null;\n }\n\n const newIndex = wrap\n ? (index + 1) % items.length\n : Math.min(index + 1, items.length - 1);\n\n return items[newIndex] ?? null;\n },\n [getNavigableItems, wrap],\n ),\n getPrevious: useCallback(\n (current: string): Item | null => {\n const items = getNavigableItems();\n if (items.length === 0) return null;\n\n const index = items.findIndex(({ id }) => id === current);\n\n if (index === -1) {\n return wrap ? items[items.length - 1] : null;\n }\n\n const newIndex = wrap\n ? (index - 1 + items.length) % items.length\n : Math.max(index - 1, 0);\n\n return items[newIndex] ?? null;\n },\n [getNavigableItems, wrap],\n ),\n getFirst: useCallback((): Item | null => {\n return getNavigableItems()[0] ?? null;\n }, [getNavigableItems]),\n getLast: useCallback((): Item | null => {\n const items = getNavigableItems();\n return items[items.length - 1] ?? null;\n }, [getNavigableItems]),\n getIndex: useCallback(\n (current: string): number => {\n return getNavigableItems().findIndex(({ id }) => id === current);\n },\n [getNavigableItems],\n ),\n itemAt: useCallback(\n (index: number): Item | null => {\n return getNavigableItems()[index] ?? null;\n },\n [getNavigableItems],\n ),\n updateItem,\n getRemovedItems,\n removalVersion,\n sortItems,\n };\n}\n"],"names":["useRef","useState","useCallback","useEffect","item"],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+
5
+ function useFocusWithRetry({
6
+ maxAttempts = 120,
7
+ targetWindow
8
+ }) {
9
+ const focusRafRef = react.useRef(null);
10
+ const cancelScheduledFocus = react.useCallback(() => {
11
+ if (focusRafRef.current != null && targetWindow) {
12
+ targetWindow.cancelAnimationFrame(focusRafRef.current);
13
+ focusRafRef.current = null;
14
+ }
15
+ }, [targetWindow]);
16
+ const focusElementWithRetry = react.useCallback(
17
+ (getElement) => {
18
+ var _a;
19
+ const doc = targetWindow == null ? void 0 : targetWindow.document;
20
+ if (!doc) {
21
+ (_a = getElement()) == null ? void 0 : _a.focus({ preventScroll: true });
22
+ return;
23
+ }
24
+ cancelScheduledFocus();
25
+ let attempts = 0;
26
+ const focusElement = () => {
27
+ const element = getElement();
28
+ if (!(element == null ? void 0 : element.isConnected)) {
29
+ if (attempts >= maxAttempts || !(targetWindow == null ? void 0 : targetWindow.requestAnimationFrame)) {
30
+ return;
31
+ }
32
+ attempts += 1;
33
+ focusRafRef.current = targetWindow.requestAnimationFrame(focusElement);
34
+ return;
35
+ }
36
+ element.focus({ preventScroll: true });
37
+ if (doc.activeElement === element || attempts >= maxAttempts) {
38
+ focusRafRef.current = null;
39
+ return;
40
+ }
41
+ attempts += 1;
42
+ if (targetWindow == null ? void 0 : targetWindow.requestAnimationFrame) {
43
+ focusRafRef.current = targetWindow.requestAnimationFrame(focusElement);
44
+ } else {
45
+ queueMicrotask(focusElement);
46
+ }
47
+ };
48
+ focusElement();
49
+ },
50
+ [cancelScheduledFocus, maxAttempts, targetWindow]
51
+ );
52
+ react.useEffect(() => {
53
+ return () => {
54
+ cancelScheduledFocus();
55
+ };
56
+ }, [cancelScheduledFocus]);
57
+ return {
58
+ cancelScheduledFocus,
59
+ focusElementWithRetry
60
+ };
61
+ }
62
+
63
+ exports.useFocusWithRetry = useFocusWithRetry;
64
+ //# sourceMappingURL=useFocusWithRetry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFocusWithRetry.js","sources":["../src/tabs-next/hooks/useFocusWithRetry.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from \"react\";\n\ninterface UseFocusWithRetryArgs {\n maxAttempts?: number;\n targetWindow: Window | null | undefined;\n}\n\nexport function useFocusWithRetry({\n maxAttempts = 120,\n targetWindow,\n}: UseFocusWithRetryArgs) {\n const focusRafRef = useRef<number | null>(null);\n\n const cancelScheduledFocus = useCallback(() => {\n if (focusRafRef.current != null && targetWindow) {\n targetWindow.cancelAnimationFrame(focusRafRef.current);\n focusRafRef.current = null;\n }\n }, [targetWindow]);\n\n const focusElementWithRetry = useCallback(\n (getElement: () => HTMLElement | null | undefined) => {\n const doc = targetWindow?.document;\n if (!doc) {\n getElement()?.focus({ preventScroll: true });\n return;\n }\n\n cancelScheduledFocus();\n\n let attempts = 0;\n\n const focusElement = () => {\n const element = getElement();\n if (!element?.isConnected) {\n if (attempts >= maxAttempts || !targetWindow?.requestAnimationFrame) {\n return;\n }\n\n attempts += 1;\n focusRafRef.current =\n targetWindow.requestAnimationFrame(focusElement);\n return;\n }\n\n element.focus({ preventScroll: true });\n\n if (doc.activeElement === element || attempts >= maxAttempts) {\n focusRafRef.current = null;\n return;\n }\n\n attempts += 1;\n if (targetWindow?.requestAnimationFrame) {\n focusRafRef.current =\n targetWindow.requestAnimationFrame(focusElement);\n } else {\n queueMicrotask(focusElement);\n }\n };\n\n focusElement();\n },\n [cancelScheduledFocus, maxAttempts, targetWindow],\n );\n\n useEffect(() => {\n return () => {\n cancelScheduledFocus();\n };\n }, [cancelScheduledFocus]);\n\n return {\n cancelScheduledFocus,\n focusElementWithRetry,\n };\n}\n"],"names":["useRef","useCallback","useEffect"],"mappings":";;;;AAOO,SAAS,iBAAA,CAAkB;AAAA,EAChC,WAAA,GAAc,GAAA;AAAA,EACd;AACF,CAAA,EAA0B;AACxB,EAAA,MAAM,WAAA,GAAcA,aAAsB,IAAI,CAAA;AAE9C,EAAA,MAAM,oBAAA,GAAuBC,kBAAY,MAAM;AAC7C,IAAA,IAAI,WAAA,CAAY,OAAA,IAAW,IAAA,IAAQ,YAAA,EAAc;AAC/C,MAAA,YAAA,CAAa,oBAAA,CAAqB,YAAY,OAAO,CAAA;AACrD,MAAA,WAAA,CAAY,OAAA,GAAU,IAAA;AAAA,IACxB;AAAA,EACF,CAAA,EAAG,CAAC,YAAY,CAAC,CAAA;AAEjB,EAAA,MAAM,qBAAA,GAAwBA,iBAAA;AAAA,IAC5B,CAAC,UAAA,KAAqD;AArB1D,MAAA,IAAA,EAAA;AAsBM,MAAA,MAAM,MAAM,YAAA,IAAA,IAAA,GAAA,MAAA,GAAA,YAAA,CAAc,QAAA;AAC1B,MAAA,IAAI,CAAC,GAAA,EAAK;AACR,QAAA,CAAA,EAAA,GAAA,UAAA,EAAW,KAAX,IAAA,GAAA,MAAA,GAAA,EAAA,CAAc,KAAA,CAAM,EAAE,eAAe,IAAA,EAAK,CAAA;AAC1C,QAAA;AAAA,MACF;AAEA,MAAA,oBAAA,EAAqB;AAErB,MAAA,IAAI,QAAA,GAAW,CAAA;AAEf,MAAA,MAAM,eAAe,MAAM;AACzB,QAAA,MAAM,UAAU,UAAA,EAAW;AAC3B,QAAA,IAAI,EAAC,mCAAS,WAAA,CAAA,EAAa;AACzB,UAAA,IAAI,QAAA,IAAY,WAAA,IAAe,EAAC,YAAA,IAAA,IAAA,GAAA,MAAA,GAAA,YAAA,CAAc,qBAAA,CAAA,EAAuB;AACnE,YAAA;AAAA,UACF;AAEA,UAAA,QAAA,IAAY,CAAA;AACZ,UAAA,WAAA,CAAY,OAAA,GACV,YAAA,CAAa,qBAAA,CAAsB,YAAY,CAAA;AACjD,UAAA;AAAA,QACF;AAEA,QAAA,OAAA,CAAQ,KAAA,CAAM,EAAE,aAAA,EAAe,IAAA,EAAM,CAAA;AAErC,QAAA,IAAI,GAAA,CAAI,aAAA,KAAkB,OAAA,IAAW,QAAA,IAAY,WAAA,EAAa;AAC5D,UAAA,WAAA,CAAY,OAAA,GAAU,IAAA;AACtB,UAAA;AAAA,QACF;AAEA,QAAA,QAAA,IAAY,CAAA;AACZ,QAAA,IAAI,6CAAc,qBAAA,EAAuB;AACvC,UAAA,WAAA,CAAY,OAAA,GACV,YAAA,CAAa,qBAAA,CAAsB,YAAY,CAAA;AAAA,QACnD,CAAA,MAAO;AACL,UAAA,cAAA,CAAe,YAAY,CAAA;AAAA,QAC7B;AAAA,MACF,CAAA;AAEA,MAAA,YAAA,EAAa;AAAA,IACf,CAAA;AAAA,IACA,CAAC,oBAAA,EAAsB,WAAA,EAAa,YAAY;AAAA,GAClD;AAEA,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,OAAO,MAAM;AACX,MAAA,oBAAA,EAAqB;AAAA,IACvB,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,oBAAoB,CAAC,CAAA;AAEzB,EAAA,OAAO;AAAA,IACL,oBAAA;AAAA,IACA;AAAA,GACF;AACF;;;;"}