@salt-ds/core 1.60.0 → 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 (195) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/css/salt-core.css +366 -1
  3. package/dist-cjs/index.js +16 -0
  4. package/dist-cjs/index.js.map +1 -1
  5. package/dist-cjs/navigation-item/NavigationItem.js +2 -0
  6. package/dist-cjs/navigation-item/NavigationItem.js.map +1 -1
  7. package/dist-cjs/rating/Rating.css.js +6 -0
  8. package/dist-cjs/rating/Rating.css.js.map +1 -0
  9. package/dist-cjs/rating/Rating.js +140 -0
  10. package/dist-cjs/rating/Rating.js.map +1 -0
  11. package/dist-cjs/rating/RatingItem.css.js +6 -0
  12. package/dist-cjs/rating/RatingItem.css.js.map +1 -0
  13. package/dist-cjs/rating/RatingItem.js +75 -0
  14. package/dist-cjs/rating/RatingItem.js.map +1 -0
  15. package/dist-cjs/semantic-icon-provider/SemanticIconProvider.js +22 -20
  16. package/dist-cjs/semantic-icon-provider/SemanticIconProvider.js.map +1 -1
  17. package/dist-cjs/tabs/Tab.css.js +6 -0
  18. package/dist-cjs/tabs/Tab.css.js.map +1 -0
  19. package/dist-cjs/tabs/Tab.js +211 -0
  20. package/dist-cjs/tabs/Tab.js.map +1 -0
  21. package/dist-cjs/tabs/TabAction.js +63 -0
  22. package/dist-cjs/tabs/TabAction.js.map +1 -0
  23. package/dist-cjs/tabs/TabBar.css.js +6 -0
  24. package/dist-cjs/tabs/TabBar.css.js.map +1 -0
  25. package/dist-cjs/tabs/TabBar.js +45 -0
  26. package/dist-cjs/tabs/TabBar.js.map +1 -0
  27. package/dist-cjs/tabs/TabList.css.js +6 -0
  28. package/dist-cjs/tabs/TabList.css.js.map +1 -0
  29. package/dist-cjs/tabs/TabList.js +281 -0
  30. package/dist-cjs/tabs/TabList.js.map +1 -0
  31. package/dist-cjs/tabs/TabPanel.css.js +6 -0
  32. package/dist-cjs/tabs/TabPanel.css.js.map +1 -0
  33. package/dist-cjs/tabs/TabPanel.js +98 -0
  34. package/dist-cjs/tabs/TabPanel.js.map +1 -0
  35. package/dist-cjs/tabs/TabTrigger.css.js +6 -0
  36. package/dist-cjs/tabs/TabTrigger.css.js.map +1 -0
  37. package/dist-cjs/tabs/TabTrigger.js +188 -0
  38. package/dist-cjs/tabs/TabTrigger.js.map +1 -0
  39. package/dist-cjs/tabs/Tabs.css.js +6 -0
  40. package/dist-cjs/tabs/Tabs.css.js.map +1 -0
  41. package/dist-cjs/tabs/Tabs.js +200 -0
  42. package/dist-cjs/tabs/Tabs.js.map +1 -0
  43. package/dist-cjs/tabs/internal/contexts/TabContext.js +26 -0
  44. package/dist-cjs/tabs/internal/contexts/TabContext.js.map +1 -0
  45. package/dist-cjs/tabs/internal/contexts/TabListLayoutContext.js +19 -0
  46. package/dist-cjs/tabs/internal/contexts/TabListLayoutContext.js.map +1 -0
  47. package/dist-cjs/tabs/internal/contexts/TabSlotRegistryContext.js +22 -0
  48. package/dist-cjs/tabs/internal/contexts/TabSlotRegistryContext.js.map +1 -0
  49. package/dist-cjs/tabs/internal/contexts/TabsContext.js +50 -0
  50. package/dist-cjs/tabs/internal/contexts/TabsContext.js.map +1 -0
  51. package/dist-cjs/tabs/internal/hooks/useFocusWithRetry.js +64 -0
  52. package/dist-cjs/tabs/internal/hooks/useFocusWithRetry.js.map +1 -0
  53. package/dist-cjs/tabs/internal/hooks/useTabListRecovery.js +76 -0
  54. package/dist-cjs/tabs/internal/hooks/useTabListRecovery.js.map +1 -0
  55. package/dist-cjs/tabs/internal/hooks/useTabRemovalHandler.js +165 -0
  56. package/dist-cjs/tabs/internal/hooks/useTabRemovalHandler.js.map +1 -0
  57. package/dist-cjs/tabs/internal/hooks/useTabSelectionFocus.js +87 -0
  58. package/dist-cjs/tabs/internal/hooks/useTabSelectionFocus.js.map +1 -0
  59. package/dist-cjs/tabs/internal/overflow/TabOverflowList.css.js +6 -0
  60. package/dist-cjs/tabs/internal/overflow/TabOverflowList.css.js.map +1 -0
  61. package/dist-cjs/tabs/internal/overflow/TabOverflowList.js +245 -0
  62. package/dist-cjs/tabs/internal/overflow/TabOverflowList.js.map +1 -0
  63. package/dist-cjs/tabs/internal/overflow/TabSlot.js +30 -0
  64. package/dist-cjs/tabs/internal/overflow/TabSlot.js.map +1 -0
  65. package/dist-cjs/tabs/internal/overflow/overflowMath.js +86 -0
  66. package/dist-cjs/tabs/internal/overflow/overflowMath.js.map +1 -0
  67. package/dist-cjs/tabs/internal/overflow/useOverflow.js +273 -0
  68. package/dist-cjs/tabs/internal/overflow/useOverflow.js.map +1 -0
  69. package/dist-cjs/tabs/internal/overflow/useOverflowLayoutState.js +99 -0
  70. package/dist-cjs/tabs/internal/overflow/useOverflowLayoutState.js.map +1 -0
  71. package/dist-cjs/tabs/internal/overflow/useOverflowSelectionState.js +68 -0
  72. package/dist-cjs/tabs/internal/overflow/useOverflowSelectionState.js.map +1 -0
  73. package/dist-cjs/tabs/internal/overflow/useRenderedTabWidth.js +92 -0
  74. package/dist-cjs/tabs/internal/overflow/useRenderedTabWidth.js.map +1 -0
  75. package/dist-cjs/tabs/internal/overflow/widthMeasurement.js +42 -0
  76. package/dist-cjs/tabs/internal/overflow/widthMeasurement.js.map +1 -0
  77. package/dist-cjs/tabs/internal/registry/useCollection.js +197 -0
  78. package/dist-cjs/tabs/internal/registry/useCollection.js.map +1 -0
  79. package/dist-cjs/tabs/internal/registry/useRenderedTabsRegistry.js +206 -0
  80. package/dist-cjs/tabs/internal/registry/useRenderedTabsRegistry.js.map +1 -0
  81. package/dist-cjs/tabs/internal/utils/domUtils.js +13 -0
  82. package/dist-cjs/tabs/internal/utils/domUtils.js.map +1 -0
  83. package/dist-es/index.js +8 -0
  84. package/dist-es/index.js.map +1 -1
  85. package/dist-es/navigation-item/NavigationItem.js +2 -0
  86. package/dist-es/navigation-item/NavigationItem.js.map +1 -1
  87. package/dist-es/rating/Rating.css.js +4 -0
  88. package/dist-es/rating/Rating.css.js.map +1 -0
  89. package/dist-es/rating/Rating.js +138 -0
  90. package/dist-es/rating/Rating.js.map +1 -0
  91. package/dist-es/rating/RatingItem.css.js +4 -0
  92. package/dist-es/rating/RatingItem.css.js.map +1 -0
  93. package/dist-es/rating/RatingItem.js +73 -0
  94. package/dist-es/rating/RatingItem.js.map +1 -0
  95. package/dist-es/semantic-icon-provider/SemanticIconProvider.js +23 -21
  96. package/dist-es/semantic-icon-provider/SemanticIconProvider.js.map +1 -1
  97. package/dist-es/tabs/Tab.css.js +4 -0
  98. package/dist-es/tabs/Tab.css.js.map +1 -0
  99. package/dist-es/tabs/Tab.js +209 -0
  100. package/dist-es/tabs/Tab.js.map +1 -0
  101. package/dist-es/tabs/TabAction.js +61 -0
  102. package/dist-es/tabs/TabAction.js.map +1 -0
  103. package/dist-es/tabs/TabBar.css.js +4 -0
  104. package/dist-es/tabs/TabBar.css.js.map +1 -0
  105. package/dist-es/tabs/TabBar.js +43 -0
  106. package/dist-es/tabs/TabBar.js.map +1 -0
  107. package/dist-es/tabs/TabList.css.js +4 -0
  108. package/dist-es/tabs/TabList.css.js.map +1 -0
  109. package/dist-es/tabs/TabList.js +279 -0
  110. package/dist-es/tabs/TabList.js.map +1 -0
  111. package/dist-es/tabs/TabPanel.css.js +4 -0
  112. package/dist-es/tabs/TabPanel.css.js.map +1 -0
  113. package/dist-es/tabs/TabPanel.js +96 -0
  114. package/dist-es/tabs/TabPanel.js.map +1 -0
  115. package/dist-es/tabs/TabTrigger.css.js +4 -0
  116. package/dist-es/tabs/TabTrigger.css.js.map +1 -0
  117. package/dist-es/tabs/TabTrigger.js +186 -0
  118. package/dist-es/tabs/TabTrigger.js.map +1 -0
  119. package/dist-es/tabs/Tabs.css.js +4 -0
  120. package/dist-es/tabs/Tabs.css.js.map +1 -0
  121. package/dist-es/tabs/Tabs.js +198 -0
  122. package/dist-es/tabs/Tabs.js.map +1 -0
  123. package/dist-es/tabs/internal/contexts/TabContext.js +23 -0
  124. package/dist-es/tabs/internal/contexts/TabContext.js.map +1 -0
  125. package/dist-es/tabs/internal/contexts/TabListLayoutContext.js +16 -0
  126. package/dist-es/tabs/internal/contexts/TabListLayoutContext.js.map +1 -0
  127. package/dist-es/tabs/internal/contexts/TabSlotRegistryContext.js +19 -0
  128. package/dist-es/tabs/internal/contexts/TabSlotRegistryContext.js.map +1 -0
  129. package/dist-es/tabs/internal/contexts/TabsContext.js +47 -0
  130. package/dist-es/tabs/internal/contexts/TabsContext.js.map +1 -0
  131. package/dist-es/tabs/internal/hooks/useFocusWithRetry.js +62 -0
  132. package/dist-es/tabs/internal/hooks/useFocusWithRetry.js.map +1 -0
  133. package/dist-es/tabs/internal/hooks/useTabListRecovery.js +74 -0
  134. package/dist-es/tabs/internal/hooks/useTabListRecovery.js.map +1 -0
  135. package/dist-es/tabs/internal/hooks/useTabRemovalHandler.js +163 -0
  136. package/dist-es/tabs/internal/hooks/useTabRemovalHandler.js.map +1 -0
  137. package/dist-es/tabs/internal/hooks/useTabSelectionFocus.js +85 -0
  138. package/dist-es/tabs/internal/hooks/useTabSelectionFocus.js.map +1 -0
  139. package/dist-es/tabs/internal/overflow/TabOverflowList.css.js +4 -0
  140. package/dist-es/tabs/internal/overflow/TabOverflowList.css.js.map +1 -0
  141. package/dist-es/tabs/internal/overflow/TabOverflowList.js +243 -0
  142. package/dist-es/tabs/internal/overflow/TabOverflowList.js.map +1 -0
  143. package/dist-es/tabs/internal/overflow/TabSlot.js +28 -0
  144. package/dist-es/tabs/internal/overflow/TabSlot.js.map +1 -0
  145. package/dist-es/tabs/internal/overflow/overflowMath.js +82 -0
  146. package/dist-es/tabs/internal/overflow/overflowMath.js.map +1 -0
  147. package/dist-es/tabs/internal/overflow/useOverflow.js +271 -0
  148. package/dist-es/tabs/internal/overflow/useOverflow.js.map +1 -0
  149. package/dist-es/tabs/internal/overflow/useOverflowLayoutState.js +97 -0
  150. package/dist-es/tabs/internal/overflow/useOverflowLayoutState.js.map +1 -0
  151. package/dist-es/tabs/internal/overflow/useOverflowSelectionState.js +66 -0
  152. package/dist-es/tabs/internal/overflow/useOverflowSelectionState.js.map +1 -0
  153. package/dist-es/tabs/internal/overflow/useRenderedTabWidth.js +90 -0
  154. package/dist-es/tabs/internal/overflow/useRenderedTabWidth.js.map +1 -0
  155. package/dist-es/tabs/internal/overflow/widthMeasurement.js +36 -0
  156. package/dist-es/tabs/internal/overflow/widthMeasurement.js.map +1 -0
  157. package/dist-es/tabs/internal/registry/useCollection.js +195 -0
  158. package/dist-es/tabs/internal/registry/useCollection.js.map +1 -0
  159. package/dist-es/tabs/internal/registry/useRenderedTabsRegistry.js +204 -0
  160. package/dist-es/tabs/internal/registry/useRenderedTabsRegistry.js.map +1 -0
  161. package/dist-es/tabs/internal/utils/domUtils.js +11 -0
  162. package/dist-es/tabs/internal/utils/domUtils.js.map +1 -0
  163. package/dist-types/index.d.ts +2 -0
  164. package/dist-types/rating/Rating.d.ts +48 -0
  165. package/dist-types/rating/RatingItem.d.ts +47 -0
  166. package/dist-types/rating/index.d.ts +1 -0
  167. package/dist-types/semantic-icon-provider/SemanticIconProvider.d.ts +21 -19
  168. package/dist-types/tabs/Tab.d.ts +12 -0
  169. package/dist-types/tabs/TabAction.d.ts +4 -0
  170. package/dist-types/tabs/TabBar.d.ts +12 -0
  171. package/dist-types/tabs/TabList.d.ts +12 -0
  172. package/dist-types/tabs/TabPanel.d.ts +9 -0
  173. package/dist-types/tabs/TabTrigger.d.ts +4 -0
  174. package/dist-types/tabs/Tabs.d.ts +20 -0
  175. package/dist-types/tabs/index.d.ts +7 -0
  176. package/dist-types/tabs/internal/contexts/TabContext.d.ts +12 -0
  177. package/dist-types/tabs/internal/contexts/TabListLayoutContext.d.ts +9 -0
  178. package/dist-types/tabs/internal/contexts/TabSlotRegistryContext.d.ts +5 -0
  179. package/dist-types/tabs/internal/contexts/TabsContext.d.ts +43 -0
  180. package/dist-types/tabs/internal/hooks/useFocusWithRetry.d.ts +9 -0
  181. package/dist-types/tabs/internal/hooks/useTabListRecovery.d.ts +12 -0
  182. package/dist-types/tabs/internal/hooks/useTabRemovalHandler.d.ts +32 -0
  183. package/dist-types/tabs/internal/hooks/useTabSelectionFocus.d.ts +15 -0
  184. package/dist-types/tabs/internal/overflow/TabOverflowList.d.ts +10 -0
  185. package/dist-types/tabs/internal/overflow/TabSlot.d.ts +6 -0
  186. package/dist-types/tabs/internal/overflow/overflowMath.d.ts +18 -0
  187. package/dist-types/tabs/internal/overflow/useOverflow.d.ts +11 -0
  188. package/dist-types/tabs/internal/overflow/useOverflowLayoutState.d.ts +13 -0
  189. package/dist-types/tabs/internal/overflow/useOverflowSelectionState.d.ts +13 -0
  190. package/dist-types/tabs/internal/overflow/useRenderedTabWidth.d.ts +12 -0
  191. package/dist-types/tabs/internal/overflow/widthMeasurement.d.ts +5 -0
  192. package/dist-types/tabs/internal/registry/useCollection.d.ts +30 -0
  193. package/dist-types/tabs/internal/registry/useRenderedTabsRegistry.d.ts +12 -0
  194. package/dist-types/tabs/internal/utils/domUtils.d.ts +1 -0
  195. package/package.json +3 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TabOverflowList.js","sources":["../src/tabs/internal/overflow/TabOverflowList.tsx"],"sourcesContent":["import {\n flip,\n offset,\n shift,\n size,\n useClick,\n useDismiss,\n useInteractions,\n} from \"@floating-ui/react\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n type ComponentPropsWithoutRef,\n type Dispatch,\n forwardRef,\n type KeyboardEvent,\n type Ref,\n type SetStateAction,\n useEffect,\n useRef,\n} from \"react\";\nimport { Button } from \"../../../button\";\nimport { useIcon } from \"../../../semantic-icon-provider\";\nimport {\n makePrefixer,\n useFloatingComponent,\n useFloatingUI,\n useForkRef,\n useId,\n useIsomorphicLayoutEffect,\n} from \"../../../utils\";\nimport { useTabs } from \"../contexts/TabsContext\";\nimport { isHTMLElement } from \"../utils/domUtils\";\nimport tabOverflowListCss from \"./TabOverflowList.css\";\nimport { TabSlot } from \"./TabSlot\";\nimport {\n getMeasuredWidth,\n seedWidthMap,\n updateWidthMap,\n} from \"./widthMeasurement\";\n\ninterface TabOverflowListProps extends ComponentPropsWithoutRef<\"button\"> {\n buttonRef?: Ref<HTMLButtonElement>;\n hiddenValues: string[];\n open: boolean;\n setOpen: Dispatch<SetStateAction<boolean>>;\n order: number;\n}\n\nconst withBaseName = makePrefixer(\"saltTabOverflowList\");\n\nexport const TabOverflowList = forwardRef<HTMLDivElement, TabOverflowListProps>(\n function TabOverflowList(props, ref) {\n const {\n buttonRef,\n className,\n hiddenValues,\n order,\n open,\n setOpen,\n ...rest\n } = props;\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-tab-overflow-list\",\n css: tabOverflowListCss,\n window: targetWindow,\n });\n\n const overflowRef = useRef<HTMLButtonElement>(null);\n const hadOverflowItemsRef = useRef(false);\n\n const { OverflowIcon } = useIcon();\n const { registerTab, updateTab, activeTab } = useTabs();\n\n const { refs, x, y, strategy, context, elements } = useFloatingUI({\n open: open,\n onOpenChange(open, _, reason) {\n setOpen(open);\n\n if (reason === \"escape-key\") {\n overflowRef.current?.focus();\n }\n },\n placement: \"bottom-start\",\n middleware: [\n offset(1),\n size({\n apply({ elements, availableHeight }) {\n Object.assign(elements.floating.style, {\n maxHeight: `max(calc((var(--salt-size-base) + var(--salt-spacing-100)) * 5), calc(${availableHeight}px - var(--salt-spacing-100)))`,\n });\n },\n }),\n flip(),\n shift({\n padding: 8,\n }),\n ],\n });\n\n const { getFloatingProps, getReferenceProps } = useInteractions([\n useClick(context),\n useDismiss(context),\n ]);\n\n const handleListRef = useForkRef<HTMLDivElement>(ref, refs.setFloating);\n\n const handleButtonRef = useForkRef<HTMLButtonElement>(\n buttonRef,\n refs.setReference,\n );\n const handleRef = useForkRef(handleButtonRef, overflowRef);\n\n const { Component: FloatingComponent } = useFloatingComponent();\n\n const overflowId = useId();\n const overlayId = useId();\n\n const handleFocus = () => {\n if (overflowId) {\n activeTab.current = { value: overflowId, id: overflowId };\n }\n };\n\n const handleFloatingKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key !== \"Tab\") {\n return;\n }\n\n if (event.shiftKey) {\n event.preventDefault();\n setOpen(false);\n const scheduleFocus = targetWindow?.requestAnimationFrame;\n if (scheduleFocus) {\n scheduleFocus(() =>\n overflowRef.current?.focus({ preventScroll: true }),\n );\n return;\n }\n\n queueMicrotask(() =>\n overflowRef.current?.focus({ preventScroll: true }),\n );\n return;\n }\n };\n\n const overflowItemCount = hiddenValues.length;\n const hasOverflowItems = overflowItemCount > 0;\n const initialOrderRef = useRef(order);\n\n useEffect(() => {\n const tabList = overflowRef.current?.parentElement;\n const resizeObserverCtor = (\n targetWindow as\n | (Window & { ResizeObserver?: typeof ResizeObserver })\n | undefined\n )?.ResizeObserver;\n if (!open || !tabList || !resizeObserverCtor) {\n return;\n }\n\n const observedElements = [tabList, tabList.parentElement].filter(\n (element): element is HTMLElement => element != null,\n );\n const widths = seedWidthMap(observedElements);\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 =\n entry.contentRect.width || getMeasuredWidth(entry.target);\n if (updateWidthMap(widths, entry.target, nextWidth)) {\n setOpen(false);\n return;\n }\n }\n },\n );\n\n for (const element of observedElements) {\n resizeObserver.observe(element);\n }\n\n return () => {\n resizeObserver.disconnect();\n };\n }, [open, setOpen, targetWindow]);\n\n useIsomorphicLayoutEffect(() => {\n if (open && !hasOverflowItems) {\n setOpen(false);\n }\n }, [hasOverflowItems, open, setOpen]);\n\n useIsomorphicLayoutEffect(() => {\n if (hasOverflowItems && !hadOverflowItemsRef.current) {\n setOpen(false);\n }\n\n hadOverflowItemsRef.current = hasOverflowItems;\n }, [hasOverflowItems, setOpen]);\n\n useIsomorphicLayoutEffect(() => {\n if (overflowId && overflowRef.current && hasOverflowItems) {\n const item = {\n id: overflowId,\n value: overflowId,\n element: overflowRef.current,\n location: \"main\" as const,\n order: initialOrderRef.current,\n };\n\n return registerTab(item);\n }\n }, [hasOverflowItems, overflowId, registerTab]);\n\n useIsomorphicLayoutEffect(() => {\n if (!overflowId || !hasOverflowItems) {\n return;\n }\n\n updateTab(overflowId, {\n element: overflowRef.current,\n location: \"main\",\n order,\n });\n }, [hasOverflowItems, order, overflowId, updateTab]);\n\n if (!hasOverflowItems) return null;\n\n return (\n <>\n <Button\n className={clsx(withBaseName(), className)}\n data-overflowbutton\n appearance=\"transparent\"\n sentiment=\"neutral\"\n {...getReferenceProps({\n onFocus: handleFocus,\n })}\n ref={handleRef}\n aria-label=\"Overflow\"\n aria-expanded={open}\n aria-controls={overlayId}\n role=\"tab\"\n tabIndex={-1}\n {...rest}\n >\n <OverflowIcon aria-hidden />\n </Button>\n <FloatingComponent\n ref={handleListRef}\n {...getFloatingProps({\n id: overlayId,\n onKeyDown: handleFloatingKeyDown,\n })}\n focusManagerProps={\n context\n ? {\n context,\n initialFocus: 0,\n returnFocus: false,\n modal: false,\n closeOnFocusOut: true,\n }\n : undefined\n }\n className={withBaseName(\"list\")}\n open={open}\n left={x ?? 0}\n top={y ?? 0}\n position={strategy}\n width={elements.floating?.offsetWidth}\n height={elements.floating?.offsetHeight}\n >\n <div\n role=\"tablist\"\n aria-orientation=\"vertical\"\n className={withBaseName(\"listContainer\")}\n aria-label=\"Overflow tab options\"\n >\n {hiddenValues.map((value) => (\n <TabSlot key={value} slotId={`overflow:${value}`} value={value} />\n ))}\n </div>\n </FloatingComponent>\n </>\n );\n },\n);\n"],"names":["TabOverflowList","tabOverflowListCss","open","_a","elements"],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { useCallback } from 'react';
