@salt-ds/lab 1.0.0-alpha.60 → 1.0.0-alpha.62

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 (96) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/css/salt-lab.css +185 -1
  3. package/dist-cjs/date-picker/DatePickerRangeInput.js +1 -0
  4. package/dist-cjs/date-picker/DatePickerRangeInput.js.map +1 -1
  5. package/dist-cjs/date-picker/DatePickerSingleInput.js +1 -0
  6. package/dist-cjs/date-picker/DatePickerSingleInput.js.map +1 -1
  7. package/dist-cjs/index.js +6 -0
  8. package/dist-cjs/index.js.map +1 -1
  9. package/dist-cjs/splitter/SplitHandle.css.js +6 -0
  10. package/dist-cjs/splitter/SplitHandle.css.js.map +1 -0
  11. package/dist-cjs/splitter/SplitHandle.js +60 -0
  12. package/dist-cjs/splitter/SplitHandle.js.map +1 -0
  13. package/dist-cjs/splitter/SplitPanel.css.js +6 -0
  14. package/dist-cjs/splitter/SplitPanel.css.js.map +1 -0
  15. package/dist-cjs/splitter/SplitPanel.js +37 -0
  16. package/dist-cjs/splitter/SplitPanel.js.map +1 -0
  17. package/dist-cjs/splitter/Splitter.js +31 -0
  18. package/dist-cjs/splitter/Splitter.js.map +1 -0
  19. package/dist-cjs/splitter/utils.js +18 -0
  20. package/dist-cjs/splitter/utils.js.map +1 -0
  21. package/dist-cjs/stepped-tracker/stepReducer.js +127 -81
  22. package/dist-cjs/stepped-tracker/stepReducer.js.map +1 -1
  23. package/dist-cjs/stepped-tracker/useStepReducer.js +6 -4
  24. package/dist-cjs/stepped-tracker/useStepReducer.js.map +1 -1
  25. package/dist-cjs/stepped-tracker/utils.js +44 -9
  26. package/dist-cjs/stepped-tracker/utils.js.map +1 -1
  27. package/dist-cjs/stepper-input/StepperInput.js +6 -5
  28. package/dist-cjs/stepper-input/StepperInput.js.map +1 -1
  29. package/dist-cjs/tabs-next/TabListNext.css.js +1 -1
  30. package/dist-cjs/tabs-next/TabListNext.js +10 -16
  31. package/dist-cjs/tabs-next/TabListNext.js.map +1 -1
  32. package/dist-cjs/tabs-next/TabOverflowList.js +1 -1
  33. package/dist-cjs/tabs-next/TabOverflowList.js.map +1 -1
  34. package/dist-cjs/tabs-next/TabsNext.js +4 -51
  35. package/dist-cjs/tabs-next/TabsNext.js.map +1 -1
  36. package/dist-cjs/tabs-next/TabsNextContext.js +1 -1
  37. package/dist-cjs/tabs-next/TabsNextContext.js.map +1 -1
  38. package/dist-cjs/tabs-next/hooks/useCollection.js.map +1 -1
  39. package/dist-cjs/tabs-next/hooks/useOverflow.js +48 -5
  40. package/dist-cjs/tabs-next/hooks/useOverflow.js.map +1 -1
  41. package/dist-cjs/tabs-next/hooks/useRestoreActiveTab.js +93 -0
  42. package/dist-cjs/tabs-next/hooks/useRestoreActiveTab.js.map +1 -0
  43. package/dist-es/date-picker/DatePickerRangeInput.js +1 -0
  44. package/dist-es/date-picker/DatePickerRangeInput.js.map +1 -1
  45. package/dist-es/date-picker/DatePickerSingleInput.js +1 -0
  46. package/dist-es/date-picker/DatePickerSingleInput.js.map +1 -1
  47. package/dist-es/index.js +3 -0
  48. package/dist-es/index.js.map +1 -1
  49. package/dist-es/splitter/SplitHandle.css.js +4 -0
  50. package/dist-es/splitter/SplitHandle.css.js.map +1 -0
  51. package/dist-es/splitter/SplitHandle.js +58 -0
  52. package/dist-es/splitter/SplitHandle.js.map +1 -0
  53. package/dist-es/splitter/SplitPanel.css.js +4 -0
  54. package/dist-es/splitter/SplitPanel.css.js.map +1 -0
  55. package/dist-es/splitter/SplitPanel.js +35 -0
  56. package/dist-es/splitter/SplitPanel.js.map +1 -0
  57. package/dist-es/splitter/Splitter.js +27 -0
  58. package/dist-es/splitter/Splitter.js.map +1 -0
  59. package/dist-es/splitter/utils.js +15 -0
  60. package/dist-es/splitter/utils.js.map +1 -0
  61. package/dist-es/stepped-tracker/stepReducer.js +128 -82
  62. package/dist-es/stepped-tracker/stepReducer.js.map +1 -1
  63. package/dist-es/stepped-tracker/useStepReducer.js +7 -5
  64. package/dist-es/stepped-tracker/useStepReducer.js.map +1 -1
  65. package/dist-es/stepped-tracker/utils.js +43 -9
  66. package/dist-es/stepped-tracker/utils.js.map +1 -1
  67. package/dist-es/stepper-input/StepperInput.js +6 -5
  68. package/dist-es/stepper-input/StepperInput.js.map +1 -1
  69. package/dist-es/tabs-next/TabListNext.css.js +1 -1
  70. package/dist-es/tabs-next/TabListNext.js +11 -17
  71. package/dist-es/tabs-next/TabListNext.js.map +1 -1
  72. package/dist-es/tabs-next/TabOverflowList.js +1 -1
  73. package/dist-es/tabs-next/TabOverflowList.js.map +1 -1
  74. package/dist-es/tabs-next/TabsNext.js +5 -52
  75. package/dist-es/tabs-next/TabsNext.js.map +1 -1
  76. package/dist-es/tabs-next/TabsNextContext.js +1 -1
  77. package/dist-es/tabs-next/TabsNextContext.js.map +1 -1
  78. package/dist-es/tabs-next/hooks/useCollection.js.map +1 -1
  79. package/dist-es/tabs-next/hooks/useOverflow.js +49 -6
  80. package/dist-es/tabs-next/hooks/useOverflow.js.map +1 -1
  81. package/dist-es/tabs-next/hooks/useRestoreActiveTab.js +91 -0
  82. package/dist-es/tabs-next/hooks/useRestoreActiveTab.js.map +1 -0
  83. package/dist-types/index.d.ts +1 -0
  84. package/dist-types/splitter/SplitHandle.d.ts +21 -0
  85. package/dist-types/splitter/SplitPanel.d.ts +10 -0
  86. package/dist-types/splitter/Splitter.d.ts +22 -0
  87. package/dist-types/splitter/index.d.ts +4 -0
  88. package/dist-types/splitter/utils.d.ts +4 -0
  89. package/dist-types/stepped-tracker/Step.types.d.ts +2 -4
  90. package/dist-types/stepped-tracker/stepReducer.types.d.ts +6 -4
  91. package/dist-types/stepped-tracker/utils.d.ts +6 -3
  92. package/dist-types/tabs/drag-drop/drag-utils.d.ts +6 -6
  93. package/dist-types/tabs-next/TabsNextContext.d.ts +1 -1
  94. package/dist-types/tabs-next/hooks/useOverflow.d.ts +1 -1
  95. package/dist-types/tabs-next/hooks/useRestoreActiveTab.d.ts +10 -0
  96. package/package.json +5 -4
@@ -1,6 +1,6 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import { forwardRef, useState, useRef, useCallback, useMemo } from 'react';
3
- import { makePrefixer, useControlled, useIsomorphicLayoutEffect, useEventCallback } from '@salt-ds/core';
3
+ import { makePrefixer, useControlled, useEventCallback } from '@salt-ds/core';
4
4
  import { clsx } from 'clsx';
5
5
  import { TabsNextContext } from './TabsNextContext.js';
6
6
  import { useCollection } from './hooks/useCollection.js';
@@ -25,7 +25,7 @@ const TabsNext = forwardRef(
25
25
  items
26
26
  } = useCollection({ wrap: true });
27
27
  const activeTab = useRef();
28
- const returnFocus = useRef(void 0);
28
+ const removedActiveTabRef = useRef(void 0);
29
29
  const [menuOpen, setMenuOpen] = useState(false);
