@salt-ds/core 1.59.1 → 1.61.0

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 (233) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/css/salt-core.css +366 -1
  3. package/dist-cjs/aria-announcer/AriaAnnounce.js +15 -3
  4. package/dist-cjs/aria-announcer/AriaAnnounce.js.map +1 -1
  5. package/dist-cjs/aria-announcer/AriaAnnouncerContext.js.map +1 -1
  6. package/dist-cjs/aria-announcer/AriaAnnouncerProvider.js +65 -43
  7. package/dist-cjs/aria-announcer/AriaAnnouncerProvider.js.map +1 -1
  8. package/dist-cjs/aria-announcer/announcementRegistry.js +31 -0
  9. package/dist-cjs/aria-announcer/announcementRegistry.js.map +1 -0
  10. package/dist-cjs/aria-announcer/useAriaAnnouncer.js +44 -16
  11. package/dist-cjs/aria-announcer/useAriaAnnouncer.js.map +1 -1
  12. package/dist-cjs/index.js +17 -1
  13. package/dist-cjs/index.js.map +1 -1
  14. package/dist-cjs/navigation-item/NavigationItem.js +2 -0
  15. package/dist-cjs/navigation-item/NavigationItem.js.map +1 -1
  16. package/dist-cjs/pagination/Pagination.js +1 -0
  17. package/dist-cjs/pagination/Pagination.js.map +1 -1
  18. package/dist-cjs/rating/Rating.css.js +6 -0
  19. package/dist-cjs/rating/Rating.css.js.map +1 -0
  20. package/dist-cjs/rating/Rating.js +140 -0
  21. package/dist-cjs/rating/Rating.js.map +1 -0
  22. package/dist-cjs/rating/RatingItem.css.js +6 -0
  23. package/dist-cjs/rating/RatingItem.css.js.map +1 -0
  24. package/dist-cjs/rating/RatingItem.js +75 -0
  25. package/dist-cjs/rating/RatingItem.js.map +1 -0
  26. package/dist-cjs/salt-provider/SaltProvider.js +3 -1
  27. package/dist-cjs/salt-provider/SaltProvider.js.map +1 -1
  28. package/dist-cjs/semantic-icon-provider/SemanticIconProvider.js +22 -20
  29. package/dist-cjs/semantic-icon-provider/SemanticIconProvider.js.map +1 -1
  30. package/dist-cjs/spinner/Spinner.js +1 -0
  31. package/dist-cjs/spinner/Spinner.js.map +1 -1
  32. package/dist-cjs/tabs/Tab.css.js +6 -0
  33. package/dist-cjs/tabs/Tab.css.js.map +1 -0
  34. package/dist-cjs/tabs/Tab.js +211 -0
  35. package/dist-cjs/tabs/Tab.js.map +1 -0
  36. package/dist-cjs/tabs/TabAction.js +63 -0
  37. package/dist-cjs/tabs/TabAction.js.map +1 -0
  38. package/dist-cjs/tabs/TabBar.css.js +6 -0
  39. package/dist-cjs/tabs/TabBar.css.js.map +1 -0
  40. package/dist-cjs/tabs/TabBar.js +45 -0
  41. package/dist-cjs/tabs/TabBar.js.map +1 -0
  42. package/dist-cjs/tabs/TabList.css.js +6 -0
  43. package/dist-cjs/tabs/TabList.css.js.map +1 -0
  44. package/dist-cjs/tabs/TabList.js +281 -0
  45. package/dist-cjs/tabs/TabList.js.map +1 -0
  46. package/dist-cjs/tabs/TabPanel.css.js +6 -0
  47. package/dist-cjs/tabs/TabPanel.css.js.map +1 -0
  48. package/dist-cjs/tabs/TabPanel.js +98 -0
  49. package/dist-cjs/tabs/TabPanel.js.map +1 -0
  50. package/dist-cjs/tabs/TabTrigger.css.js +6 -0
  51. package/dist-cjs/tabs/TabTrigger.css.js.map +1 -0
  52. package/dist-cjs/tabs/TabTrigger.js +188 -0
  53. package/dist-cjs/tabs/TabTrigger.js.map +1 -0
  54. package/dist-cjs/tabs/Tabs.css.js +6 -0
  55. package/dist-cjs/tabs/Tabs.css.js.map +1 -0
  56. package/dist-cjs/tabs/Tabs.js +200 -0
  57. package/dist-cjs/tabs/Tabs.js.map +1 -0
  58. package/dist-cjs/tabs/internal/contexts/TabContext.js +26 -0
  59. package/dist-cjs/tabs/internal/contexts/TabContext.js.map +1 -0
  60. package/dist-cjs/tabs/internal/contexts/TabListLayoutContext.js +19 -0
  61. package/dist-cjs/tabs/internal/contexts/TabListLayoutContext.js.map +1 -0
  62. package/dist-cjs/tabs/internal/contexts/TabSlotRegistryContext.js +22 -0
  63. package/dist-cjs/tabs/internal/contexts/TabSlotRegistryContext.js.map +1 -0
  64. package/dist-cjs/tabs/internal/contexts/TabsContext.js +50 -0
  65. package/dist-cjs/tabs/internal/contexts/TabsContext.js.map +1 -0
  66. package/dist-cjs/tabs/internal/hooks/useFocusWithRetry.js +64 -0
  67. package/dist-cjs/tabs/internal/hooks/useFocusWithRetry.js.map +1 -0
  68. package/dist-cjs/tabs/internal/hooks/useTabListRecovery.js +76 -0
  69. package/dist-cjs/tabs/internal/hooks/useTabListRecovery.js.map +1 -0
  70. package/dist-cjs/tabs/internal/hooks/useTabRemovalHandler.js +165 -0
  71. package/dist-cjs/tabs/internal/hooks/useTabRemovalHandler.js.map +1 -0
  72. package/dist-cjs/tabs/internal/hooks/useTabSelectionFocus.js +87 -0
  73. package/dist-cjs/tabs/internal/hooks/useTabSelectionFocus.js.map +1 -0
  74. package/dist-cjs/tabs/internal/overflow/TabOverflowList.css.js +6 -0
  75. package/dist-cjs/tabs/internal/overflow/TabOverflowList.css.js.map +1 -0
  76. package/dist-cjs/tabs/internal/overflow/TabOverflowList.js +245 -0
  77. package/dist-cjs/tabs/internal/overflow/TabOverflowList.js.map +1 -0
  78. package/dist-cjs/tabs/internal/overflow/TabSlot.js +30 -0
  79. package/dist-cjs/tabs/internal/overflow/TabSlot.js.map +1 -0
  80. package/dist-cjs/tabs/internal/overflow/overflowMath.js +86 -0
  81. package/dist-cjs/tabs/internal/overflow/overflowMath.js.map +1 -0
  82. package/dist-cjs/tabs/internal/overflow/useOverflow.js +273 -0
  83. package/dist-cjs/tabs/internal/overflow/useOverflow.js.map +1 -0
  84. package/dist-cjs/tabs/internal/overflow/useOverflowLayoutState.js +99 -0
  85. package/dist-cjs/tabs/internal/overflow/useOverflowLayoutState.js.map +1 -0
  86. package/dist-cjs/tabs/internal/overflow/useOverflowSelectionState.js +68 -0
  87. package/dist-cjs/tabs/internal/overflow/useOverflowSelectionState.js.map +1 -0
  88. package/dist-cjs/tabs/internal/overflow/useRenderedTabWidth.js +92 -0
  89. package/dist-cjs/tabs/internal/overflow/useRenderedTabWidth.js.map +1 -0
  90. package/dist-cjs/tabs/internal/overflow/widthMeasurement.js +42 -0
  91. package/dist-cjs/tabs/internal/overflow/widthMeasurement.js.map +1 -0
  92. package/dist-cjs/tabs/internal/registry/useCollection.js +197 -0
  93. package/dist-cjs/tabs/internal/registry/useCollection.js.map +1 -0
  94. package/dist-cjs/tabs/internal/registry/useRenderedTabsRegistry.js +206 -0
  95. package/dist-cjs/tabs/internal/registry/useRenderedTabsRegistry.js.map +1 -0
  96. package/dist-cjs/tabs/internal/utils/domUtils.js +13 -0
  97. package/dist-cjs/tabs/internal/utils/domUtils.js.map +1 -0
  98. package/dist-cjs/tooltip/useAriaAnnounce.js +1 -0
  99. package/dist-cjs/tooltip/useAriaAnnounce.js.map +1 -1
  100. package/dist-es/aria-announcer/AriaAnnounce.js +15 -3
  101. package/dist-es/aria-announcer/AriaAnnounce.js.map +1 -1
  102. package/dist-es/aria-announcer/AriaAnnouncerContext.js.map +1 -1
  103. package/dist-es/aria-announcer/AriaAnnouncerProvider.js +67 -45
  104. package/dist-es/aria-announcer/AriaAnnouncerProvider.js.map +1 -1
  105. package/dist-es/aria-announcer/announcementRegistry.js +28 -0
  106. package/dist-es/aria-announcer/announcementRegistry.js.map +1 -0
  107. package/dist-es/aria-announcer/useAriaAnnouncer.js +45 -17
  108. package/dist-es/aria-announcer/useAriaAnnouncer.js.map +1 -1
  109. package/dist-es/index.js +9 -1
  110. package/dist-es/index.js.map +1 -1
  111. package/dist-es/navigation-item/NavigationItem.js +2 -0
  112. package/dist-es/navigation-item/NavigationItem.js.map +1 -1
  113. package/dist-es/pagination/Pagination.js +1 -0
  114. package/dist-es/pagination/Pagination.js.map +1 -1
  115. package/dist-es/rating/Rating.css.js +4 -0
  116. package/dist-es/rating/Rating.css.js.map +1 -0
  117. package/dist-es/rating/Rating.js +138 -0
  118. package/dist-es/rating/Rating.js.map +1 -0
  119. package/dist-es/rating/RatingItem.css.js +4 -0
  120. package/dist-es/rating/RatingItem.css.js.map +1 -0
  121. package/dist-es/rating/RatingItem.js +73 -0
  122. package/dist-es/rating/RatingItem.js.map +1 -0
  123. package/dist-es/salt-provider/SaltProvider.js +3 -1
  124. package/dist-es/salt-provider/SaltProvider.js.map +1 -1
  125. package/dist-es/semantic-icon-provider/SemanticIconProvider.js +23 -21
  126. package/dist-es/semantic-icon-provider/SemanticIconProvider.js.map +1 -1
  127. package/dist-es/spinner/Spinner.js +1 -0
  128. package/dist-es/spinner/Spinner.js.map +1 -1
  129. package/dist-es/tabs/Tab.css.js +4 -0
  130. package/dist-es/tabs/Tab.css.js.map +1 -0
  131. package/dist-es/tabs/Tab.js +209 -0
  132. package/dist-es/tabs/Tab.js.map +1 -0
  133. package/dist-es/tabs/TabAction.js +61 -0
  134. package/dist-es/tabs/TabAction.js.map +1 -0
  135. package/dist-es/tabs/TabBar.css.js +4 -0
  136. package/dist-es/tabs/TabBar.css.js.map +1 -0
  137. package/dist-es/tabs/TabBar.js +43 -0
  138. package/dist-es/tabs/TabBar.js.map +1 -0
  139. package/dist-es/tabs/TabList.css.js +4 -0
  140. package/dist-es/tabs/TabList.css.js.map +1 -0
  141. package/dist-es/tabs/TabList.js +279 -0
  142. package/dist-es/tabs/TabList.js.map +1 -0
  143. package/dist-es/tabs/TabPanel.css.js +4 -0
  144. package/dist-es/tabs/TabPanel.css.js.map +1 -0
  145. package/dist-es/tabs/TabPanel.js +96 -0
  146. package/dist-es/tabs/TabPanel.js.map +1 -0
  147. package/dist-es/tabs/TabTrigger.css.js +4 -0
  148. package/dist-es/tabs/TabTrigger.css.js.map +1 -0
  149. package/dist-es/tabs/TabTrigger.js +186 -0
  150. package/dist-es/tabs/TabTrigger.js.map +1 -0
  151. package/dist-es/tabs/Tabs.css.js +4 -0
  152. package/dist-es/tabs/Tabs.css.js.map +1 -0
  153. package/dist-es/tabs/Tabs.js +198 -0
  154. package/dist-es/tabs/Tabs.js.map +1 -0
  155. package/dist-es/tabs/internal/contexts/TabContext.js +23 -0
  156. package/dist-es/tabs/internal/contexts/TabContext.js.map +1 -0
  157. package/dist-es/tabs/internal/contexts/TabListLayoutContext.js +16 -0
  158. package/dist-es/tabs/internal/contexts/TabListLayoutContext.js.map +1 -0
  159. package/dist-es/tabs/internal/contexts/TabSlotRegistryContext.js +19 -0
  160. package/dist-es/tabs/internal/contexts/TabSlotRegistryContext.js.map +1 -0
  161. package/dist-es/tabs/internal/contexts/TabsContext.js +47 -0
  162. package/dist-es/tabs/internal/contexts/TabsContext.js.map +1 -0
  163. package/dist-es/tabs/internal/hooks/useFocusWithRetry.js +62 -0
  164. package/dist-es/tabs/internal/hooks/useFocusWithRetry.js.map +1 -0
  165. package/dist-es/tabs/internal/hooks/useTabListRecovery.js +74 -0
  166. package/dist-es/tabs/internal/hooks/useTabListRecovery.js.map +1 -0
  167. package/dist-es/tabs/internal/hooks/useTabRemovalHandler.js +163 -0
  168. package/dist-es/tabs/internal/hooks/useTabRemovalHandler.js.map +1 -0
  169. package/dist-es/tabs/internal/hooks/useTabSelectionFocus.js +85 -0
  170. package/dist-es/tabs/internal/hooks/useTabSelectionFocus.js.map +1 -0
  171. package/dist-es/tabs/internal/overflow/TabOverflowList.css.js +4 -0
  172. package/dist-es/tabs/internal/overflow/TabOverflowList.css.js.map +1 -0
  173. package/dist-es/tabs/internal/overflow/TabOverflowList.js +243 -0
  174. package/dist-es/tabs/internal/overflow/TabOverflowList.js.map +1 -0
  175. package/dist-es/tabs/internal/overflow/TabSlot.js +28 -0
  176. package/dist-es/tabs/internal/overflow/TabSlot.js.map +1 -0
  177. package/dist-es/tabs/internal/overflow/overflowMath.js +82 -0
  178. package/dist-es/tabs/internal/overflow/overflowMath.js.map +1 -0
  179. package/dist-es/tabs/internal/overflow/useOverflow.js +271 -0
  180. package/dist-es/tabs/internal/overflow/useOverflow.js.map +1 -0
  181. package/dist-es/tabs/internal/overflow/useOverflowLayoutState.js +97 -0
  182. package/dist-es/tabs/internal/overflow/useOverflowLayoutState.js.map +1 -0
  183. package/dist-es/tabs/internal/overflow/useOverflowSelectionState.js +66 -0
  184. package/dist-es/tabs/internal/overflow/useOverflowSelectionState.js.map +1 -0
  185. package/dist-es/tabs/internal/overflow/useRenderedTabWidth.js +90 -0
  186. package/dist-es/tabs/internal/overflow/useRenderedTabWidth.js.map +1 -0
  187. package/dist-es/tabs/internal/overflow/widthMeasurement.js +36 -0
  188. package/dist-es/tabs/internal/overflow/widthMeasurement.js.map +1 -0
  189. package/dist-es/tabs/internal/registry/useCollection.js +195 -0
  190. package/dist-es/tabs/internal/registry/useCollection.js.map +1 -0
  191. package/dist-es/tabs/internal/registry/useRenderedTabsRegistry.js +204 -0
  192. package/dist-es/tabs/internal/registry/useRenderedTabsRegistry.js.map +1 -0
  193. package/dist-es/tabs/internal/utils/domUtils.js +11 -0
  194. package/dist-es/tabs/internal/utils/domUtils.js.map +1 -0
  195. package/dist-es/tooltip/useAriaAnnounce.js +1 -0
  196. package/dist-es/tooltip/useAriaAnnounce.js.map +1 -1
  197. package/dist-types/aria-announcer/AriaAnnounce.d.ts +9 -2
  198. package/dist-types/aria-announcer/AriaAnnouncerContext.d.ts +26 -2
  199. package/dist-types/aria-announcer/AriaAnnouncerProvider.d.ts +6 -7
  200. package/dist-types/aria-announcer/announcementRegistry.d.ts +5 -0
  201. package/dist-types/index.d.ts +2 -0
  202. package/dist-types/rating/Rating.d.ts +48 -0
  203. package/dist-types/rating/RatingItem.d.ts +47 -0
  204. package/dist-types/rating/index.d.ts +1 -0
  205. package/dist-types/semantic-icon-provider/SemanticIconProvider.d.ts +21 -19
  206. package/dist-types/tabs/Tab.d.ts +12 -0
  207. package/dist-types/tabs/TabAction.d.ts +4 -0
  208. package/dist-types/tabs/TabBar.d.ts +12 -0
  209. package/dist-types/tabs/TabList.d.ts +12 -0
  210. package/dist-types/tabs/TabPanel.d.ts +9 -0
  211. package/dist-types/tabs/TabTrigger.d.ts +4 -0
  212. package/dist-types/tabs/Tabs.d.ts +20 -0
  213. package/dist-types/tabs/index.d.ts +7 -0
  214. package/dist-types/tabs/internal/contexts/TabContext.d.ts +12 -0
  215. package/dist-types/tabs/internal/contexts/TabListLayoutContext.d.ts +9 -0
  216. package/dist-types/tabs/internal/contexts/TabSlotRegistryContext.d.ts +5 -0
  217. package/dist-types/tabs/internal/contexts/TabsContext.d.ts +43 -0
  218. package/dist-types/tabs/internal/hooks/useFocusWithRetry.d.ts +9 -0
  219. package/dist-types/tabs/internal/hooks/useTabListRecovery.d.ts +12 -0
  220. package/dist-types/tabs/internal/hooks/useTabRemovalHandler.d.ts +32 -0
  221. package/dist-types/tabs/internal/hooks/useTabSelectionFocus.d.ts +15 -0
  222. package/dist-types/tabs/internal/overflow/TabOverflowList.d.ts +10 -0
  223. package/dist-types/tabs/internal/overflow/TabSlot.d.ts +6 -0
  224. package/dist-types/tabs/internal/overflow/overflowMath.d.ts +18 -0
  225. package/dist-types/tabs/internal/overflow/useOverflow.d.ts +11 -0
  226. package/dist-types/tabs/internal/overflow/useOverflowLayoutState.d.ts +13 -0
  227. package/dist-types/tabs/internal/overflow/useOverflowSelectionState.d.ts +13 -0
  228. package/dist-types/tabs/internal/overflow/useRenderedTabWidth.d.ts +12 -0
  229. package/dist-types/tabs/internal/overflow/widthMeasurement.d.ts +5 -0
  230. package/dist-types/tabs/internal/registry/useCollection.d.ts +30 -0
  231. package/dist-types/tabs/internal/registry/useRenderedTabsRegistry.d.ts +12 -0
  232. package/dist-types/tabs/internal/utils/domUtils.d.ts +1 -0
  233. package/package.json +3 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useOverflow.js","sources":["../src/tabs/internal/overflow/useOverflow.ts"],"sourcesContent":["import {\n type MutableRefObject,\n type RefObject,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { ownerWindow, useIsomorphicLayoutEffect } from \"../../../utils\";\nimport type { RenderedTab } from \"../contexts/TabsContext\";\nimport { isHTMLElement } from \"../utils/domUtils\";\nimport {\n calculateVisibleCount,\n MIN_TRUSTED_TAB_WIDTH,\n partitionVisibleValues,\n} from \"./overflowMath\";\nimport {\n getGapValue,\n getMeasuredWidth,\n seedWidthMap,\n updateWidthMap,\n} from \"./widthMeasurement\";\n\ninterface UseOverflowProps {\n container: RefObject<HTMLElement>;\n selected?: string;\n tabs: RenderedTab[];\n overflowButton: RefObject<HTMLButtonElement>;\n menuOpen: boolean;\n}\n\nfunction getTabWidth(tab: RenderedTab) {\n const width = tab.width || getMeasuredWidth(tab.root);\n return width > MIN_TRUSTED_TAB_WIDTH ? width : null;\n}\n\nfunction getAvailableWidth(element: HTMLElement) {\n const parent = element.parentElement;\n if (!parent) {\n return getMeasuredWidth(element);\n }\n\n const parentWidth = getMeasuredWidth(parent);\n const parentStyles = ownerWindow(parent).getComputedStyle(parent);\n const parentGap = getGapValue(parentStyles);\n const siblings = Array.from(parent.children).filter(\n (child): child is HTMLElement => {\n if (!isHTMLElement(child) || child === element) {\n return false;\n }\n\n return ownerWindow(child).getComputedStyle(child).display !== \"none\";\n },\n );\n\n const siblingWidth = siblings.reduce((width, sibling) => {\n return width + getMeasuredWidth(sibling);\n }, 0);\n const gapCount = siblings.length > 0 ? siblings.length : 0;\n const availableWidth = Math.max(\n 0,\n parentWidth - siblingWidth - gapCount * parentGap,\n );\n return availableWidth;\n}\n\nfunction isSelectedValueHidden(\n selected: string | undefined,\n hiddenValues: string[],\n) {\n return selected !== undefined && hiddenValues.includes(selected);\n}\n\nfunction getPinnedSelectionValue(\n selected: string | undefined,\n selectedIsHidden: boolean,\n pinnedSelectionRef: MutableRefObject<string | undefined>,\n) {\n return selectedIsHidden ? selected : pinnedSelectionRef.current;\n}\n\nexport function useOverflow({\n container,\n overflowButton,\n tabs,\n selected,\n menuOpen,\n}: UseOverflowProps) {\n const orderedValues = useMemo(() => tabs.map((tab) => tab.value), [tabs]);\n const measurementInputKey = useMemo(() => {\n return tabs.map((tab) => `${tab.value}:${tab.width.toFixed(2)}`).join(\"\\0\");\n }, [tabs]);\n const [visibleCount, setVisibleCount] = useState(0);\n const [isMeasuring, setIsMeasuring] = useState(true);\n const [measureRetryVersion, setMeasureRetryVersion] = useState(0);\n const pinnedSelectionRef = useRef(selected);\n const previousOverflowButtonWidthRef = useRef(0);\n const previousMeasurementInputKeyRef = useRef(measurementInputKey);\n const previousMenuOpenRef = useRef(menuOpen);\n const measureRetryFrameRef = useRef<number | null>(null);\n const measureRetryCountRef = useRef(0);\n const baseHiddenValues = orderedValues.slice(visibleCount);\n const selectedIsHidden = isSelectedValueHidden(selected, baseHiddenValues);\n const pinnedValue = getPinnedSelectionValue(\n selected,\n selectedIsHidden,\n pinnedSelectionRef,\n );\n const getCurrentPinnedValue = useCallback(() => {\n return getPinnedSelectionValue(\n selected,\n selectedIsHidden,\n pinnedSelectionRef,\n );\n }, [selected, selectedIsHidden]);\n const markMeasurementStale = useCallback(() => {\n setIsMeasuring(true);\n }, []);\n\n const measureVisibleCount = useCallback(\n (pinnedValue?: string) => {\n const element = container.current;\n if (!element) {\n return null;\n }\n\n const maxWidth = getAvailableWidth(element);\n const styles = ownerWindow(element).getComputedStyle(element);\n const gap = getGapValue(styles);\n const overflowWidth = overflowButton.current\n ? overflowButton.current.offsetWidth + gap\n : 0;\n const measuredTabs = tabs.map((tab) => ({\n value: tab.value,\n width: getTabWidth(tab),\n }));\n\n return calculateVisibleCount({\n gap,\n maxWidth,\n overflowWidth,\n pinnedValue,\n tabs: measuredTabs,\n });\n },\n [container, overflowButton, tabs],\n );\n const clearMeasureRetry = useCallback(() => {\n const element = container.current;\n const frame = measureRetryFrameRef.current;\n\n if (element && frame != null) {\n ownerWindow(element).cancelAnimationFrame(frame);\n }\n\n measureRetryFrameRef.current = null;\n measureRetryCountRef.current = 0;\n }, [container]);\n\n useEffect(() => {\n return clearMeasureRetry;\n }, [clearMeasureRetry]);\n\n useIsomorphicLayoutEffect(() => {\n if (selected !== undefined && selectedIsHidden) {\n pinnedSelectionRef.current = selected;\n const nextVisibleCount = measureVisibleCount(selected);\n if (nextVisibleCount == null) {\n markMeasurementStale();\n return;\n }\n if (nextVisibleCount !== visibleCount) {\n setVisibleCount(nextVisibleCount);\n }\n if (isMeasuring) {\n setIsMeasuring(false);\n }\n }\n }, [\n isMeasuring,\n markMeasurementStale,\n measureVisibleCount,\n selected,\n selectedIsHidden,\n visibleCount,\n ]);\n\n useEffect(() => {\n const element = container.current;\n if (!element || menuOpen || isMeasuring) {\n return;\n }\n\n const observedElements = [element];\n const parent = element.parentElement;\n if (parent) {\n observedElements.push(parent);\n for (const child of Array.from(parent.children)) {\n if (isHTMLElement(child) && child !== element) {\n observedElements.push(child);\n }\n }\n }\n\n const widths = seedWidthMap(observedElements);\n const resizeObserverCtor = ownerWindow(element).ResizeObserver;\n if (!resizeObserverCtor) {\n return;\n }\n\n const resizeObserver = new resizeObserverCtor(\n (entries: ResizeObserverEntry[]) => {\n for (const entry of entries) {\n if (!isHTMLElement(entry.target)) {\n continue;\n }\n\n const nextWidth = entry.contentRect.width;\n if (updateWidthMap(widths, entry.target, nextWidth)) {\n const nextVisibleCount = measureVisibleCount(\n getCurrentPinnedValue(),\n );\n\n if (nextVisibleCount != null && nextVisibleCount === visibleCount) {\n continue;\n }\n\n markMeasurementStale();\n return;\n }\n }\n },\n );\n\n for (const observedElement of observedElements) {\n resizeObserver.observe(observedElement);\n }\n\n return () => {\n resizeObserver.disconnect();\n };\n }, [\n container,\n getCurrentPinnedValue,\n isMeasuring,\n markMeasurementStale,\n measureVisibleCount,\n menuOpen,\n visibleCount,\n ]);\n\n useIsomorphicLayoutEffect(() => {\n if (previousMenuOpenRef.current && !menuOpen) {\n markMeasurementStale();\n }\n\n previousMenuOpenRef.current = menuOpen;\n }, [markMeasurementStale, menuOpen]);\n\n useIsomorphicLayoutEffect(() => {\n const nextOverflowButtonWidth = overflowButton.current?.offsetWidth ?? 0;\n if (previousOverflowButtonWidthRef.current === nextOverflowButtonWidth) {\n return;\n }\n\n previousOverflowButtonWidthRef.current = nextOverflowButtonWidth;\n if (visibleCount < tabs.length) {\n markMeasurementStale();\n }\n });\n\n useIsomorphicLayoutEffect(() => {\n if (previousMeasurementInputKeyRef.current !== measurementInputKey) {\n previousMeasurementInputKeyRef.current = measurementInputKey;\n markMeasurementStale();\n }\n }, [markMeasurementStale, measurementInputKey]);\n\n useIsomorphicLayoutEffect(() => {\n // A content-only tab width update can briefly leave a tab without a\n // trustworthy measured width after it moves through the portal slots.\n // Retry on the next frame instead of leaving overflow stuck measuring.\n void measureRetryVersion;\n\n if (!isMeasuring || menuOpen) {\n return;\n }\n\n const nextVisibleCount = measureVisibleCount(getCurrentPinnedValue());\n\n if (nextVisibleCount == null) {\n if (measureRetryFrameRef.current != null) {\n return;\n }\n\n const element = container.current;\n if (!element || getMeasuredWidth(element) <= MIN_TRUSTED_TAB_WIDTH) {\n measureRetryCountRef.current = 0;\n return;\n }\n\n if (measureRetryCountRef.current >= 5) {\n return;\n }\n\n measureRetryCountRef.current += 1;\n measureRetryFrameRef.current = ownerWindow(element).requestAnimationFrame(\n () => {\n measureRetryFrameRef.current = null;\n setMeasureRetryVersion((currentVersion) => currentVersion + 1);\n },\n );\n return;\n }\n\n clearMeasureRetry();\n\n setVisibleCount(nextVisibleCount);\n setIsMeasuring(false);\n }, [\n clearMeasureRetry,\n container.current,\n getCurrentPinnedValue,\n isMeasuring,\n measureRetryVersion,\n measureVisibleCount,\n menuOpen,\n ]);\n\n const { visibleValues, hiddenValues } = partitionVisibleValues(\n orderedValues,\n visibleCount,\n pinnedValue,\n );\n\n return [visibleValues, hiddenValues, isMeasuring] as const;\n}\n"],"names":["pinnedValue"],"mappings":"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"}