3
+ import { useTabSlotRegistry } from '../contexts/TabSlotRegistryContext.js';
4
+
5
+ function TabSlot({ slotId, value, ...rest }) {
6
+ const slotRegistry = useTabSlotRegistry();
7
+ const handleRef = useCallback(
8
+ (element) => {
9
+ slotRegistry == null ? void 0 : slotRegistry.registerSlot(slotId, element);
10
+ },
11
+ [slotId, slotRegistry]
12
+ );
13
+ return /* @__PURE__ */ jsx(
14
+ "div",
15
+ {
16
+ role: "presentation",
17
+ "data-tabslot": "",
18
+ "data-slotid": slotId,
19
+ "data-value": value,
20
+ ref: handleRef,
21
+ style: { display: "contents" },
22
+ ...rest
23
+ }
24
+ );
25
+ }
26
+
27
+ export { TabSlot };
28
+ //# sourceMappingURL=TabSlot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TabSlot.js","sources":["../src/tabs/internal/overflow/TabSlot.tsx"],"sourcesContent":["import { type ComponentPropsWithoutRef, useCallback } from \"react\";\nimport { useTabSlotRegistry } from \"../contexts/TabSlotRegistryContext\";\n\nexport interface TabSlotProps extends ComponentPropsWithoutRef<\"div\"> {\n slotId: string;\n value: string;\n}\n\nexport function TabSlot({ slotId, value, ...rest }: TabSlotProps) {\n const slotRegistry = useTabSlotRegistry();\n const handleRef = useCallback(\n (element: HTMLDivElement | null) => {\n slotRegistry?.registerSlot(slotId, element);\n },\n [slotId, slotRegistry],\n );\n\n return (\n <div\n role=\"presentation\"\n data-tabslot=\"\"\n data-slotid={slotId}\n data-value={value}\n ref={handleRef}\n style={{ display: \"contents\" }}\n {...rest}\n />\n );\n}\n"],"names":[],"mappings":";;;;AAQO,SAAS,QAAQ,EAAE,MAAA,EAAQ,KAAA,EAAO,GAAG,MAAK,EAAiB;AAChE,EAAA,MAAM,eAAe,kBAAA,EAAmB;AACxC,EAAA,MAAM,SAAA,GAAY,WAAA;AAAA,IAChB,CAAC,OAAA,KAAmC;AAClC,MAAA,YAAA,IAAA,IAAA,GAAA,MAAA,GAAA,YAAA,CAAc,aAAa,MAAA,EAAQ,OAAA,CAAA;AAAA,IACrC,CAAA;AAAA,IACA,CAAC,QAAQ,YAAY;AAAA,GACvB;AAEA,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,cAAA;AAAA,MACL,cAAA,EAAa,EAAA;AAAA,MACb,aAAA,EAAa,MAAA;AAAA,MACb,YAAA,EAAY,KAAA;AAAA,MACZ,GAAA,EAAK,SAAA;AAAA,MACL,KAAA,EAAO,EAAE,OAAA,EAAS,UAAA,EAAW;AAAA,MAC5B,GAAG;AAAA;AAAA,GACN;AAEJ;;;;"}
@@ -0,0 +1,82 @@
1
+ const MIN_TRUSTED_TAB_WIDTH = 0.5;
2
+ function calculateVisibleCount({
3
+ gap,
4
+ maxWidth: initialMaxWidth,
5
+ overflowWidth,
6
+ pinnedValue,
7
+ tabs
8
+ }) {
9
+ let maxWidth = initialMaxWidth;
10
+ let currentWidth = 0;
11
+ let nextVisibleCount = 0;
12
+ const visibleItems = [];
13
+ while (nextVisibleCount < tabs.length) {
14
+ const item = tabs[nextVisibleCount];
15
+ if (!item) {
16
+ break;
17
+ }
18
+ if (item.width == null) {
19
+ return null;
20
+ }
21
+ const itemWidth = item.width + gap;
22
+ if (currentWidth + itemWidth > maxWidth) {
23
+ break;
24
+ }
25
+ currentWidth += itemWidth;
26
+ visibleItems.push(item);
27
+ nextVisibleCount += 1;
28
+ }
29
+ const allTabsFit = nextVisibleCount >= tabs.length;
30
+ if (allTabsFit) {
31
+ return nextVisibleCount;
32
+ }
33
+ maxWidth -= overflowWidth;
34
+ while (currentWidth > maxWidth) {
35
+ const removed = visibleItems.pop();
36
+ if (!removed) {
37
+ break;
38
+ }
39
+ if (removed.width == null) {
40
+ return null;
41
+ }
42
+ currentWidth -= removed.width + gap;
43
+ nextVisibleCount -= 1;
44
+ }
45
+ const pinnedItem = pinnedValue == null ? null : tabs.find((item) => item.value === pinnedValue) ?? null;
46
+ if (pinnedItem && !visibleItems.includes(pinnedItem)) {
47
+ if (pinnedItem.width == null) {
48
+ return null;
49
+ }
50
+ const pinnedWidth = pinnedItem.width + gap;
51
+ while (currentWidth + pinnedWidth > maxWidth) {
52
+ const removed = visibleItems.pop();
53
+ if (!removed) {
54
+ break;
55
+ }
56
+ if (removed.width == null) {
57
+ return null;
58
+ }
59
+ currentWidth -= removed.width + gap;
60
+ nextVisibleCount -= 1;
61
+ }
62
+ }
63
+ return Math.max(0, nextVisibleCount);
64
+ }
65
+ function partitionVisibleValues(orderedValues, visibleCount, pinnedValue) {
66
+ let visibleValues = orderedValues.slice(0, visibleCount);
67
+ let hiddenValues = orderedValues.slice(visibleCount);
68
+ const hiddenPinnedIndex = pinnedValue != null ? hiddenValues.indexOf(pinnedValue) : -1;
69
+ if (hiddenPinnedIndex !== -1) {
70
+ const pinnedHiddenValue = hiddenValues[hiddenPinnedIndex];
71
+ hiddenValues = hiddenValues.filter(
72
+ (_, index) => index !== hiddenPinnedIndex
73
+ );
74
+ if (pinnedHiddenValue !== void 0) {
75
+ visibleValues = [...visibleValues, pinnedHiddenValue];
76
+ }
77
+ }
78
+ return { visibleValues, hiddenValues };
79
+ }
80
+
81
+ export { MIN_TRUSTED_TAB_WIDTH, calculateVisibleCount, partitionVisibleValues };
82
+ //# sourceMappingURL=overflowMath.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overflowMath.js","sources":["../src/tabs/internal/overflow/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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"}
@@ -0,0 +1,271 @@
1
+ import { useMemo, useState, useRef, useCallback, useEffect } from 'react';
2
+ import 'clsx';
3
+ import { ownerWindow } from '../../../utils/ownerWindow.js';
4
+ import 'react/jsx-runtime';
5
+ import { useIsomorphicLayoutEffect } from '../../../utils/useIsomorphicLayoutEffect.js';
6
+ import '../../../utils/useFloatingUI/useFloatingUI.js';
7
+ import '../../../utils/useId.js';
8
+ import '../../../salt-provider/SaltProvider.js';
9
+ import '../../../viewport/ViewportProvider.js';
10
+ import { isHTMLElement } from '../utils/domUtils.js';
11
+ import { calculateVisibleCount, MIN_TRUSTED_TAB_WIDTH, partitionVisibleValues } from './overflowMath.js';
12
+ import { seedWidthMap, updateWidthMap, getMeasuredWidth, getGapValue } from './widthMeasurement.js';
13
+
14
+ function getTabWidth(tab) {
15
+ const width = tab.width || getMeasuredWidth(tab.root);
16
+ return width > MIN_TRUSTED_TAB_WIDTH ? width : null;
17
+ }
18
+ function getAvailableWidth(element) {
19
+ const parent = element.parentElement;
20
+ if (!parent) {
21
+ return getMeasuredWidth(element);
22
+ }
23
+ const parentWidth = getMeasuredWidth(parent);
24
+ const parentStyles = ownerWindow(parent).getComputedStyle(parent);
25
+ const parentGap = getGapValue(parentStyles);
26
+ const siblings = Array.from(parent.children).filter(
27
+ (child) => {
28
+ if (!isHTMLElement(child) || child === element) {
29
+ return false;
30
+ }
31
+ return ownerWindow(child).getComputedStyle(child).display !== "none";
32
+ }
33
+ );
34
+ const siblingWidth = siblings.reduce((width, sibling) => {
35
+ return width + getMeasuredWidth(sibling);
36
+ }, 0);
37
+ const gapCount = siblings.length > 0 ? siblings.length : 0;
38
+ const availableWidth = Math.max(
39
+ 0,
40
+ parentWidth - siblingWidth - gapCount * parentGap
41
+ );
42
+ return availableWidth;
43
+ }
44
+ function isSelectedValueHidden(selected, hiddenValues) {
45
+ return selected !== void 0 && hiddenValues.includes(selected);
46
+ }
47
+ function getPinnedSelectionValue(selected, selectedIsHidden, pinnedSelectionRef) {
48
+ return selectedIsHidden ? selected : pinnedSelectionRef.current;
49
+ }
50
+ function useOverflow({
51
+ container,
52
+ overflowButton,
53
+ tabs,
54
+ selected,
55
+ menuOpen
56
+ }) {
57
+ const orderedValues = useMemo(() => tabs.map((tab) => tab.value), [tabs]);
58
+ const measurementInputKey = useMemo(() => {
59
+ return tabs.map((tab) => `${tab.value}:${tab.width.toFixed(2)}`).join("\0");
60
+ }, [tabs]);
61
+ const [visibleCount, setVisibleCount] = useState(0);
62
+ const [isMeasuring, setIsMeasuring] = useState(true);
63
+ const [measureRetryVersion, setMeasureRetryVersion] = useState(0);
64
+ const pinnedSelectionRef = useRef(selected);
65
+ const previousOverflowButtonWidthRef = useRef(0);
66
+ const previousMeasurementInputKeyRef = useRef(measurementInputKey);
67
+ const previousMenuOpenRef = useRef(menuOpen);
68
+ const measureRetryFrameRef = useRef(null);
69
+ const measureRetryCountRef = useRef(0);
70
+ const baseHiddenValues = orderedValues.slice(visibleCount);
71
+ const selectedIsHidden = isSelectedValueHidden(selected, baseHiddenValues);
72
+ const pinnedValue = getPinnedSelectionValue(
73
+ selected,
74
+ selectedIsHidden,
75
+ pinnedSelectionRef
76
+ );
77
+ const getCurrentPinnedValue = useCallback(() => {
78
+ return getPinnedSelectionValue(
79
+ selected,
80
+ selectedIsHidden,
81
+ pinnedSelectionRef
82
+ );
83
+ }, [selected, selectedIsHidden]);
84
+ const markMeasurementStale = useCallback(() => {
85
+ setIsMeasuring(true);
86
+ }, []);
87
+ const measureVisibleCount = useCallback(
88
+ (pinnedValue2) => {
89
+ const element = container.current;
90
+ if (!element) {
91
+ return null;
92
+ }
93
+ const maxWidth = getAvailableWidth(element);
94
+ const styles = ownerWindow(element).getComputedStyle(element);
95
+ const gap = getGapValue(styles);
96
+ const overflowWidth = overflowButton.current ? overflowButton.current.offsetWidth + gap : 0;
97
+ const measuredTabs = tabs.map((tab) => ({
98
+ value: tab.value,
99
+ width: getTabWidth(tab)
100
+ }));
101
+ return calculateVisibleCount({
102
+ gap,
103
+ maxWidth,
104
+ overflowWidth,
105
+ pinnedValue: pinnedValue2,
106
+ tabs: measuredTabs
107
+ });
108
+ },
109
+ [container, overflowButton, tabs]
110
+ );
111
+ const clearMeasureRetry = useCallback(() => {
112
+ const element = container.current;
113
+ const frame = measureRetryFrameRef.current;
114
+ if (element && frame != null) {
115
+ ownerWindow(element).cancelAnimationFrame(frame);
116
+ }
117
+ measureRetryFrameRef.current = null;
118
+ measureRetryCountRef.current = 0;
119
+ }, [container]);
120
+ useEffect(() => {
121
+ return clearMeasureRetry;
122
+ }, [clearMeasureRetry]);
123
+ useIsomorphicLayoutEffect(() => {
124
+ if (selected !== void 0 && selectedIsHidden) {
125
+ pinnedSelectionRef.current = selected;
126
+ const nextVisibleCount = measureVisibleCount(selected);
127
+ if (nextVisibleCount == null) {
128
+ markMeasurementStale();
129
+ return;
130
+ }
131
+ if (nextVisibleCount !== visibleCount) {
132
+ setVisibleCount(nextVisibleCount);
133
+ }
134
+ if (isMeasuring) {
135
+ setIsMeasuring(false);
136
+ }
137
+ }
138
+ }, [
139
+ isMeasuring,
140
+ markMeasurementStale,
141
+ measureVisibleCount,
142
+ selected,
143
+ selectedIsHidden,
144
+ visibleCount
145
+ ]);
146
+ useEffect(() => {
147
+ const element = container.current;
148
+ if (!element || menuOpen || isMeasuring) {
149
+ return;
150
+ }
151
+ const observedElements = [element];
152
+ const parent = element.parentElement;
153
+ if (parent) {
154
+ observedElements.push(parent);
155
+ for (const child of Array.from(parent.children)) {
156
+ if (isHTMLElement(child) && child !== element) {
157
+ observedElements.push(child);
158
+ }
159
+ }
160
+ }
161
+ const widths = seedWidthMap(observedElements);
162
+ const resizeObserverCtor = ownerWindow(element).ResizeObserver;
163
+ if (!resizeObserverCtor) {
164
+ return;
165
+ }
166
+ const resizeObserver = new resizeObserverCtor(
167
+ (entries) => {
168
+ for (const entry of entries) {
169
+ if (!isHTMLElement(entry.target)) {
170
+ continue;
171
+ }
172
+ const nextWidth = entry.contentRect.width;
173
+ if (updateWidthMap(widths, entry.target, nextWidth)) {
174
+ const nextVisibleCount = measureVisibleCount(
175
+ getCurrentPinnedValue()
176
+ );
177
+ if (nextVisibleCount != null && nextVisibleCount === visibleCount) {
178
+ continue;
179
+ }
180
+ markMeasurementStale();
181
+ return;
182
+ }
183
+ }
184
+ }
185
+ );
186
+ for (const observedElement of observedElements) {
187
+ resizeObserver.observe(observedElement);
188
+ }
189
+ return () => {
190
+ resizeObserver.disconnect();
191
+ };
192
+ }, [
193
+ container,
194
+ getCurrentPinnedValue,
195
+ isMeasuring,
196
+ markMeasurementStale,
197
+ measureVisibleCount,
198
+ menuOpen,
199
+ visibleCount
200
+ ]);
201
+ useIsomorphicLayoutEffect(() => {
202
+ if (previousMenuOpenRef.current && !menuOpen) {
203
+ markMeasurementStale();
204
+ }
205
+ previousMenuOpenRef.current = menuOpen;
206
+ }, [markMeasurementStale, menuOpen]);
207
+ useIsomorphicLayoutEffect(() => {
208
+ var _a;
209
+ const nextOverflowButtonWidth = ((_a = overflowButton.current) == null ? void 0 : _a.offsetWidth) ?? 0;
210
+ if (previousOverflowButtonWidthRef.current === nextOverflowButtonWidth) {
211
+ return;
212
+ }
213
+ previousOverflowButtonWidthRef.current = nextOverflowButtonWidth;
214
+ if (visibleCount < tabs.length) {
215
+ markMeasurementStale();
216
+ }
217
+ });
218
+ useIsomorphicLayoutEffect(() => {
219
+ if (previousMeasurementInputKeyRef.current !== measurementInputKey) {
220
+ previousMeasurementInputKeyRef.current = measurementInputKey;
221
+ markMeasurementStale();
222
+ }
223
+ }, [markMeasurementStale, measurementInputKey]);
224
+ useIsomorphicLayoutEffect(() => {
225
+ if (!isMeasuring || menuOpen) {
226
+ return;
227
+ }
228
+ const nextVisibleCount = measureVisibleCount(getCurrentPinnedValue());
229
+ if (nextVisibleCount == null) {
230
+ if (measureRetryFrameRef.current != null) {
231
+ return;
232
+ }
233
+ const element = container.current;
234
+ if (!element || getMeasuredWidth(element) <= MIN_TRUSTED_TAB_WIDTH) {
235
+ measureRetryCountRef.current = 0;
236
+ return;
237
+ }
238
+ if (measureRetryCountRef.current >= 5) {
239
+ return;
240
+ }
241
+ measureRetryCountRef.current += 1;
242
+ measureRetryFrameRef.current = ownerWindow(element).requestAnimationFrame(
243
+ () => {
244
+ measureRetryFrameRef.current = null;
245
+ setMeasureRetryVersion((currentVersion) => currentVersion + 1);
246
+ }
247
+ );
248
+ return;
249
+ }
250
+ clearMeasureRetry();
251
+ setVisibleCount(nextVisibleCount);
252
+ setIsMeasuring(false);
253
+ }, [
254
+ clearMeasureRetry,
255
+ container.current,
256
+ getCurrentPinnedValue,
257
+ isMeasuring,
258
+ measureRetryVersion,
259
+ measureVisibleCount,
260
+ menuOpen
261
+ ]);
262
+ const { visibleValues, hiddenValues } = partitionVisibleValues(
263
+ orderedValues,
264
+ visibleCount,
265
+ pinnedValue
266
+ );
267
+ return [visibleValues, hiddenValues, isMeasuring];
268
+ }
269
+
270
+ export { useOverflow };
271
+ //# sourceMappingURL=useOverflow.js.map
@@ -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