30
30
  const [selected, setSelectedState] = useControlled({
31
31
  controlled: value,
@@ -33,10 +33,6 @@ const TabsNext = forwardRef(
33
33
  name: "TabListNext",
34
34
  state: "selected"
35
35
  });
36
- const selectedRef = useRef(void 0);
37
- useIsomorphicLayoutEffect(() => {
38
- selectedRef.current = selected;
39
- }, [selected]);
40
36
  const setSelected = useCallback(
41
37
  (event, value2) => {
42
38
  setMenuOpen(false);
@@ -53,7 +49,7 @@ const TabsNext = forwardRef(
53
49
  });
54
50
  return () => {
55
51
  var _a;
56
- const items2 = cleanup();
52
+ cleanup();
57
53
  setValueToIdMap(({ map }) => {
58
54
  map.delete(item2.value);
59
55
  return { map };
@@ -61,50 +57,7 @@ const TabsNext = forwardRef(
61
57
  if (((_a = activeTab.current) == null ? void 0 : _a.value) !== item2.value) {
62
58
  return;
63
59
  }
64
- returnFocus.current = item2.value;
65
- const containFocus = () => {
66
- var _a2;
67
- const activeIndex = items2.current.findIndex(
68
- (i) => item2.value === i.value
69
- );
70
- const nextIndex = activeIndex === items2.current.length - 1 ? items2.current.length - 2 : activeIndex + 1;
71
- const nextActive = items2.current[nextIndex];
72
- returnFocus.current = nextActive.value;
73
- if (selectedRef.current === item2.value) {
74
- setSelected(null, nextActive.value);
75
- }
76
- (_a2 = nextActive == null ? void 0 : nextActive.element) == null ? void 0 : _a2.focus();
77
- };
78
- if (document.activeElement === document.body) {
79
- requestAnimationFrame(() => {
80
- if (document.activeElement === document.body) {
81
- containFocus();
82
- }
83
- });
84
- } else {
85
- const handleFocusOut = (event) => {
86
- if (!event.relatedTarget) {
87
- requestAnimationFrame(() => {
88
- if (document.activeElement === document.body) {
89
- containFocus();
90
- }
91
- });
92
- }
93
- };
94
- item2.element.ownerDocument.addEventListener(
95
- "focusout",
96
- handleFocusOut,
97
- {
98
- once: true
99
- }
100
- );
101
- setTimeout(() => {
102
- item2.element.ownerDocument.removeEventListener(
103
- "focusout",
104
- handleFocusOut
105
- );
106
- }, 1e3);
107
- }
60
+ removedActiveTabRef.current = item2.value;
108
61
  };
109
62
  });
110
63
  const registerPanel = useCallback((id, value2) => {
@@ -148,7 +101,7 @@ const TabsNext = forwardRef(
148
101
  activeTab,
149
102
  menuOpen,
150
103
  setMenuOpen,
151
- returnFocus
104
+ removedActiveTabRef
152
105
  }),
153
106
  [
154
107
  registerPanel,
@@ -1 +1 @@
1
- {"version":3,"file":"TabsNext.js","sources":["../src/tabs-next/TabsNext.tsx"],"sourcesContent":["import {\n type ComponentPropsWithoutRef,\n type ReactNode,\n type SyntheticEvent,\n forwardRef,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport {\n makePrefixer,\n useControlled,\n useEventCallback,\n useIsomorphicLayoutEffect,\n} from \"@salt-ds/core\";\nimport { clsx } from \"clsx\";\nimport { type Item, TabsNextContext } from \"./TabsNextContext\";\nimport { useCollection } from \"./hooks/useCollection\";\n\nexport interface TabsNextProps\n extends Omit<ComponentPropsWithoutRef<\"div\">, \"onChange\"> {\n children?: ReactNode;\n /**\n * The default value. Use when the component is not controlled.\n */\n defaultValue?: string;\n /**\n * The value. Use when the component is controlled.\n */\n value?: string;\n /**\n * Callback fired when the selection changes. The event will be null when selection is moved automatically.\n */\n onChange?: (event: SyntheticEvent | null, value: string) => void;\n}\n\nconst withBaseName = makePrefixer(\"saltTabsNext\");\n\nexport const TabsNext = forwardRef<HTMLDivElement, TabsNextProps>(\n function TabsNext(props, ref) {\n const { className, children, value, defaultValue, onChange, ...rest } =\n props;\n\n const [valueToTabIdMap, setValueToIdMap] = useState({\n map: new Map<string, string>(),\n });\n const [valueToPanelIdMap, setValueToPanelIdMap] = useState({\n map: new Map<string, string>(),\n });\n\n const {\n registerItem,\n item,\n getNext,\n getPrevious,\n getFirst,\n getLast,\n items,\n } = useCollection({ wrap: true });\n\n const activeTab = useRef<Pick<Item, \"id\" | \"value\">>();\n const returnFocus = useRef<string | undefined>(undefined);\n\n const [menuOpen, setMenuOpen] = useState(false);\n\n const [selected, setSelectedState] = useControlled({\n controlled: value,\n default: defaultValue,\n name: \"TabListNext\",\n state: \"selected\",\n });\n\n // This ref is needed so we can read the current selected item in the containFocus() function.\n const selectedRef = useRef<string | undefined>(undefined);\n useIsomorphicLayoutEffect(() => {\n selectedRef.current = selected;\n }, [selected]);\n\n const setSelected = useCallback(\n (event: SyntheticEvent | null, value: string) => {\n setMenuOpen(false);\n setSelectedState(value);\n onChange?.(event, value);\n },\n [onChange],\n );\n\n const registerTab = useEventCallback((item: Item) => {\n const cleanup = registerItem(item);\n setValueToIdMap(({ map }) => {\n map.set(item.value, item.id);\n return { map };\n });\n\n return () => {\n const items = cleanup();\n setValueToIdMap(({ map }) => {\n map.delete(item.value);\n return { map };\n });\n\n if (activeTab.current?.value !== item.value) {\n return;\n }\n\n returnFocus.current = item.value;\n\n const containFocus = () => {\n const activeIndex = items.current.findIndex(\n (i) => item.value === i.value,\n );\n\n const nextIndex =\n activeIndex === items.current.length - 1\n ? items.current.length - 2\n : activeIndex + 1;\n\n const nextActive = items.current[nextIndex];\n\n returnFocus.current = nextActive.value;\n\n if (selectedRef.current === item.value) {\n setSelected(null, nextActive.value);\n }\n\n nextActive?.element?.focus();\n };\n\n if (document.activeElement === document.body) {\n requestAnimationFrame(() => {\n if (document.activeElement === document.body) {\n containFocus();\n }\n });\n } else {\n const handleFocusOut = (event: FocusEvent) => {\n if (!event.relatedTarget) {\n requestAnimationFrame(() => {\n if (document.activeElement === document.body) {\n containFocus();\n }\n });\n }\n };\n\n item.element.ownerDocument.addEventListener(\n \"focusout\",\n handleFocusOut,\n {\n once: true,\n },\n );\n\n setTimeout(() => {\n item.element.ownerDocument.removeEventListener(\n \"focusout\",\n handleFocusOut,\n );\n }, 1000);\n }\n };\n });\n\n const registerPanel = useCallback((id: string, value: string) => {\n setValueToPanelIdMap(({ map }) => {\n map.set(value, id);\n return { map };\n });\n return () => {\n setValueToIdMap(({ map }) => {\n map.delete(value);\n return { map };\n });\n };\n }, []);\n\n const getPanelId = useCallback(\n (value: string) => {\n return valueToPanelIdMap.map.get(value);\n },\n [valueToPanelIdMap],\n );\n\n const getTabId = useCallback(\n (value: string) => {\n return valueToTabIdMap.map.get(value);\n },\n [valueToTabIdMap],\n );\n\n const context = useMemo(\n () => ({\n registerTab,\n registerPanel,\n getPanelId,\n getTabId,\n selected,\n setSelected,\n item,\n getNext,\n getPrevious,\n getFirst,\n getLast,\n items,\n activeTab,\n menuOpen,\n setMenuOpen,\n returnFocus,\n }),\n [\n registerPanel,\n registerTab,\n getPanelId,\n getTabId,\n selected,\n setSelected,\n item,\n getNext,\n getPrevious,\n getFirst,\n getLast,\n items,\n menuOpen,\n ],\n );\n\n return (\n <TabsNextContext.Provider value={context}>\n <div className={clsx(withBaseName(), className)} ref={ref} {...rest}>\n {children}\n </div>\n </TabsNextContext.Provider>\n );\n },\n);\n"],"names":["TabsNext","value","item","items","_a"],"mappings":"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"}
1
+ {"version":3,"file":"TabsNext.js","sources":["../src/tabs-next/TabsNext.tsx"],"sourcesContent":["import {\n type ComponentPropsWithoutRef,\n type ReactNode,\n type SyntheticEvent,\n forwardRef,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport { makePrefixer, useControlled, useEventCallback } from \"@salt-ds/core\";\nimport { clsx } from \"clsx\";\nimport { type Item, TabsNextContext } from \"./TabsNextContext\";\nimport { useCollection } from \"./hooks/useCollection\";\n\nexport interface TabsNextProps\n extends Omit<ComponentPropsWithoutRef<\"div\">, \"onChange\"> {\n children?: ReactNode;\n /**\n * The default value. Use when the component is not controlled.\n */\n defaultValue?: string;\n /**\n * The value. Use when the component is controlled.\n */\n value?: string;\n /**\n * Callback fired when the selection changes. The event will be null when selection is moved automatically.\n */\n onChange?: (event: SyntheticEvent | null, value: string) => void;\n}\n\nconst withBaseName = makePrefixer(\"saltTabsNext\");\n\nexport const TabsNext = forwardRef<HTMLDivElement, TabsNextProps>(\n function TabsNext(props, ref) {\n const { className, children, value, defaultValue, onChange, ...rest } =\n props;\n\n const [valueToTabIdMap, setValueToIdMap] = useState({\n map: new Map<string, string>(),\n });\n const [valueToPanelIdMap, setValueToPanelIdMap] = useState({\n map: new Map<string, string>(),\n });\n\n const {\n registerItem,\n item,\n getNext,\n getPrevious,\n getFirst,\n getLast,\n items,\n } = useCollection({ wrap: true });\n\n const activeTab = useRef<Pick<Item, \"id\" | \"value\">>();\n const removedActiveTabRef = useRef<string | undefined>(undefined);\n\n const [menuOpen, setMenuOpen] = useState(false);\n\n const [selected, setSelectedState] = useControlled({\n controlled: value,\n default: defaultValue,\n name: \"TabListNext\",\n state: \"selected\",\n });\n\n const setSelected = useCallback(\n (event: SyntheticEvent | null, value: string) => {\n setMenuOpen(false);\n setSelectedState(value);\n onChange?.(event, value);\n },\n [onChange],\n );\n\n const registerTab = useEventCallback((item: Item) => {\n const cleanup = registerItem(item);\n setValueToIdMap(({ map }) => {\n map.set(item.value, item.id);\n return { map };\n });\n\n return () => {\n cleanup();\n setValueToIdMap(({ map }) => {\n map.delete(item.value);\n return { map };\n });\n\n if (activeTab.current?.value !== item.value) {\n return;\n }\n\n removedActiveTabRef.current = item.value;\n };\n });\n\n const registerPanel = useCallback((id: string, value: string) => {\n setValueToPanelIdMap(({ map }) => {\n map.set(value, id);\n return { map };\n });\n return () => {\n setValueToIdMap(({ map }) => {\n map.delete(value);\n return { map };\n });\n };\n }, []);\n\n const getPanelId = useCallback(\n (value: string) => {\n return valueToPanelIdMap.map.get(value);\n },\n [valueToPanelIdMap],\n );\n\n const getTabId = useCallback(\n (value: string) => {\n return valueToTabIdMap.map.get(value);\n },\n [valueToTabIdMap],\n );\n\n const context = useMemo(\n () => ({\n registerTab,\n registerPanel,\n getPanelId,\n getTabId,\n selected,\n setSelected,\n item,\n getNext,\n getPrevious,\n getFirst,\n getLast,\n items,\n activeTab,\n menuOpen,\n setMenuOpen,\n removedActiveTabRef,\n }),\n [\n registerPanel,\n registerTab,\n getPanelId,\n getTabId,\n selected,\n setSelected,\n item,\n getNext,\n getPrevious,\n getFirst,\n getLast,\n items,\n menuOpen,\n ],\n );\n\n return (\n <TabsNextContext.Provider value={context}>\n <div className={clsx(withBaseName(), className)} ref={ref} {...rest}>\n {children}\n </div>\n </TabsNextContext.Provider>\n );\n },\n);\n"],"names":["TabsNext","value","item"],"mappings":"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"}
@@ -17,7 +17,7 @@ const TabsNextContext = createContext(
17
17
  getTabId: () => void 0,
18
18
  setSelected: () => void 0,
19
19
  activeTab: { current: void 0 },
20
- returnFocus: { current: void 0 },
20
+ removedActiveTabRef: { current: void 0 },
21
21
  menuOpen: false,
22
22
  setMenuOpen: () => void 0
23
23
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TabsNextContext.js","sources":["../src/tabs-next/TabsNextContext.tsx"],"sourcesContent":["import { createContext } from \"@salt-ds/core\";\nimport {\n type Dispatch,\n type MutableRefObject,\n type SetStateAction,\n type SyntheticEvent,\n useContext,\n} from \"react\";\nimport type { useCollection } from \"./hooks/useCollection\";\n\nexport interface Item {\n id: string;\n value: string;\n element: HTMLElement;\n}\n\nexport interface TabsNextContextValue\n extends Omit<ReturnType<typeof useCollection>, \"registerItem\"> {\n registerTab: (item: Item) => () => void;\n registerPanel: (id: string, value: string) => () => void;\n getPanelId: (value: string) => string | undefined;\n getTabId: (value: string) => string | undefined;\n selected?: string;\n setSelected: (event: SyntheticEvent, value: string) => void;\n activeTab: MutableRefObject<Pick<Item, \"id\" | \"value\"> | undefined>;\n returnFocus: MutableRefObject<string | undefined>;\n menuOpen: boolean;\n setMenuOpen: Dispatch<SetStateAction<boolean>>;\n}\n\nexport const TabsNextContext = createContext<TabsNextContextValue>(\n \"TabsNextContext\",\n {\n getFirst: () => null,\n getLast: () => null,\n getNext: () => null,\n getPrevious: () => null,\n item: () => null,\n items: [],\n selected: undefined,\n registerTab: () => () => undefined,\n registerPanel: () => () => undefined,\n getPanelId: () => undefined,\n getTabId: () => undefined,\n setSelected: () => undefined,\n activeTab: { current: undefined },\n returnFocus: { current: undefined },\n menuOpen: false,\n setMenuOpen: () => undefined,\n },\n);\n\nexport function useTabsNext() {\n return useContext(TabsNextContext);\n}\n"],"names":[],"mappings":";;;AA8BO,MAAM,eAAkB,GAAA,aAAA;AAAA,EAC7B,iBAAA;AAAA,EACA;AAAA,IACE,UAAU,MAAM,IAAA;AAAA,IAChB,SAAS,MAAM,IAAA;AAAA,IACf,SAAS,MAAM,IAAA;AAAA,IACf,aAAa,MAAM,IAAA;AAAA,IACnB,MAAM,MAAM,IAAA;AAAA,IACZ,OAAO,EAAC;AAAA,IACR,QAAU,EAAA,KAAA,CAAA;AAAA,IACV,WAAA,EAAa,MAAM,MAAM,KAAA,CAAA;AAAA,IACzB,aAAA,EAAe,MAAM,MAAM,KAAA,CAAA;AAAA,IAC3B,YAAY,MAAM,KAAA,CAAA;AAAA,IAClB,UAAU,MAAM,KAAA,CAAA;AAAA,IAChB,aAAa,MAAM,KAAA,CAAA;AAAA,IACnB,SAAA,EAAW,EAAE,OAAA,EAAS,KAAU,CAAA,EAAA;AAAA,IAChC,WAAA,EAAa,EAAE,OAAA,EAAS,KAAU,CAAA,EAAA;AAAA,IAClC,QAAU,EAAA,KAAA;AAAA,IACV,aAAa,MAAM,KAAA;AAAA;AAEvB;AAEO,SAAS,WAAc,GAAA;AAC5B,EAAA,OAAO,WAAW,eAAe,CAAA;AACnC;;;;"}
1
+ {"version":3,"file":"TabsNextContext.js","sources":["../src/tabs-next/TabsNextContext.tsx"],"sourcesContent":["import { createContext } from \"@salt-ds/core\";\nimport {\n type Dispatch,\n type MutableRefObject,\n type SetStateAction,\n type SyntheticEvent,\n useContext,\n} from \"react\";\nimport type { useCollection } from \"./hooks/useCollection\";\n\nexport interface Item {\n id: string;\n value: string;\n element: HTMLElement;\n}\n\nexport interface TabsNextContextValue\n extends Omit<ReturnType<typeof useCollection>, \"registerItem\"> {\n registerTab: (item: Item) => () => void;\n registerPanel: (id: string, value: string) => () => void;\n getPanelId: (value: string) => string | undefined;\n getTabId: (value: string) => string | undefined;\n selected?: string;\n setSelected: (event: SyntheticEvent, value: string) => void;\n activeTab: MutableRefObject<Pick<Item, \"id\" | \"value\"> | undefined>;\n removedActiveTabRef: MutableRefObject<string | undefined>;\n menuOpen: boolean;\n setMenuOpen: Dispatch<SetStateAction<boolean>>;\n}\n\nexport const TabsNextContext = createContext<TabsNextContextValue>(\n \"TabsNextContext\",\n {\n getFirst: () => null,\n getLast: () => null,\n getNext: () => null,\n getPrevious: () => null,\n item: () => null,\n items: [],\n selected: undefined,\n registerTab: () => () => undefined,\n registerPanel: () => () => undefined,\n getPanelId: () => undefined,\n getTabId: () => undefined,\n setSelected: () => undefined,\n activeTab: { current: undefined },\n removedActiveTabRef: { current: undefined },\n menuOpen: false,\n setMenuOpen: () => undefined,\n },\n);\n\nexport function useTabsNext() {\n return useContext(TabsNextContext);\n}\n"],"names":[],"mappings":";;;AA8BO,MAAM,eAAkB,GAAA,aAAA;AAAA,EAC7B,iBAAA;AAAA,EACA;AAAA,IACE,UAAU,MAAM,IAAA;AAAA,IAChB,SAAS,MAAM,IAAA;AAAA,IACf,SAAS,MAAM,IAAA;AAAA,IACf,aAAa,MAAM,IAAA;AAAA,IACnB,MAAM,MAAM,IAAA;AAAA,IACZ,OAAO,EAAC;AAAA,IACR,QAAU,EAAA,KAAA,CAAA;AAAA,IACV,WAAA,EAAa,MAAM,MAAM,KAAA,CAAA;AAAA,IACzB,aAAA,EAAe,MAAM,MAAM,KAAA,CAAA;AAAA,IAC3B,YAAY,MAAM,KAAA,CAAA;AAAA,IAClB,UAAU,MAAM,KAAA,CAAA;AAAA,IAChB,aAAa,MAAM,KAAA,CAAA;AAAA,IACnB,SAAA,EAAW,EAAE,OAAA,EAAS,KAAU,CAAA,EAAA;AAAA,IAChC,mBAAA,EAAqB,EAAE,OAAA,EAAS,KAAU,CAAA,EAAA;AAAA,IAC1C,QAAU,EAAA,KAAA;AAAA,IACV,aAAa,MAAM,KAAA;AAAA;AAEvB;AAEO,SAAS,WAAc,GAAA;AAC5B,EAAA,OAAO,WAAW,eAAe,CAAA;AACnC;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"useCollection.js","sources":["../src/tabs-next/hooks/useCollection.tsx"],"sourcesContent":["import { useCallback, useRef, useState } from \"react\";\n\nexport interface Item {\n id: string;\n element?: HTMLElement | null;\n value: string;\n}\n\nfunction sortBasedOnDOMPosition(items: Item[]): Item[] {\n const indexedItems = items.map((item, index) => [index, item] as const);\n let orderChanged = false;\n indexedItems.sort(([itemAIndex, itemA], [itemBIndex, itemB]) => {\n const itemAElement = itemA.element;\n const itemBElement = itemB.element;\n if (itemAElement === itemBElement) return 0;\n if (!itemAElement || !itemBElement) return 0;\n\n if (\n itemAElement.compareDocumentPosition(itemBElement) &\n Node.DOCUMENT_POSITION_FOLLOWING\n ) {\n if (itemAIndex > itemBIndex) {\n orderChanged = true;\n }\n return -1;\n }\n\n if (itemAIndex < itemBIndex) {\n orderChanged = true;\n }\n return 1;\n });\n\n if (orderChanged) {\n return indexedItems.map(([_, item]) => item);\n }\n return items;\n}\n\ninterface UseCollectionProps {\n wrap: boolean;\n}\n\nexport function useCollection({ wrap }: UseCollectionProps) {\n const [items, setItems] = useState<Item[]>([]);\n const itemsRef = useRef<Item[]>([]);\n const itemMap = useRef<Map<string, Item>>(new Map());\n\n const registerItem = useCallback((item: Item) => {\n setItems((old) => {\n const newItems = old.slice();\n const index = newItems.findIndex(({ id }) => id === item.id);\n if (index !== -1) {\n const newItem = { ...newItems[index], ...item };\n newItems[index] = newItem;\n itemMap.current.set(item.id, newItem);\n } else {\n newItems.push(item);\n itemMap.current.set(item.id, item);\n }\n const value = sortBasedOnDOMPosition(newItems);\n itemsRef.current = value;\n return value;\n });\n\n return () => {\n setItems((old) => {\n itemMap.current.delete(item.id);\n return old.filter(({ id }) => id !== item.id);\n });\n return itemsRef;\n };\n }, []);\n\n return {\n registerItem,\n item: (id?: string | null): Item | null => {\n if (!id) return null;\n let item = itemMap.current.get(id);\n if (!item) {\n item = items.find((item) => item.id === id);\n if (item) {\n itemMap.current.set(item.id, item);\n }\n }\n return item ?? null;\n },\n getNext: (current: string): Item | null => {\n const index = items.findIndex(({ id }) => id === current);\n\n const newIndex = wrap\n ? (index + 1) % items.length\n : Math.min(index + 1, items.length - 1);\n\n return items[newIndex] ?? null;\n },\n getPrevious: (current: string): Item | null => {\n const index = items.findIndex(({ id }) => id === current);\n\n const newIndex = wrap\n ? (index - 1 + items.length) % items.length\n : Math.max(index - 1, 0);\n\n return items[newIndex] ?? null;\n },\n getFirst: (): Item | null => {\n return items[0] ?? null;\n },\n getLast: (): Item | null => {\n return items[items.length - 1] ?? null;\n },\n items,\n };\n}\n"],"names":["item"],"mappings":"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"}
1
+ {"version":3,"file":"useCollection.js","sources":["../src/tabs-next/hooks/useCollection.ts"],"sourcesContent":["import { useCallback, useRef, useState } from \"react\";\n\nexport interface Item {\n id: string;\n element?: HTMLElement | null;\n value: string;\n}\n\nfunction sortBasedOnDOMPosition(items: Item[]): Item[] {\n const indexedItems = items.map((item, index) => [index, item] as const);\n let orderChanged = false;\n indexedItems.sort(([itemAIndex, itemA], [itemBIndex, itemB]) => {\n const itemAElement = itemA.element;\n const itemBElement = itemB.element;\n if (itemAElement === itemBElement) return 0;\n if (!itemAElement || !itemBElement) return 0;\n\n if (\n itemAElement.compareDocumentPosition(itemBElement) &\n Node.DOCUMENT_POSITION_FOLLOWING\n ) {\n if (itemAIndex > itemBIndex) {\n orderChanged = true;\n }\n return -1;\n }\n\n if (itemAIndex < itemBIndex) {\n orderChanged = true;\n }\n return 1;\n });\n\n if (orderChanged) {\n return indexedItems.map(([_, item]) => item);\n }\n return items;\n}\n\ninterface UseCollectionProps {\n wrap: boolean;\n}\n\nexport function useCollection({ wrap }: UseCollectionProps) {\n const [items, setItems] = useState<Item[]>([]);\n const itemsRef = useRef<Item[]>([]);\n const itemMap = useRef<Map<string, Item>>(new Map());\n\n const registerItem = useCallback((item: Item) => {\n setItems((old) => {\n const newItems = old.slice();\n const index = newItems.findIndex(({ id }) => id === item.id);\n if (index !== -1) {\n const newItem = { ...newItems[index], ...item };\n newItems[index] = newItem;\n itemMap.current.set(item.id, newItem);\n } else {\n newItems.push(item);\n itemMap.current.set(item.id, item);\n }\n const value = sortBasedOnDOMPosition(newItems);\n itemsRef.current = value;\n return value;\n });\n\n return () => {\n setItems((old) => {\n itemMap.current.delete(item.id);\n return old.filter(({ id }) => id !== item.id);\n });\n return itemsRef;\n };\n }, []);\n\n return {\n registerItem,\n item: (id?: string | null): Item | null => {\n if (!id) return null;\n let item = itemMap.current.get(id);\n if (!item) {\n item = items.find((item) => item.id === id);\n if (item) {\n itemMap.current.set(item.id, item);\n }\n }\n return item ?? null;\n },\n getNext: (current: string): Item | null => {\n const index = items.findIndex(({ id }) => id === current);\n\n const newIndex = wrap\n ? (index + 1) % items.length\n : Math.min(index + 1, items.length - 1);\n\n return items[newIndex] ?? null;\n },\n getPrevious: (current: string): Item | null => {\n const index = items.findIndex(({ id }) => id === current);\n\n const newIndex = wrap\n ? (index - 1 + items.length) % items.length\n : Math.max(index - 1, 0);\n\n return items[newIndex] ?? null;\n },\n getFirst: (): Item | null => {\n return items[0] ?? null;\n },\n getLast: (): Item | null => {\n return items[items.length - 1] ?? null;\n },\n items,\n };\n}\n"],"names":["item"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { useValueEffect, useEventCallback, useIsomorphicLayoutEffect, ownerWindow } from '@salt-ds/core';
2
2
  import { useWindow } from '@salt-ds/window';
3
- import { useEffect, useMemo, Children } from 'react';
3
+ import { useRef, useEffect, useMemo, Children } from 'react';
4
4
 
5
5
  function getTabWidth(element) {
6
6
  const { width } = element.getBoundingClientRect();
@@ -18,6 +18,7 @@ function useOverflow({
18
18
  isMeasuring: false
19
19
  });
20
20
  const targetWindow = useWindow();
21
+ const realSelectedIndex = useRef(-1);
21
22
  const updateOverflow = useEventCallback(() => {
22
23
  const computeVisible = (visibleCount2) => {
23
24
  var _a;
@@ -69,7 +70,7 @@ function useOverflow({
69
70
  newVisibleCount--;
70
71
  }
71
72
  }
72
- return Math.max(1, newVisibleCount);
73
+ return Math.max(0, newVisibleCount);
73
74
  }
74
75
  return visibleCount2;
75
76
  };
@@ -95,6 +96,15 @@ function useOverflow({
95
96
  useIsomorphicLayoutEffect(() => {
96
97
  updateOverflow();
97
98
  }, [selected]);
99
+ useEffect(() => {
100
+ const handleWindowResize = () => {
101
+ updateOverflow();
102
+ };
103
+ targetWindow == null ? void 0 : targetWindow.addEventListener("resize", handleWindowResize);
104
+ return () => {
105
+ targetWindow == null ? void 0 : targetWindow.removeEventListener("resize", handleWindowResize);
106
+ };
107
+ }, [updateOverflow, targetWindow]);
98
108
  useEffect(() => {
99
109
  const element = container == null ? void 0 : container.current;
100
110
  if (!element) return;
@@ -115,9 +125,31 @@ function useOverflow({
115
125
  }
116
126
  };
117
127
  }, [container, updateOverflow]);
128
+ useEffect(() => {
129
+ const element = container == null ? void 0 : container.current;
130
+ if (!element || isMeasuring) return;
131
+ const win = ownerWindow(element);
132
+ const mutationObserver = new win.MutationObserver(() => {
133
+ requestAnimationFrame(() => {
134
+ updateOverflow();
135
+ });
136
+ });
137
+ mutationObserver.observe(element, {
138
+ childList: true
139
+ });
140
+ return () => {
141
+ mutationObserver.disconnect();
142
+ };
143
+ }, [container, updateOverflow, isMeasuring]);
118
144
  const childArray = useMemo(() => Children.toArray(children), [children]);
119
- const visible = childArray.slice(0, visibleCount || 1);
120
- const hidden = childArray.slice(visibleCount || 1);
145
+ const visible = useMemo(
146
+ () => childArray.slice(0, visibleCount),
147
+ [visibleCount, childArray]
148
+ );
149
+ const hidden = useMemo(
150
+ () => childArray.slice(visibleCount),
151
+ [childArray, visibleCount]
152
+ );
121
153
  const hiddenSelectedIndex = hidden.findIndex(
122
154
  // @ts-ignore
123
155
  (child) => {
@@ -125,14 +157,25 @@ function useOverflow({
125
157
  return ((_a = child == null ? void 0 : child.props) == null ? void 0 : _a.value) === selected;
126
158
  }
127
159
  );
160
+ useIsomorphicLayoutEffect(() => {
161
+ if (visibleCount === childArray.length) {
162
+ realSelectedIndex.current = childArray.findIndex(
163
+ // @ts-ignore
164
+ (child) => {
165
+ var _a;
166
+ return ((_a = child == null ? void 0 : child.props) == null ? void 0 : _a.value) === selected;
167
+ }
168
+ );
169
+ }
170
+ }, [visibleCount, childArray, selected]);
128
171
  if (selected && hiddenSelectedIndex !== -1) {
129
172
  const removed = hidden.splice(hiddenSelectedIndex, 1);
130
173
  visible.push(removed[0]);
131
174
  }
132
175
  if (isMeasuring) {
133
- return [childArray, [], isMeasuring];
176
+ return [childArray, [], isMeasuring, realSelectedIndex];
134
177
  }
135
- return [visible, hidden, isMeasuring];
178
+ return [visible, hidden, isMeasuring, realSelectedIndex];
136
179
  }
137
180
 
138
181
  export { useOverflow };
@@ -1 +1 @@
1
- {"version":3,"file":"useOverflow.js","sources":["../src/tabs-next/hooks/useOverflow.ts"],"sourcesContent":["import {\n ownerWindow,\n useEventCallback,\n useIsomorphicLayoutEffect,\n useValueEffect,\n} from \"@salt-ds/core\";\nimport { useWindow } from \"@salt-ds/window\";\nimport {\n Children,\n type ReactNode,\n type RefObject,\n useEffect,\n useMemo,\n} from \"react\";\nimport type { Item } from \"./useCollection\";\n\ninterface UseOverflowProps {\n container: RefObject<HTMLElement>;\n selected?: string;\n children: ReactNode;\n tabs: Item[];\n overflowButton: RefObject<HTMLButtonElement>;\n}\n\nfunction getTabWidth(element: HTMLElement) {\n const { width } = element.getBoundingClientRect();\n return Math.ceil(width);\n}\n\nexport function useOverflow({\n tabs,\n container,\n overflowButton,\n children,\n selected,\n}: UseOverflowProps) {\n const [{ visibleCount, isMeasuring }, setVisibleItems] = useValueEffect({\n visibleCount: tabs.length,\n isMeasuring: false,\n });\n const targetWindow = useWindow();\n\n const updateOverflow = useEventCallback(() => {\n const computeVisible = (visibleCount: number) => {\n if (container.current && targetWindow) {\n const items = Array.from(\n container.current.querySelectorAll<HTMLElement>(\n \"[data-overflowitem]\",\n ),\n );\n const selectedTab = container.current.querySelector<HTMLElement>(\n \"[role=tab][aria-selected=true]\",\n )?.parentElement;\n\n let maxWidth = container.current.clientWidth ?? 0;\n\n const containerStyles = targetWindow.getComputedStyle(\n container.current,\n );\n const gap = Number.parseInt(containerStyles.gap || \"0\");\n\n let currentWidth = 0;\n let newVisibleCount = 0;\n\n const visible = [];\n\n while (newVisibleCount < items.length) {\n const element = items[newVisibleCount];\n if (element) {\n if (currentWidth + getTabWidth(element) + gap > maxWidth) {\n break;\n }\n currentWidth += getTabWidth(element) + gap;\n visible.push(element);\n }\n newVisibleCount++;\n }\n\n if (newVisibleCount >= items.length) {\n return newVisibleCount;\n }\n\n const overflowButtonWidth = overflowButton.current\n ? overflowButton.current.offsetWidth + gap\n : 0;\n maxWidth -= overflowButtonWidth;\n\n while (currentWidth > maxWidth) {\n const removed = visible.pop();\n if (!removed) break;\n currentWidth -= getTabWidth(removed) + gap;\n newVisibleCount--;\n }\n\n if (selectedTab && !visible.includes(selectedTab)) {\n const selectedTabWidth = getTabWidth(selectedTab) + gap;\n while (currentWidth + selectedTabWidth > maxWidth) {\n const removed = visible.pop();\n if (!removed) break;\n currentWidth -= getTabWidth(selectedTab) + gap;\n newVisibleCount--;\n }\n }\n\n return Math.max(1, newVisibleCount);\n }\n return visibleCount;\n };\n\n setVisibleItems(function* () {\n // Show all\n yield {\n visibleCount: tabs.length,\n isMeasuring: true,\n };\n\n // Measure the visible count\n const newVisibleCount = computeVisible(tabs.length);\n const isMeasuring = newVisibleCount < tabs.length && newVisibleCount > 0;\n yield {\n visibleCount: newVisibleCount,\n isMeasuring,\n };\n\n // ensure the visible count is correct\n if (isMeasuring) {\n yield {\n visibleCount: computeVisible(newVisibleCount),\n isMeasuring: false,\n };\n }\n });\n });\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: we want to update when selected changes.\n useIsomorphicLayoutEffect(() => {\n updateOverflow();\n }, [selected]);\n\n useEffect(() => {\n const element = container?.current;\n if (!element) return;\n\n const win = ownerWindow(element);\n\n const resizeObserver = new win.ResizeObserver((entries) => {\n requestAnimationFrame(() => {\n if (entries.length === 0) return;\n\n updateOverflow();\n });\n });\n resizeObserver.observe(element);\n if (element.parentElement) {\n resizeObserver.observe(element.parentElement);\n }\n\n return () => {\n if (element) {\n resizeObserver.unobserve(element);\n }\n };\n }, [container, updateOverflow]);\n\n const childArray = useMemo(() => Children.toArray(children), [children]);\n const visible = childArray.slice(0, visibleCount || 1);\n const hidden = childArray.slice(visibleCount || 1);\n\n const hiddenSelectedIndex = hidden.findIndex(\n // @ts-ignore\n (child) => child?.props?.value === selected,\n );\n\n if (selected && hiddenSelectedIndex !== -1) {\n const removed = hidden.splice(hiddenSelectedIndex, 1);\n visible.push(removed[0]);\n }\n\n if (isMeasuring) {\n return [childArray, [], isMeasuring] as const;\n }\n\n return [visible, hidden, isMeasuring] as const;\n}\n"],"names":["visibleCount","visible","isMeasuring"],"mappings":"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"}
1
+ {"version":3,"file":"useOverflow.js","sources":["../src/tabs-next/hooks/useOverflow.ts"],"sourcesContent":["import {\n ownerWindow,\n useEventCallback,\n useIsomorphicLayoutEffect,\n useValueEffect,\n} from \"@salt-ds/core\";\nimport { useWindow } from \"@salt-ds/window\";\nimport {\n Children,\n type ReactNode,\n type RefObject,\n useEffect,\n useMemo,\n useRef,\n} from \"react\";\nimport type { Item } from \"./useCollection\";\n\ninterface UseOverflowProps {\n container: RefObject<HTMLElement>;\n selected?: string;\n children: ReactNode;\n tabs: Item[];\n overflowButton: RefObject<HTMLButtonElement>;\n}\n\nfunction getTabWidth(element: HTMLElement) {\n const { width } = element.getBoundingClientRect();\n return Math.ceil(width);\n}\n\nexport function useOverflow({\n tabs,\n container,\n overflowButton,\n children,\n selected,\n}: UseOverflowProps) {\n /**\n * `visibleCount` doesn't include newly selected tab from overflow menu, which is removed in `computeVisible`\n */\n const [{ visibleCount, isMeasuring }, setVisibleItems] = useValueEffect({\n visibleCount: tabs.length,\n isMeasuring: false,\n });\n const targetWindow = useWindow();\n const realSelectedIndex = useRef<number>(-1);\n\n const updateOverflow = useEventCallback(() => {\n const computeVisible = (visibleCount: number) => {\n if (container.current && targetWindow) {\n const items = Array.from(\n container.current.querySelectorAll<HTMLElement>(\n \"[data-overflowitem]\",\n ),\n );\n const selectedTab = container.current.querySelector<HTMLElement>(\n \"[role=tab][aria-selected=true]\",\n )?.parentElement;\n\n let maxWidth = container.current.clientWidth ?? 0;\n\n const containerStyles = targetWindow.getComputedStyle(\n container.current,\n );\n const gap = Number.parseInt(containerStyles.gap || \"0\");\n\n let currentWidth = 0;\n let newVisibleCount = 0;\n\n const visible = [];\n\n while (newVisibleCount < items.length) {\n const element = items[newVisibleCount];\n if (element) {\n if (currentWidth + getTabWidth(element) + gap > maxWidth) {\n break;\n }\n currentWidth += getTabWidth(element) + gap;\n visible.push(element);\n }\n newVisibleCount++;\n }\n\n if (newVisibleCount >= items.length) {\n return newVisibleCount;\n }\n\n const overflowButtonWidth = overflowButton.current\n ? overflowButton.current.offsetWidth + gap\n : 0;\n maxWidth -= overflowButtonWidth;\n\n while (currentWidth > maxWidth) {\n const removed = visible.pop();\n if (!removed) break;\n currentWidth -= getTabWidth(removed) + gap;\n newVisibleCount--;\n }\n\n if (selectedTab && !visible.includes(selectedTab)) {\n const selectedTabWidth = getTabWidth(selectedTab) + gap;\n while (currentWidth + selectedTabWidth > maxWidth) {\n const removed = visible.pop();\n if (!removed) break;\n currentWidth -= getTabWidth(selectedTab) + gap;\n newVisibleCount--;\n }\n }\n\n // minimal count should be 0, if there is no space for any tab apart from selected tab from the overflow menu\n return Math.max(0, newVisibleCount);\n }\n return visibleCount;\n };\n\n setVisibleItems(function* () {\n // Show all\n yield {\n visibleCount: tabs.length,\n isMeasuring: true,\n };\n\n // Measure the visible count\n const newVisibleCount = computeVisible(tabs.length);\n const isMeasuring = newVisibleCount < tabs.length && newVisibleCount > 0;\n yield {\n visibleCount: newVisibleCount,\n isMeasuring,\n };\n\n // ensure the visible count is correct\n if (isMeasuring) {\n yield {\n visibleCount: computeVisible(newVisibleCount),\n isMeasuring: false,\n };\n }\n });\n });\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: we want to update when selected changes.\n useIsomorphicLayoutEffect(() => {\n updateOverflow();\n }, [selected]);\n\n useEffect(() => {\n const handleWindowResize = () => {\n updateOverflow();\n };\n\n targetWindow?.addEventListener(\"resize\", handleWindowResize);\n\n return () => {\n targetWindow?.removeEventListener(\"resize\", handleWindowResize);\n };\n }, [updateOverflow, targetWindow]);\n\n useEffect(() => {\n const element = container?.current;\n if (!element) return;\n\n const win = ownerWindow(element);\n\n const resizeObserver = new win.ResizeObserver((entries) => {\n requestAnimationFrame(() => {\n if (entries.length === 0) return;\n\n updateOverflow();\n });\n });\n resizeObserver.observe(element);\n if (element.parentElement) {\n resizeObserver.observe(element.parentElement);\n }\n\n return () => {\n if (element) {\n resizeObserver.unobserve(element);\n }\n };\n }, [container, updateOverflow]);\n\n useEffect(() => {\n const element = container?.current;\n if (!element || isMeasuring) return;\n\n const win = ownerWindow(element);\n\n const mutationObserver = new win.MutationObserver(() => {\n requestAnimationFrame(() => {\n updateOverflow();\n });\n });\n\n mutationObserver.observe(element, {\n childList: true,\n });\n\n return () => {\n mutationObserver.disconnect();\n };\n }, [container, updateOverflow, isMeasuring]);\n\n const childArray = useMemo(() => Children.toArray(children), [children]);\n const visible = useMemo(\n () => childArray.slice(0, visibleCount),\n [visibleCount, childArray],\n );\n const hidden = useMemo(\n () => childArray.slice(visibleCount),\n [childArray, visibleCount],\n );\n\n const hiddenSelectedIndex = hidden.findIndex(\n // @ts-ignore\n (child) => child?.props?.value === selected,\n );\n\n useIsomorphicLayoutEffect(() => {\n if (visibleCount === childArray.length) {\n realSelectedIndex.current = childArray.findIndex(\n // @ts-ignore\n (child) => child?.props?.value === selected,\n );\n }\n }, [visibleCount, childArray, selected]);\n\n if (selected && hiddenSelectedIndex !== -1) {\n const removed = hidden.splice(hiddenSelectedIndex, 1);\n visible.push(removed[0]);\n }\n\n if (isMeasuring) {\n return [childArray, [], isMeasuring, realSelectedIndex] as const;\n }\n\n return [visible, hidden, isMeasuring, realSelectedIndex] as const;\n}\n"],"names":["visibleCount","visible","isMeasuring"],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ import { useIsomorphicLayoutEffect, ownerWindow } from '@salt-ds/core';
2
+ import { useRef, useEffect } from 'react';
3
+
4
+ function useRestoreActiveTab({
5
+ container,
6
+ tabs,
7
+ realSelectedIndex,
8
+ removedActiveTabRef
9
+ }) {
10
+ const tabsRef = useRef(tabs);
11
+ const previousTabsRef = useRef(tabs);
12
+ useIsomorphicLayoutEffect(() => {
13
+ tabsRef.current = tabs;
14
+ return () => {
15
+ previousTabsRef.current = tabs;
16
+ };
17
+ }, [tabs]);
18
+ useEffect(() => {
19
+ if (!container.current) return;
20
+ const win = ownerWindow(container.current);
21
+ const mutationObserver = new win.MutationObserver((mutations) => {
22
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
23
+ for (const mutation of mutations) {
24
+ const removedItem = mutation.removedNodes[0] instanceof HTMLElement ? mutation.removedNodes[0] : null;
25
+ const removedItemWasTab = removedActiveTabRef.current && ((_a = removedItem == null ? void 0 : removedItem.dataset) == null ? void 0 : _a.overflowitem);
26
+ const activeTabWasRemoved = removedItemWasTab && !tabsRef.current.find(
27
+ ({ value }) => value === removedActiveTabRef.current
28
+ );
29
+ if (activeTabWasRemoved) {
30
+ const removedTab = removedItem == null ? void 0 : removedItem.querySelector('[role="tab"]');
31
+ let nextTab = null;
32
+ if ((removedTab == null ? void 0 : removedTab.ariaSelected) === "true" && realSelectedIndex.current != null && realSelectedIndex.current >= 0) {
33
+ nextTab = (_b = tabsRef.current[Math.min(realSelectedIndex.current, tabsRef.current.length - 1)]) == null ? void 0 : _b.element;
34
+ }
35
+ if (!nextTab) {
36
+ const previousTab = mutation.previousSibling instanceof HTMLElement ? mutation.previousSibling.querySelector(
37
+ '[role="tab"]'
38
+ ) : null;
39
+ if (!previousTab) {
40
+ nextTab = mutation.nextSibling instanceof HTMLElement ? (_c = mutation.nextSibling) == null ? void 0 : _c.querySelector(
41
+ '[role="tab"]'
42
+ ) : null;
43
+ } else {
44
+ const nextTabIndex = previousTab ? tabsRef.current.findIndex(
45
+ ({ element }) => element === previousTab
46
+ ) + 1 : -1;
47
+ nextTab = (_d = tabsRef.current[Math.min(nextTabIndex, tabsRef.current.length - 1)]) == null ? void 0 : _d.element;
48
+ }
49
+ }
50
+ if (!((_e = container.current) == null ? void 0 : _e.querySelector(
51
+ '[role="tab"][aria-selected="true"]'
52
+ ))) {
53
+ nextTab == null ? void 0 : nextTab.click();
54
+ }
55
+ if (!((_f = container.current) == null ? void 0 : _f.contains(win.document.activeElement))) {
56
+ if (nextTab == null ? void 0 : nextTab.isConnected) {
57
+ nextTab == null ? void 0 : nextTab.focus({ preventScroll: true });
58
+ } else {
59
+ (_h = (_g = container.current) == null ? void 0 : _g.querySelector(
60
+ '[role="tab"][aria-selected="true"]'
61
+ )) == null ? void 0 : _h.focus({ preventScroll: true });
62
+ }
63
+ }
64
+ removedActiveTabRef.current = void 0;
65
+ }
66
+ if (removedActiveTabRef.current) {
67
+ if (removedItemWasTab) {
68
+ const tabElement = (_i = tabsRef.current.find(
69
+ ({ value }) => value === removedActiveTabRef.current
70
+ )) == null ? void 0 : _i.element;
71
+ if (win.document.activeElement === win.document.body) {
72
+ tabElement == null ? void 0 : tabElement.focus();
73
+ }
74
+ } else if (removedItem == null ? void 0 : removedItem.dataset.overflow) {
75
+ (_k = (_j = tabsRef.current[tabsRef.current.length - 1]) == null ? void 0 : _j.element) == null ? void 0 : _k.focus();
76
+ }
77
+ }
78
+ }
79
+ });
80
+ mutationObserver.observe(container.current, {
81
+ childList: true,
82
+ subtree: true
83
+ });
84
+ return () => {
85
+ mutationObserver.disconnect();
86
+ };
87
+ }, [container, realSelectedIndex, removedActiveTabRef]);
88
+ }
89
+
90
+ export { useRestoreActiveTab };
91
+ //# sourceMappingURL=useRestoreActiveTab.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useRestoreActiveTab.js","sources":["../src/tabs-next/hooks/useRestoreActiveTab.ts"],"sourcesContent":["import { ownerWindow, useIsomorphicLayoutEffect } from \"@salt-ds/core\";\nimport {\n type MutableRefObject,\n type RefObject,\n useEffect,\n useRef,\n} from \"react\";\nimport type { Item } from \"./useCollection\";\n\ninterface UseHandleRemovalProps {\n container: RefObject<HTMLElement>;\n tabs: Item[];\n realSelectedIndex: RefObject<number>;\n removedActiveTabRef: MutableRefObject<string | undefined>;\n}\n\nexport function useRestoreActiveTab({\n container,\n tabs,\n realSelectedIndex,\n removedActiveTabRef,\n}: UseHandleRemovalProps) {\n const tabsRef = useRef(tabs);\n const previousTabsRef = useRef(tabs);\n\n useIsomorphicLayoutEffect(() => {\n tabsRef.current = tabs;\n\n return () => {\n previousTabsRef.current = tabs;\n };\n }, [tabs]);\n\n useEffect(() => {\n if (!container.current) return;\n\n const win = ownerWindow(container.current);\n\n const mutationObserver = new win.MutationObserver((mutations) => {\n for (const mutation of mutations) {\n const removedItem =\n mutation.removedNodes[0] instanceof HTMLElement\n ? mutation.removedNodes[0]\n : null;\n\n const removedItemWasTab =\n removedActiveTabRef.current && removedItem?.dataset?.overflowitem;\n\n const activeTabWasRemoved =\n removedItemWasTab &&\n !tabsRef.current.find(\n ({ value }) => value === removedActiveTabRef.current,\n );\n\n if (activeTabWasRemoved) {\n const removedTab =\n removedItem?.querySelector<HTMLElement>('[role=\"tab\"]');\n\n let nextTab: HTMLElement | null | undefined = null;\n\n if (\n removedTab?.ariaSelected === \"true\" &&\n realSelectedIndex.current != null &&\n realSelectedIndex.current >= 0\n ) {\n nextTab =\n tabsRef.current[\n Math.min(realSelectedIndex.current, tabsRef.current.length - 1)\n ]?.element;\n }\n\n if (!nextTab) {\n const previousTab =\n mutation.previousSibling instanceof HTMLElement\n ? mutation.previousSibling.querySelector<HTMLElement>(\n '[role=\"tab\"]',\n )\n : null;\n\n if (!previousTab) {\n nextTab =\n mutation.nextSibling instanceof HTMLElement\n ? mutation.nextSibling?.querySelector<HTMLElement>(\n '[role=\"tab\"]',\n )\n : null;\n } else {\n const nextTabIndex = previousTab\n ? tabsRef.current.findIndex(\n ({ element }) => element === previousTab,\n ) + 1\n : -1;\n\n nextTab =\n tabsRef.current[\n Math.min(nextTabIndex, tabsRef.current.length - 1)\n ]?.element;\n }\n }\n\n if (\n !container.current?.querySelector<HTMLElement>(\n '[role=\"tab\"][aria-selected=\"true\"]',\n )\n ) {\n nextTab?.click();\n }\n\n if (!container.current?.contains(win.document.activeElement)) {\n if (nextTab?.isConnected) {\n nextTab?.focus({ preventScroll: true });\n } else {\n container.current\n ?.querySelector<HTMLElement>(\n '[role=\"tab\"][aria-selected=\"true\"]',\n )\n ?.focus({ preventScroll: true });\n }\n }\n\n removedActiveTabRef.current = undefined;\n }\n\n // Focus the tab if it was moved from the overflow menu into the visible tabs\n if (removedActiveTabRef.current) {\n if (removedItemWasTab) {\n const tabElement = tabsRef.current.find(\n ({ value }) => value === removedActiveTabRef.current,\n )?.element;\n\n if (win.document.activeElement === win.document.body) {\n tabElement?.focus();\n }\n } else if (removedItem?.dataset.overflow) {\n tabsRef.current[tabsRef.current.length - 1]?.element?.focus();\n }\n }\n }\n });\n\n mutationObserver.observe(container.current, {\n childList: true,\n subtree: true,\n });\n\n return () => {\n mutationObserver.disconnect();\n };\n }, [container, realSelectedIndex, removedActiveTabRef]);\n}\n"],"names":[],"mappings":"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"}
@@ -37,6 +37,7 @@ export * from "./query-input";
37
37
  export * from "./responsive";
38
38
  export * from "./search-input";
39
39
  export * from "./slider";
40
+ export * from "./splitter";
40
41
  export * from "./static-list";
41
42
  export * from "./stepped-tracker";
42
43
  export * from "./stepper-input";
@@ -0,0 +1,21 @@
1
+ import { type PanelResizeHandleProps } from "react-resizable-panels";
2
+ export declare type SplitHandleVariant = "primary" | "secondary" | "tertiary" | "transparent";
3
+ export declare type SplitHandleBorder = "top" | "bottom" | "right" | "left" | "top-bottom" | "left-right" | "none";
4
+ export interface SplitHandleProps extends PanelResizeHandleProps {
5
+ /**
6
+ * Styling variant
7
+ * @default "primary"
8
+ */
9
+ variant?: SplitHandleVariant;
10
+ /**
11
+ * Change which sides get a border displayed
12
+ *
13
+ * Default is based on the orientation and appearance
14
+ * set on the parent Stepper components, ex.
15
+ * bordered + vertical = left-right
16
+ * bordered + horizontal = top-bottom
17
+ * transparent = none
18
+ */
19
+ border?: SplitHandleBorder;
20
+ }
21
+ export declare function SplitHandle({ variant: variantProp, border: borderProp, hitAreaMargins, className, ...props }: SplitHandleProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,10 @@
1
+ import { type ImperativePanelHandle, type PanelProps } from "react-resizable-panels";
2
+ export declare type SplitPanelVariant = "primary" | "secondary" | "tertiary";
3
+ export interface SplitPanelProps extends PanelProps {
4
+ /**
5
+ * Styling variant
6
+ * @default "primary"
7
+ */
8
+ variant?: SplitPanelVariant;
9
+ }
10
+ export declare const SplitPanel: import("react").ForwardRefExoticComponent<SplitPanelProps & import("react").RefAttributes<ImperativePanelHandle>>;
@@ -0,0 +1,22 @@
1
+ import { type ReactNode } from "react";
2
+ import { type PanelGroupProps } from "react-resizable-panels";
3
+ export declare type SplitterAppearance = "bordered" | "transparent";
4
+ export declare type SplitterOrientation = "horizontal" | "vertical";
5
+ export declare const OrientationContext: import("react").Context<SplitterOrientation>;
6
+ export declare const AppearanceContext: import("react").Context<SplitterAppearance>;
7
+ export interface SplitterProps extends Omit<PanelGroupProps, "direction"> {
8
+ /**
9
+ * The orientation of the splitter.
10
+ * Replaces `PanelGroupProps["direction"]`
11
+ */
12
+ orientation: SplitterOrientation;
13
+ /**
14
+ * The appearance of the splitter.
15
+ * If set to "transparent", the splitter handle will
16
+ * be transparent, hence the background will be visible.
17
+ * @default "bordered"
18
+ */
19
+ appearance?: SplitterAppearance;
20
+ children: ReactNode;
21
+ }
22
+ export declare function Splitter({ orientation, appearance: appearanceProp, ...props }: SplitterProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,4 @@
1
+ export { Splitter, type SplitterProps } from "./Splitter";
2
+ export { SplitPanel, type SplitPanelProps } from "./SplitPanel";
3
+ export { SplitHandle, type SplitHandleProps } from "./SplitHandle";
4
+ export type { ImperativePanelHandle } from "react-resizable-panels";
@@ -0,0 +1,4 @@
1
+ import type { SplitHandleBorder } from "./SplitHandle";
2
+ import type { SplitterAppearance, SplitterOrientation } from "./Splitter";
3
+ export declare function computeAccent(appearance: SplitterAppearance, orientation: SplitterOrientation): SplitHandleBorder;
4
+ export declare function computeVariant(appearance: SplitterAppearance): "primary" | "transparent";
@@ -11,11 +11,9 @@ export interface StepProps extends Omit<ComponentPropsWithoutRef<"li">, "onToggl
11
11
  substeps?: StepRecord[];
12
12
  children?: ReactNode;
13
13
  }
14
- export declare type StepRecord = (Omit<StepProps, "children"> & {
14
+ export declare type StepRecord = Omit<StepProps, "children"> & {
15
15
  id: string;
16
- }) | (Omit<StepProps, "children"> & {
17
- key: string;
18
- });
16
+ };
19
17
  export declare type StepStatus = "warning" | "error";
20
18
  export declare type StepStage = "pending" | "locked" | "completed" | "inprogress" | "active";
21
19
  export declare type StepDepth = number;
@@ -2,10 +2,10 @@ import type { StepRecord } from ".";
2
2
  export interface StepReducerState {
3
3
  steps: StepRecord[];
4
4
  flatSteps: StepRecord[];
5
+ activeStepIndex: number;
5
6
  activeStep: StepRecord | null;
6
7
  previousStep: StepRecord | null;
7
8
  nextStep: StepRecord | null;
8
- activeStepIndex: number;
9
9
  started: boolean;
10
10
  ended: boolean;
11
11
  }
@@ -14,11 +14,13 @@ export declare type StepReducerAction = {
14
14
  } | {
15
15
  type: "previous";
16
16
  } | {
17
- type: "error";
17
+ type: "reset";
18
+ } | {
19
+ type: "status/error";
18
20
  } | {
19
- type: "warning";
21
+ type: "status/warning";
20
22
  } | {
21
- type: "clear";
23
+ type: "status/clear";
22
24
  };
23
25
  export interface StepReducerOptions {
24
26
  activeStepId?: string;
@@ -1,7 +1,10 @@
1
- import type { StepRecord, StepStage } from "./Step.types";
1
+ import type { StepRecord, StepStage, StepStatus } from "./Step.types";
2
2
  import type { StepReducerOptions, StepReducerState } from "./stepReducer.types";
3
- export declare function assignSteps(steps: StepRecord[], stage?: StepStage): StepRecord[];
4
- export declare function resetSteps(steps: StepRecord[]): StepRecord[];
3
+ export declare function assignStepsStage(steps: StepRecord[], stage?: StepStage): StepRecord[];
4
+ export declare function assignStepStatus(steps: StepRecord[], stepId: string, status: StepStatus | undefined): StepRecord[];
5
+ export declare function resetSteps(steps: StepRecord[], options?: {
6
+ resetStatus: boolean;
7
+ }): StepRecord[];
5
8
  export declare function autoStageSteps(steps: StepRecord[], options?: StepReducerOptions): StepRecord[];
6
9
  export declare function flattenSteps(steps: StepRecord[]): StepRecord[];
7
10
  export declare function initStepReducerState(initialSteps: StepRecord[], options?: StepReducerOptions): StepReducerState;