@salt-ds/lab 1.0.0-alpha.61 → 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 (92) hide show
  1. package/CHANGELOG.md +75 -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/tabs-next/TabListNext.css.js +1 -1
  28. package/dist-cjs/tabs-next/TabListNext.js +10 -16
  29. package/dist-cjs/tabs-next/TabListNext.js.map +1 -1
  30. package/dist-cjs/tabs-next/TabOverflowList.js +1 -1
  31. package/dist-cjs/tabs-next/TabOverflowList.js.map +1 -1
  32. package/dist-cjs/tabs-next/TabsNext.js +4 -51
  33. package/dist-cjs/tabs-next/TabsNext.js.map +1 -1
  34. package/dist-cjs/tabs-next/TabsNextContext.js +1 -1
  35. package/dist-cjs/tabs-next/TabsNextContext.js.map +1 -1
  36. package/dist-cjs/tabs-next/hooks/useCollection.js.map +1 -1
  37. package/dist-cjs/tabs-next/hooks/useOverflow.js +48 -5
  38. package/dist-cjs/tabs-next/hooks/useOverflow.js.map +1 -1
  39. package/dist-cjs/tabs-next/hooks/useRestoreActiveTab.js +93 -0
  40. package/dist-cjs/tabs-next/hooks/useRestoreActiveTab.js.map +1 -0
  41. package/dist-es/date-picker/DatePickerRangeInput.js +1 -0
  42. package/dist-es/date-picker/DatePickerRangeInput.js.map +1 -1
  43. package/dist-es/date-picker/DatePickerSingleInput.js +1 -0
  44. package/dist-es/date-picker/DatePickerSingleInput.js.map +1 -1
  45. package/dist-es/index.js +3 -0
  46. package/dist-es/index.js.map +1 -1
  47. package/dist-es/splitter/SplitHandle.css.js +4 -0
  48. package/dist-es/splitter/SplitHandle.css.js.map +1 -0
  49. package/dist-es/splitter/SplitHandle.js +58 -0
  50. package/dist-es/splitter/SplitHandle.js.map +1 -0
  51. package/dist-es/splitter/SplitPanel.css.js +4 -0
  52. package/dist-es/splitter/SplitPanel.css.js.map +1 -0
  53. package/dist-es/splitter/SplitPanel.js +35 -0
  54. package/dist-es/splitter/SplitPanel.js.map +1 -0
  55. package/dist-es/splitter/Splitter.js +27 -0
  56. package/dist-es/splitter/Splitter.js.map +1 -0
  57. package/dist-es/splitter/utils.js +15 -0
  58. package/dist-es/splitter/utils.js.map +1 -0
  59. package/dist-es/stepped-tracker/stepReducer.js +128 -82
  60. package/dist-es/stepped-tracker/stepReducer.js.map +1 -1
  61. package/dist-es/stepped-tracker/useStepReducer.js +7 -5
  62. package/dist-es/stepped-tracker/useStepReducer.js.map +1 -1
  63. package/dist-es/stepped-tracker/utils.js +43 -9
  64. package/dist-es/stepped-tracker/utils.js.map +1 -1
  65. package/dist-es/tabs-next/TabListNext.css.js +1 -1
  66. package/dist-es/tabs-next/TabListNext.js +11 -17
  67. package/dist-es/tabs-next/TabListNext.js.map +1 -1
  68. package/dist-es/tabs-next/TabOverflowList.js +1 -1
  69. package/dist-es/tabs-next/TabOverflowList.js.map +1 -1
  70. package/dist-es/tabs-next/TabsNext.js +5 -52
  71. package/dist-es/tabs-next/TabsNext.js.map +1 -1
  72. package/dist-es/tabs-next/TabsNextContext.js +1 -1
  73. package/dist-es/tabs-next/TabsNextContext.js.map +1 -1
  74. package/dist-es/tabs-next/hooks/useCollection.js.map +1 -1
  75. package/dist-es/tabs-next/hooks/useOverflow.js +49 -6
  76. package/dist-es/tabs-next/hooks/useOverflow.js.map +1 -1
  77. package/dist-es/tabs-next/hooks/useRestoreActiveTab.js +91 -0
  78. package/dist-es/tabs-next/hooks/useRestoreActiveTab.js.map +1 -0
  79. package/dist-types/index.d.ts +1 -0
  80. package/dist-types/splitter/SplitHandle.d.ts +21 -0
  81. package/dist-types/splitter/SplitPanel.d.ts +10 -0
  82. package/dist-types/splitter/Splitter.d.ts +22 -0
  83. package/dist-types/splitter/index.d.ts +4 -0
  84. package/dist-types/splitter/utils.d.ts +4 -0
  85. package/dist-types/stepped-tracker/Step.types.d.ts +2 -4
  86. package/dist-types/stepped-tracker/stepReducer.types.d.ts +6 -4
  87. package/dist-types/stepped-tracker/utils.d.ts +6 -3
  88. package/dist-types/tabs/drag-drop/drag-utils.d.ts +6 -6
  89. package/dist-types/tabs-next/TabsNextContext.d.ts +1 -1
  90. package/dist-types/tabs-next/hooks/useOverflow.d.ts +1 -1
  91. package/dist-types/tabs-next/hooks/useRestoreActiveTab.d.ts +10 -0
  92. package/package.json +4 -3