@@ -0,0 +1,97 @@
1
+ import { useState, useEffect, useMemo, useCallback } from 'react';
2
+
3
+ function getOverflowStartIndex(hiddenValues, currentValue, fallbackValue) {
4
+ const currentIndex = hiddenValues.indexOf(currentValue);
5
+ const fallbackIndex = fallbackValue != null ? hiddenValues.indexOf(fallbackValue) : 0;
6
+ return currentIndex >= 0 ? currentIndex : Math.max(0, fallbackIndex);
7
+ }
8
+ function useOverflowLayoutState({
9
+ hiddenValues,
10
+ menuOpen,
11
+ overflowMenuOpen,
12
+ visibleValues
13
+ }) {
14
+ const [requestedOverflowActiveValue, setRequestedOverflowActiveValue] = useState(null);
15
+ useEffect(() => {
16
+ if (!overflowMenuOpen) {
17
+ setRequestedOverflowActiveValue(null);
18
+ }
19
+ }, [overflowMenuOpen]);
20
+ const resolvedOverflowActiveValue = useMemo(() => {
21
+ if (!overflowMenuOpen) {
22
+ return null;
23
+ }
24
+ if (requestedOverflowActiveValue && hiddenValues.includes(requestedOverflowActiveValue)) {
25
+ return requestedOverflowActiveValue;
26
+ }
27
+ return hiddenValues[0] ?? null;
28
+ }, [hiddenValues, overflowMenuOpen, requestedOverflowActiveValue]);
29
+ const hiddenValueSet = useMemo(() => new Set(hiddenValues), [hiddenValues]);
30
+ const visibleValueSet = useMemo(
31
+ () => new Set(visibleValues),
32
+ [visibleValues]
33
+ );
34
+ const getLocation = useCallback(
35
+ (value) => {
36
+ if (visibleValueSet.has(value)) {
37
+ return "main";
38
+ }
39
+ if (menuOpen && hiddenValueSet.has(value)) {
40
+ return "overflow";
41
+ }
42
+ return "hidden";
43
+ },
44
+ [hiddenValueSet, menuOpen, visibleValueSet]
45
+ );
46
+ const moveOverflowFocus = useCallback(
47
+ (key, value) => {
48
+ if (hiddenValues.length < 1) {
49
+ return false;
50
+ }
51
+ const startIndex = getOverflowStartIndex(
52
+ hiddenValues,
53
+ value,
54
+ resolvedOverflowActiveValue
55
+ );
56
+ const lastIndex = hiddenValues.length - 1;
57
+ let nextIndex = startIndex;
58
+ switch (key) {
59
+ case "ArrowDown":
60
+ nextIndex = startIndex >= lastIndex ? 0 : startIndex + 1;
61
+ break;
62
+ case "ArrowUp":
63
+ nextIndex = startIndex <= 0 ? lastIndex : startIndex - 1;
64
+ break;
65
+ case "Home":
66
+ nextIndex = 0;
67
+ break;
68
+ case "End":
69
+ nextIndex = lastIndex;
70
+ break;
71
+ }
72
+ const nextValue = hiddenValues[nextIndex];
73
+ if (!nextValue) {
74
+ return false;
75
+ }
76
+ setRequestedOverflowActiveValue(nextValue);
77
+ return true;
78
+ },
79
+ [hiddenValues, resolvedOverflowActiveValue]
80
+ );
81
+ const tabListLayoutContext = useMemo(
82
+ () => ({
83
+ getLocation,
84
+ overflowActiveValue: resolvedOverflowActiveValue,
85
+ setOverflowActiveValue: setRequestedOverflowActiveValue,
86
+ moveOverflowFocus
87
+ }),
88
+ [getLocation, moveOverflowFocus, resolvedOverflowActiveValue]
89
+ );
90
+ return {
91
+ resolvedOverflowActiveValue,
92
+ tabListLayoutContext
93
+ };
94
+ }
95
+
96
+ export { useOverflowLayoutState };
97
+ //# sourceMappingURL=useOverflowLayoutState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useOverflowLayoutState.js","sources":["../src/tabs/internal/overflow/useOverflowLayoutState.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState } from \"react\";\nimport type {\n TabListLayoutContextValue,\n TabSlotLocation,\n} from \"../contexts/TabListLayoutContext\";\n\nfunction getOverflowStartIndex(\n hiddenValues: string[],\n currentValue: string,\n fallbackValue: string | null,\n) {\n const currentIndex = hiddenValues.indexOf(currentValue);\n const fallbackIndex =\n fallbackValue != null ? hiddenValues.indexOf(fallbackValue) : 0;\n\n return currentIndex >= 0 ? currentIndex : Math.max(0, fallbackIndex);\n}\n\ninterface UseOverflowLayoutStateArgs {\n hiddenValues: string[];\n menuOpen: boolean;\n overflowMenuOpen: boolean;\n visibleValues: string[];\n}\n\ninterface UseOverflowLayoutStateResult {\n resolvedOverflowActiveValue: string | null;\n tabListLayoutContext: TabListLayoutContextValue;\n}\n\nexport function useOverflowLayoutState({\n hiddenValues,\n menuOpen,\n overflowMenuOpen,\n visibleValues,\n}: UseOverflowLayoutStateArgs): UseOverflowLayoutStateResult {\n const [requestedOverflowActiveValue, setRequestedOverflowActiveValue] =\n useState<string | null>(null);\n\n useEffect(() => {\n if (!overflowMenuOpen) {\n setRequestedOverflowActiveValue(null);\n }\n }, [overflowMenuOpen]);\n\n const resolvedOverflowActiveValue = useMemo(() => {\n if (!overflowMenuOpen) {\n return null;\n }\n\n if (\n requestedOverflowActiveValue &&\n hiddenValues.includes(requestedOverflowActiveValue)\n ) {\n return requestedOverflowActiveValue;\n }\n\n return hiddenValues[0] ?? null;\n }, [hiddenValues, overflowMenuOpen, requestedOverflowActiveValue]);\n\n const hiddenValueSet = useMemo(() => new Set(hiddenValues), [hiddenValues]);\n const visibleValueSet = useMemo(\n () => new Set(visibleValues),\n [visibleValues],\n );\n\n const getLocation = useCallback(\n (value: string): TabSlotLocation => {\n if (visibleValueSet.has(value)) {\n return \"main\";\n }\n\n if (menuOpen && hiddenValueSet.has(value)) {\n return \"overflow\";\n }\n\n return \"hidden\";\n },\n [hiddenValueSet, menuOpen, visibleValueSet],\n );\n\n const moveOverflowFocus = useCallback(\n (key: \"ArrowDown\" | \"ArrowUp\" | \"Home\" | \"End\", value: string) => {\n if (hiddenValues.length < 1) {\n return false;\n }\n\n const startIndex = getOverflowStartIndex(\n hiddenValues,\n value,\n resolvedOverflowActiveValue,\n );\n const lastIndex = hiddenValues.length - 1;\n let nextIndex = startIndex;\n\n switch (key) {\n case \"ArrowDown\":\n nextIndex = startIndex >= lastIndex ? 0 : startIndex + 1;\n break;\n case \"ArrowUp\":\n nextIndex = startIndex <= 0 ? lastIndex : startIndex - 1;\n break;\n case \"Home\":\n nextIndex = 0;\n break;\n case \"End\":\n nextIndex = lastIndex;\n break;\n }\n\n const nextValue = hiddenValues[nextIndex];\n if (!nextValue) {\n return false;\n }\n\n setRequestedOverflowActiveValue(nextValue);\n return true;\n },\n [hiddenValues, resolvedOverflowActiveValue],\n );\n\n const tabListLayoutContext = useMemo(\n () => ({\n getLocation,\n overflowActiveValue: resolvedOverflowActiveValue,\n setOverflowActiveValue: setRequestedOverflowActiveValue,\n moveOverflowFocus,\n }),\n [getLocation, moveOverflowFocus, resolvedOverflowActiveValue],\n );\n\n return {\n resolvedOverflowActiveValue,\n tabListLayoutContext,\n };\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ import { useRef, useCallback, useEffect } from 'react';
2
+ import 'clsx';
3
+ import 'react/jsx-runtime';
4
+ import { useIsomorphicLayoutEffect } from '../../../utils/useIsomorphicLayoutEffect.js';
5
+ import '../../../utils/useFloatingUI/useFloatingUI.js';
6
+ import '../../../utils/useId.js';
7
+ import { usePrevious } from '../../../utils/usePrevious.js';
8
+ import '../../../salt-provider/SaltProvider.js';
9
+ import '../../../viewport/ViewportProvider.js';
10
+
11
+ function useOverflowSelectionState({
12
+ commitSelection,
13
+ menuOpen,
14
+ selected,
15
+ setMenuOpen
16
+ }) {
17
+ const previousSelected = usePrevious(selected, [selected]);
18
+ const selectionFromOverflowValueRef = useRef(null);
19
+ const pendingOverflowSelectionRef = useRef(
20
+ null
21
+ );
22
+ const setSelected = useCallback(
23
+ (event, value, source = "main") => {
24
+ const selectedFromOverflow = source === "overflow";
25
+ selectionFromOverflowValueRef.current = selectedFromOverflow ? value : null;
26
+ if (selectedFromOverflow) {
27
+ event == null ? void 0 : event.persist();
28
+ pendingOverflowSelectionRef.current = { event, value };
29
+ setMenuOpen(false);
30
+ return;
31
+ }
32
+ pendingOverflowSelectionRef.current = null;
33
+ setMenuOpen(false);
34
+ commitSelection(event, value);
35
+ },
36
+ [commitSelection, setMenuOpen]
37
+ );
38
+ useIsomorphicLayoutEffect(() => {
39
+ if (menuOpen) {
40
+ return;
41
+ }
42
+ const pendingSelection = pendingOverflowSelectionRef.current;
43
+ if (!pendingSelection) {
44
+ return;
45
+ }
46
+ pendingOverflowSelectionRef.current = null;
47
+ commitSelection(pendingSelection.event, pendingSelection.value);
48
+ }, [commitSelection, menuOpen]);
49
+ useEffect(() => {
50
+ const selectedFromOverflow = selectionFromOverflowValueRef.current;
51
+ if (selectedFromOverflow == null || pendingOverflowSelectionRef.current) {
52
+ return;
53
+ }
54
+ if (selected === selectedFromOverflow && selected !== previousSelected) {
55
+ return;
56
+ }
57
+ selectionFromOverflowValueRef.current = null;
58
+ }, [previousSelected, selected]);
59
+ return {
60
+ selectionFromOverflowValueRef,
61
+ setSelected
62
+ };
63
+ }
64
+
65
+ export { useOverflowSelectionState };
66
+ //# sourceMappingURL=useOverflowSelectionState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useOverflowSelectionState.js","sources":["../src/tabs/internal/overflow/useOverflowSelectionState.ts"],"sourcesContent":["import {\n type Dispatch,\n type MutableRefObject,\n type SetStateAction,\n type SyntheticEvent,\n useCallback,\n useEffect,\n useRef,\n} from \"react\";\nimport { useIsomorphicLayoutEffect, usePrevious } from \"../../../utils\";\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 event?.persist();\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,KAAA,IAAA,IAAA,GAAA,MAAA,GAAA,KAAA,CAAO,OAAA,EAAA;AACP,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(".saltTabOverflowList-list") || element.closest(".saltTabList-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/internal/overflow/useRenderedTabWidth.ts"],"sourcesContent":["import { type RefObject, useEffect } from \"react\";\nimport type { TabsContextValue, TabsRenderMode } from \"../contexts/TabsContext\";\nimport { getIntrinsicMeasuredWidth } from \"./widthMeasurement\";\n\nconst MIN_TRUSTED_RENDERED_TAB_WIDTH = 0.5;\n\ninterface UseRenderedTabWidthProps {\n hostElement: HTMLDivElement | null;\n renderMode: TabsRenderMode;\n tabRootRef: RefObject<HTMLDivElement>;\n targetWindow: Window | null | undefined;\n updateRenderedTab: TabsContextValue[\"updateRenderedTab\"];\n value: string;\n}\n\nfunction isSecondaryMeasurementContext(element: HTMLElement) {\n return (\n element.closest(\".saltTabOverflowList-list\") ||\n element.closest(\".saltTabList-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,36 @@
1
+ const WIDTH_EPSILON = 0.5;
2
+ function getMeasuredWidth(element) {
3
+ if (!element) {
4
+ return 0;
5
+ }
6
+ const width = element.getBoundingClientRect().width;
7
+ return width || element.clientWidth || 0;
8
+ }
9
+ function getIntrinsicMeasuredWidth(element) {
10
+ if (!element) {
11
+ return 0;
12
+ }
13
+ const borderWidth = element.offsetWidth - element.clientWidth;
14
+ return Math.max(getMeasuredWidth(element), element.scrollWidth + borderWidth);
15
+ }
16
+ function getGapValue(styles) {
17
+ return Number.parseFloat(styles.columnGap || styles.gap || "0") || 0;
18
+ }
19
+ function seedWidthMap(elements) {
20
+ const widths = /* @__PURE__ */ new Map();
21
+ for (const element of elements) {
22
+ widths.set(element, getMeasuredWidth(element));
23
+ }
24
+ return widths;
25
+ }
26
+ function updateWidthMap(widths, element, nextWidth, epsilon = WIDTH_EPSILON) {
27
+ const previousWidth = widths.get(element);
28
+ widths.set(element, nextWidth);
29
+ if (previousWidth === void 0) {
30
+ return false;
31
+ }
32
+ return Math.abs(previousWidth - nextWidth) > epsilon;
33
+ }
34
+
35
+ export { getGapValue, getIntrinsicMeasuredWidth, getMeasuredWidth, seedWidthMap, updateWidthMap };
36
+ //# sourceMappingURL=widthMeasurement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"widthMeasurement.js","sources":["../src/tabs/internal/overflow/widthMeasurement.ts"],"sourcesContent":["const WIDTH_EPSILON = 0.5;\n\nexport function getMeasuredWidth(element: HTMLElement | null | undefined) {\n if (!element) {\n return 0;\n }\n\n const width = element.getBoundingClientRect().width;\n return width || element.clientWidth || 0;\n}\n\nexport function getIntrinsicMeasuredWidth(\n element: HTMLElement | null | undefined,\n) {\n if (!element) {\n return 0;\n }\n\n const borderWidth = element.offsetWidth - element.clientWidth;\n return Math.max(getMeasuredWidth(element), element.scrollWidth + borderWidth);\n}\n\nexport function getGapValue(styles: CSSStyleDeclaration) {\n return Number.parseFloat(styles.columnGap || styles.gap || \"0\") || 0;\n}\n\nexport function seedWidthMap(elements: HTMLElement[]) {\n const widths = new Map<HTMLElement, number>();\n for (const element of elements) {\n widths.set(element, getMeasuredWidth(element));\n }\n return widths;\n}\n\nexport function updateWidthMap(\n widths: Map<HTMLElement, number>,\n element: HTMLElement,\n nextWidth: number,\n epsilon = WIDTH_EPSILON,\n) {\n const previousWidth = widths.get(element);\n widths.set(element, nextWidth);\n\n if (previousWidth === undefined) {\n return false;\n }\n\n return Math.abs(previousWidth - nextWidth) > epsilon;\n}\n"],"names":[],"mappings":"AAAA,MAAM,aAAA,GAAgB,GAAA;AAEf,SAAS,iBAAiB,OAAA,EAAyC;AACxE,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,OAAO,CAAA;AAAA,EACT;AAEA,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,qBAAA,EAAsB,CAAE,KAAA;AAC9C,EAAA,OAAO,KAAA,IAAS,QAAQ,WAAA,IAAe,CAAA;AACzC;AAEO,SAAS,0BACd,OAAA,EACA;AACA,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,OAAO,CAAA;AAAA,EACT;AAEA,EAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,WAAA,GAAc,OAAA,CAAQ,WAAA;AAClD,EAAA,OAAO,KAAK,GAAA,CAAI,gBAAA,CAAiB,OAAO,CAAA,EAAG,OAAA,CAAQ,cAAc,WAAW,CAAA;AAC9E;AAEO,SAAS,YAAY,MAAA,EAA6B;AACvD,EAAA,OAAO,OAAO,UAAA,CAAW,MAAA,CAAO,aAAa,MAAA,CAAO,GAAA,IAAO,GAAG,CAAA,IAAK,CAAA;AACrE;AAEO,SAAS,aAAa,QAAA,EAAyB;AACpD,EAAA,MAAM,MAAA,uBAAa,GAAA,EAAyB;AAC5C,EAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,IAAA,MAAA,CAAO,GAAA,CAAI,OAAA,EAAS,gBAAA,CAAiB,OAAO,CAAC,CAAA;AAAA,EAC/C;AACA,EAAA,OAAO,MAAA;AACT;AAEO,SAAS,cAAA,CACd,MAAA,EACA,OAAA,EACA,SAAA,EACA,UAAU,aAAA,EACV;AACA,EAAA,MAAM,aAAA,GAAgB,MAAA,CAAO,GAAA,CAAI,OAAO,CAAA;AACxC,EAAA,MAAA,CAAO,GAAA,CAAI,SAAS,SAAS,CAAA;AAE7B,EAAA,IAAI,kBAAkB,MAAA,EAAW;AAC/B,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,OAAO,IAAA,CAAK,GAAA,CAAI,aAAA,GAAgB,SAAS,CAAA,GAAI,OAAA;AAC/C;;;;"}
@@ -0,0 +1,195 @@
1
+ import { useRef, useState, useCallback, useEffect } from 'react';
2
+
3
+ function sortBasedOnDOMPosition(items) {
4
+ const indexedItems = items.map((item, index) => [index, item]);
5
+ let orderChanged = false;
6
+ indexedItems.sort(([itemAIndex, itemA], [itemBIndex, itemB]) => {
7
+ if (itemA.order != null && itemA.order >= 0 && itemB.order != null && itemB.order >= 0 && itemA.order !== itemB.order) {
8
+ if (itemA.order < itemB.order && itemAIndex > itemBIndex || itemA.order > itemB.order && itemAIndex < itemBIndex) {
9
+ orderChanged = true;
10
+ }
11
+ return itemA.order - itemB.order;
12
+ }
13
+ const itemAElement = itemA.element;
14
+ const itemBElement = itemB.element;
15
+ if (itemAElement === itemBElement) return 0;
16
+ if (!itemAElement || !itemBElement) return 0;
17
+ const pos = itemAElement.compareDocumentPosition(itemBElement);
18
+ if (pos & Node.DOCUMENT_POSITION_DISCONNECTED) return 0;
19
+ if (pos & Node.DOCUMENT_POSITION_FOLLOWING) {
20
+ if (itemAIndex > itemBIndex) {
21
+ orderChanged = true;
22
+ }
23
+ return -1;
24
+ }
25
+ if (itemAIndex < itemBIndex) {
26
+ orderChanged = true;
27
+ }
28
+ return 1;
29
+ });
30
+ if (orderChanged) {
31
+ return indexedItems.map(([_, item]) => item);
32
+ }
33
+ return items;
34
+ }
35
+ function useCollection({ wrap, targetWindow }) {
36
+ const itemsRef = useRef([]);
37
+ const itemMap = useRef(/* @__PURE__ */ new Map());
38
+ const removedItems = useRef(/* @__PURE__ */ new Map());
39
+ const [removalVersion, setRemovalVersion] = useState(0);
40
+ const getOrderedItems = useCallback(() => {
41
+ return sortBasedOnDOMPosition(Array.from(itemMap.current.values()));
42
+ }, []);
43
+ const getNavigableItems = useCallback(() => {
44
+ return getOrderedItems().filter((item) => {
45
+ if (item.location === "hidden") {
46
+ return false;
47
+ }
48
+ return !!item.element;
49
+ });
50
+ }, [getOrderedItems]);
51
+ const sortItems = useCallback(() => {
52
+ itemsRef.current = getOrderedItems();
53
+ }, [getOrderedItems]);
54
+ const getRemovedItems = useCallback(() => {
55
+ const items = new Map(removedItems.current);
56
+ removedItems.current.clear();
57
+ return items;
58
+ }, []);
59
+ const rafId = useRef(null);
60
+ const scheduleSort = useCallback(() => {
61
+ if (!(targetWindow == null ? void 0 : targetWindow.requestAnimationFrame)) {
62
+ sortItems();
63
+ return;
64
+ }
65
+ if (rafId.current != null) {
66
+ targetWindow.cancelAnimationFrame(rafId.current);
67
+ }
68
+ rafId.current = targetWindow.requestAnimationFrame(() => {
69
+ rafId.current = null;
70
+ sortItems();
71
+ });
72
+ }, [sortItems, targetWindow]);
73
+ const registerItem = useCallback(
74
+ (item) => {
75
+ itemMap.current.set(item.id, item);
76
+ removedItems.current.delete(item.id);
77
+ scheduleSort();
78
+ return () => {
79
+ const currentItems = getOrderedItems();
80
+ const currentItem = itemMap.current.get(item.id) ?? item;
81
+ const staleIndex = currentItems.findIndex(({ id }) => id === item.id);
82
+ removedItems.current.set(item.id, {
83
+ ...currentItem,
84
+ staleIndex
85
+ });
86
+ itemsRef.current = currentItems.filter(({ id }) => id !== item.id);
87
+ itemMap.current.delete(item.id);
88
+ setRemovalVersion((currentVersion) => currentVersion + 1);
89
+ };
90
+ },
91
+ [getOrderedItems, scheduleSort]
92
+ );
93
+ const updateItem = useCallback(
94
+ (id, updates) => {
95
+ const currentItem = itemMap.current.get(id);
96
+ if (!currentItem) {
97
+ return;
98
+ }
99
+ let changed = false;
100
+ const nextItem = { ...currentItem };
101
+ for (const [key, nextValue] of Object.entries(updates)) {
102
+ const typedKey = key;
103
+ if (nextItem[typedKey] !== nextValue) {
104
+ changed = true;
105
+ nextItem[typedKey] = nextValue;
106
+ }
107
+ }
108
+ if (!changed) {
109
+ return;
110
+ }
111
+ itemMap.current.set(id, nextItem);
112
+ itemsRef.current = itemsRef.current.map((item) => {
113
+ if (item.id !== id) {
114
+ return item;
115
+ }
116
+ return nextItem;
117
+ });
118
+ scheduleSort();
119
+ },
120
+ [scheduleSort]
121
+ );
122
+ useEffect(() => {
123
+ return () => {
124
+ if (rafId.current != null && targetWindow) {
125
+ targetWindow.cancelAnimationFrame(rafId.current);
126
+ }
127
+ };
128
+ }, [targetWindow]);
129
+ return {
130
+ registerItem,
131
+ item: useCallback((id) => {
132
+ if (!id) return null;
133
+ let item = itemMap.current.get(id);
134
+ if (!item) {
135
+ item = itemsRef.current.find((item2) => item2.id === id);
136
+ if (item) {
137
+ itemMap.current.set(item.id, item);
138
+ }
139
+ }
140
+ return item ?? null;
141
+ }, []),
142
+ getNext: useCallback(
143
+ (current) => {
144
+ const items = getNavigableItems();
145
+ if (items.length === 0) return null;
146
+ const index = items.findIndex(({ id }) => id === current);
147
+ if (index === -1) {
148
+ return items[0] ;
149
+ }
150
+ const newIndex = (index + 1) % items.length ;
151
+ return items[newIndex] ?? null;
152
+ },
153
+ [getNavigableItems, wrap]
154
+ ),
155
+ getPrevious: useCallback(
156
+ (current) => {
157
+ const items = getNavigableItems();
158
+ if (items.length === 0) return null;
159
+ const index = items.findIndex(({ id }) => id === current);
160
+ if (index === -1) {
161
+ return items[items.length - 1] ;
162
+ }
163
+ const newIndex = (index - 1 + items.length) % items.length ;
164
+ return items[newIndex] ?? null;
165
+ },
166
+ [getNavigableItems, wrap]
167
+ ),
168
+ getFirst: useCallback(() => {
169
+ return getNavigableItems()[0] ?? null;
170
+ }, [getNavigableItems]),
171
+ getLast: useCallback(() => {
172
+ const items = getNavigableItems();
173
+ return items[items.length - 1] ?? null;
174
+ }, [getNavigableItems]),
175
+ getIndex: useCallback(
176
+ (current) => {
177
+ return getNavigableItems().findIndex(({ id }) => id === current);
178
+ },
179
+ [getNavigableItems]
180
+ ),
181
+ itemAt: useCallback(
182
+ (index) => {
183
+ return getNavigableItems()[index] ?? null;
184
+ },
185
+ [getNavigableItems]
186
+ ),
187
+ updateItem,
188
+ getRemovedItems,
189
+ removalVersion,
190
+ sortItems
191
+ };
192
+ }
193
+
194
+ export { useCollection };
195
+ //# sourceMappingURL=useCollection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCollection.js","sources":["../src/tabs/internal/registry/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":["item"],"mappings":"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"}