@@ -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;
@@ -20,24 +20,24 @@ export declare type targetType = {
20
20
  declare type Dimension = keyof Pick<DOMRect, "width" | "height">;
21
21
  export declare const measureElementSizeAndPosition: (element: HTMLElement, dimension?: Dimension, includeAutoMargin?: boolean) => number[];
22
22
  export declare const dimensions: (orientation: orientationType) => {
23
- CLIENT_SIZE: "scrollWidth" | "scrollHeight" | "clientHeight" | "clientWidth" | "scrollTop" | "scrollLeft";
23
+ CLIENT_SIZE: "scrollHeight" | "clientHeight" | "scrollWidth" | "clientWidth" | "scrollTop" | "scrollLeft";
24
24
  CONTRA: "x" | "y" | "height" | "width" | "left" | "right" | "top" | "bottom";
25
25
  CONTRA_POS: "clientX" | "clientY";
26
26
  DIMENSION: "height" | "width";
27
27
  END: "x" | "y" | "height" | "width" | "left" | "right" | "top" | "bottom";
28
28
  POS: "clientX" | "clientY";
29
- SCROLL_POS: "scrollWidth" | "scrollHeight" | "clientHeight" | "clientWidth" | "scrollTop" | "scrollLeft";
30
- SCROLL_SIZE: "scrollWidth" | "scrollHeight" | "clientHeight" | "clientWidth" | "scrollTop" | "scrollLeft";
29
+ SCROLL_POS: "scrollHeight" | "clientHeight" | "scrollWidth" | "clientWidth" | "scrollTop" | "scrollLeft";
30
+ SCROLL_SIZE: "scrollHeight" | "clientHeight" | "scrollWidth" | "clientWidth" | "scrollTop" | "scrollLeft";
31
31
  START: "x" | "y" | "height" | "width" | "left" | "right" | "top" | "bottom";
32
32
  } | {
33
- CLIENT_SIZE: "scrollWidth" | "scrollHeight" | "clientHeight" | "clientWidth" | "scrollTop" | "scrollLeft";
33
+ CLIENT_SIZE: "scrollHeight" | "clientHeight" | "scrollWidth" | "clientWidth" | "scrollTop" | "scrollLeft";
34
34
  CONTRA: "x" | "y" | "height" | "width" | "left" | "right" | "top" | "bottom";
35
35
  CONTRA_POS: "clientX" | "clientY";
36
36
  DIMENSION: "height" | "width";
37
37
  END: "x" | "y" | "height" | "width" | "left" | "right" | "top" | "bottom";
38
38
  POS: "clientX" | "clientY";
39
- SCROLL_POS: "scrollWidth" | "scrollHeight" | "clientHeight" | "clientWidth" | "scrollTop" | "scrollLeft";
40
- SCROLL_SIZE: "scrollWidth" | "scrollHeight" | "clientHeight" | "clientWidth" | "scrollTop" | "scrollLeft";
39
+ SCROLL_POS: "scrollHeight" | "clientHeight" | "scrollWidth" | "clientWidth" | "scrollTop" | "scrollLeft";
40
+ SCROLL_SIZE: "scrollHeight" | "clientHeight" | "scrollWidth" | "clientWidth" | "scrollTop" | "scrollLeft";
41
41
  START: "x" | "y" | "height" | "width" | "left" | "right" | "top" | "bottom";
42
42
  };
43
43
  export declare const getDraggedItem: (measuredItems: MeasuredDropTarget[]) => MeasuredDropTarget;
@@ -13,7 +13,7 @@ export interface TabsNextContextValue extends Omit<ReturnType<typeof useCollecti
13
13
  selected?: string;
14
14
  setSelected: (event: SyntheticEvent, value: string) => void;
15
15
  activeTab: MutableRefObject<Pick<Item, "id" | "value"> | undefined>;
16
- returnFocus: MutableRefObject<string | undefined>;
16
+ removedActiveTabRef: MutableRefObject<string | undefined>;
17
17
  menuOpen: boolean;
18
18
  setMenuOpen: Dispatch<SetStateAction<boolean>>;
19
19
  }
@@ -7,5 +7,5 @@ interface UseOverflowProps {
7
7
  tabs: Item[];
8
8
  overflowButton: RefObject<HTMLButtonElement>;
9
9
  }
10
- export declare function useOverflow({ tabs, container, overflowButton, children, selected, }: UseOverflowProps): readonly [(string | number | import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | import("react").ReactPortal)[], (string | number | import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | import("react").ReactPortal)[], false] | readonly [(string | number | import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | import("react").ReactPortal)[], readonly [], true];
10
+ export declare function useOverflow({ tabs, container, overflowButton, children, selected, }: UseOverflowProps): readonly [(string | number | import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | import("react").ReactPortal)[], (string | number | import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | import("react").ReactPortal)[], false, import("react").MutableRefObject<number>] | readonly [(string | number | import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | import("react").ReactPortal)[], readonly [], true, import("react").MutableRefObject<number>];
11
11
  export {};
@@ -0,0 +1,10 @@
1
+ import { type MutableRefObject, type RefObject } from "react";
2
+ import type { Item } from "./useCollection";
3
+ interface UseHandleRemovalProps {
4
+ container: RefObject<HTMLElement>;
5
+ tabs: Item[];
6
+ realSelectedIndex: RefObject<number>;
7
+ removedActiveTabRef: MutableRefObject<string | undefined>;
8
+ }
9
+ export declare function useRestoreActiveTab({ container, tabs, realSelectedIndex, removedActiveTabRef, }: UseHandleRemovalProps): void;
10
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salt-ds/lab",
3
- "version": "1.0.0-alpha.61",
3
+ "version": "1.0.0-alpha.62",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,8 +21,8 @@
21
21
  ],
22
22
  "dependencies": {
23
23
  "@floating-ui/react": "^0.26.28",
24
- "@salt-ds/core": "^1.41.0",
25
- "@salt-ds/date-adapters": "0.1.0-alpha.2",
24
+ "@salt-ds/core": "^1.42.0",
25
+ "@salt-ds/date-adapters": "0.1.0-alpha.3",
26
26
  "@salt-ds/icons": "^1.13.2",
27
27
  "@salt-ds/styles": "0.2.1",
28
28
  "@salt-ds/window": "0.1.1",
@@ -35,6 +35,7 @@
35
35
  "deepmerge": "^4.2.2",
36
36
  "no-scroll": "^2.1.1",
37
37
  "react-color": "^2.19.3",
38
+ "react-resizable-panels": "^2.1.7",
38
39
  "react-window": "^1.8.6",
39
40
  "rifm": "^0.12.0",
40
41
  "tabbable": "^6.0.0",