@salt-ds/lab 1.0.0-alpha.87 → 1.0.0-alpha.89

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/css/salt-lab.css +64 -45
  3. package/dist-cjs/calendar/internal/CalendarDay.css.js +1 -1
  4. package/dist-cjs/contact-details/ContactDetails.css.js +1 -1
  5. package/dist-cjs/list-deprecated/ListStateContext.js +1 -1
  6. package/dist-cjs/list-deprecated/ListStateContext.js.map +1 -1
  7. package/dist-cjs/tabs-next/TabBar.css.js +1 -1
  8. package/dist-cjs/tabs-next/TabBar.js +1 -1
  9. package/dist-cjs/tabs-next/TabBar.js.map +1 -1
  10. package/dist-cjs/tabs-next/TabListLayoutContext.js +13 -0
  11. package/dist-cjs/tabs-next/TabListLayoutContext.js.map +1 -0
  12. package/dist-cjs/tabs-next/TabListNext.css.js +1 -1
  13. package/dist-cjs/tabs-next/TabListNext.js +179 -33
  14. package/dist-cjs/tabs-next/TabListNext.js.map +1 -1
  15. package/dist-cjs/tabs-next/TabNext.js +111 -7
  16. package/dist-cjs/tabs-next/TabNext.js.map +1 -1
  17. package/dist-cjs/tabs-next/TabNextAction.js +25 -2
  18. package/dist-cjs/tabs-next/TabNextAction.js.map +1 -1
  19. package/dist-cjs/tabs-next/TabNextPanel.js +31 -16
  20. package/dist-cjs/tabs-next/TabNextPanel.js.map +1 -1
  21. package/dist-cjs/tabs-next/TabNextTrigger.js +110 -9
  22. package/dist-cjs/tabs-next/TabNextTrigger.js.map +1 -1
  23. package/dist-cjs/tabs-next/TabOverflowList.css.js +1 -1
  24. package/dist-cjs/tabs-next/TabOverflowList.js +168 -64
  25. package/dist-cjs/tabs-next/TabOverflowList.js.map +1 -1
  26. package/dist-cjs/tabs-next/TabSlot.js +30 -0
  27. package/dist-cjs/tabs-next/TabSlot.js.map +1 -0
  28. package/dist-cjs/tabs-next/TabSlotRegistryContext.js +16 -0
  29. package/dist-cjs/tabs-next/TabSlotRegistryContext.js.map +1 -0
  30. package/dist-cjs/tabs-next/TabsNext.css.js +6 -0
  31. package/dist-cjs/tabs-next/TabsNext.css.js.map +1 -0
  32. package/dist-cjs/tabs-next/TabsNext.js +113 -47
  33. package/dist-cjs/tabs-next/TabsNext.js.map +1 -1
  34. package/dist-cjs/tabs-next/TabsNextContext.js +17 -3
  35. package/dist-cjs/tabs-next/TabsNextContext.js.map +1 -1
  36. package/dist-cjs/tabs-next/domUtils.js +13 -0
  37. package/dist-cjs/tabs-next/domUtils.js.map +1 -0
  38. package/dist-cjs/tabs-next/hooks/overflowMath.js +86 -0
  39. package/dist-cjs/tabs-next/hooks/overflowMath.js.map +1 -0
  40. package/dist-cjs/tabs-next/hooks/useCollection.js +147 -41
  41. package/dist-cjs/tabs-next/hooks/useCollection.js.map +1 -1
  42. package/dist-cjs/tabs-next/hooks/useFocusWithRetry.js +64 -0
  43. package/dist-cjs/tabs-next/hooks/useFocusWithRetry.js.map +1 -0
  44. package/dist-cjs/tabs-next/hooks/useOverflow.js +240 -156
  45. package/dist-cjs/tabs-next/hooks/useOverflow.js.map +1 -1
  46. package/dist-cjs/tabs-next/hooks/useOverflowLayoutState.js +99 -0
  47. package/dist-cjs/tabs-next/hooks/useOverflowLayoutState.js.map +1 -0
  48. package/dist-cjs/tabs-next/hooks/useOverflowSelectionState.js +60 -0
  49. package/dist-cjs/tabs-next/hooks/useOverflowSelectionState.js.map +1 -0
  50. package/dist-cjs/tabs-next/hooks/useRenderedTabWidth.js +92 -0
  51. package/dist-cjs/tabs-next/hooks/useRenderedTabWidth.js.map +1 -0
  52. package/dist-cjs/tabs-next/hooks/useRenderedTabsRegistry.js +200 -0
  53. package/dist-cjs/tabs-next/hooks/useRenderedTabsRegistry.js.map +1 -0
  54. package/dist-cjs/tabs-next/hooks/useTabListRecovery.js +76 -0
  55. package/dist-cjs/tabs-next/hooks/useTabListRecovery.js.map +1 -0
  56. package/dist-cjs/tabs-next/hooks/useTabRemovalHandler.js +165 -0
  57. package/dist-cjs/tabs-next/hooks/useTabRemovalHandler.js.map +1 -0
  58. package/dist-cjs/tabs-next/hooks/useTabSelectionFocus.js +80 -0
  59. package/dist-cjs/tabs-next/hooks/useTabSelectionFocus.js.map +1 -0
  60. package/dist-cjs/tabs-next/widthMeasurement.js +42 -0
  61. package/dist-cjs/tabs-next/widthMeasurement.js.map +1 -0
  62. package/dist-cjs/tree/Tree.css.js +1 -1
  63. package/dist-cjs/tree/TreeNode.css.js +1 -1
  64. package/dist-cjs/tree/TreeNode.js +1 -1
  65. package/dist-cjs/tree/TreeNode.js.map +1 -1
  66. package/dist-cjs/tree/TreeNodeExpansionIcon.css.js +1 -1
  67. package/dist-cjs/tree/TreeNodeTrigger.css.js +1 -1
  68. package/dist-cjs/tree/TreeNodeTrigger.js +2 -2
  69. package/dist-cjs/tree/TreeNodeTrigger.js.map +1 -1
  70. package/dist-cjs/utils/useEventCallback.js +5 -5
  71. package/dist-cjs/utils/useEventCallback.js.map +1 -1
  72. package/dist-es/calendar/internal/CalendarDay.css.js +1 -1
  73. package/dist-es/contact-details/ContactDetails.css.js +1 -1
  74. package/dist-es/list-deprecated/ListStateContext.js +1 -1
  75. package/dist-es/list-deprecated/ListStateContext.js.map +1 -1
  76. package/dist-es/tabs-next/TabBar.css.js +1 -1
  77. package/dist-es/tabs-next/TabBar.js +1 -1
  78. package/dist-es/tabs-next/TabBar.js.map +1 -1
  79. package/dist-es/tabs-next/TabListLayoutContext.js +10 -0
  80. package/dist-es/tabs-next/TabListLayoutContext.js.map +1 -0
  81. package/dist-es/tabs-next/TabListNext.css.js +1 -1
  82. package/dist-es/tabs-next/TabListNext.js +182 -36
  83. package/dist-es/tabs-next/TabListNext.js.map +1 -1
  84. package/dist-es/tabs-next/TabNext.js +113 -9
  85. package/dist-es/tabs-next/TabNext.js.map +1 -1
  86. package/dist-es/tabs-next/TabNextAction.js +25 -2
  87. package/dist-es/tabs-next/TabNextAction.js.map +1 -1
  88. package/dist-es/tabs-next/TabNextPanel.js +31 -16
  89. package/dist-es/tabs-next/TabNextPanel.js.map +1 -1
  90. package/dist-es/tabs-next/TabNextTrigger.js +110 -9
  91. package/dist-es/tabs-next/TabNextTrigger.js.map +1 -1
  92. package/dist-es/tabs-next/TabOverflowList.css.js +1 -1
  93. package/dist-es/tabs-next/TabOverflowList.js +172 -68
  94. package/dist-es/tabs-next/TabOverflowList.js.map +1 -1
  95. package/dist-es/tabs-next/TabSlot.js +28 -0
  96. package/dist-es/tabs-next/TabSlot.js.map +1 -0
  97. package/dist-es/tabs-next/TabSlotRegistryContext.js +13 -0
  98. package/dist-es/tabs-next/TabSlotRegistryContext.js.map +1 -0
  99. package/dist-es/tabs-next/TabsNext.css.js +4 -0
  100. package/dist-es/tabs-next/TabsNext.css.js.map +1 -0
  101. package/dist-es/tabs-next/TabsNext.js +114 -48
  102. package/dist-es/tabs-next/TabsNext.js.map +1 -1
  103. package/dist-es/tabs-next/TabsNextContext.js +17 -3
  104. package/dist-es/tabs-next/TabsNextContext.js.map +1 -1
  105. package/dist-es/tabs-next/domUtils.js +11 -0
  106. package/dist-es/tabs-next/domUtils.js.map +1 -0
  107. package/dist-es/tabs-next/hooks/overflowMath.js +82 -0
  108. package/dist-es/tabs-next/hooks/overflowMath.js.map +1 -0
  109. package/dist-es/tabs-next/hooks/useCollection.js +148 -42
  110. package/dist-es/tabs-next/hooks/useCollection.js.map +1 -1
  111. package/dist-es/tabs-next/hooks/useFocusWithRetry.js +62 -0
  112. package/dist-es/tabs-next/hooks/useFocusWithRetry.js.map +1 -0
  113. package/dist-es/tabs-next/hooks/useOverflow.js +242 -158
  114. package/dist-es/tabs-next/hooks/useOverflow.js.map +1 -1
  115. package/dist-es/tabs-next/hooks/useOverflowLayoutState.js +97 -0
  116. package/dist-es/tabs-next/hooks/useOverflowLayoutState.js.map +1 -0
  117. package/dist-es/tabs-next/hooks/useOverflowSelectionState.js +58 -0
  118. package/dist-es/tabs-next/hooks/useOverflowSelectionState.js.map +1 -0
  119. package/dist-es/tabs-next/hooks/useRenderedTabWidth.js +90 -0
  120. package/dist-es/tabs-next/hooks/useRenderedTabWidth.js.map +1 -0
  121. package/dist-es/tabs-next/hooks/useRenderedTabsRegistry.js +198 -0
  122. package/dist-es/tabs-next/hooks/useRenderedTabsRegistry.js.map +1 -0
  123. package/dist-es/tabs-next/hooks/useTabListRecovery.js +74 -0
  124. package/dist-es/tabs-next/hooks/useTabListRecovery.js.map +1 -0
  125. package/dist-es/tabs-next/hooks/useTabRemovalHandler.js +163 -0
  126. package/dist-es/tabs-next/hooks/useTabRemovalHandler.js.map +1 -0
  127. package/dist-es/tabs-next/hooks/useTabSelectionFocus.js +78 -0
  128. package/dist-es/tabs-next/hooks/useTabSelectionFocus.js.map +1 -0
  129. package/dist-es/tabs-next/widthMeasurement.js +36 -0
  130. package/dist-es/tabs-next/widthMeasurement.js.map +1 -0
  131. package/dist-es/tree/Tree.css.js +1 -1
  132. package/dist-es/tree/TreeNode.css.js +1 -1
  133. package/dist-es/tree/TreeNode.js +1 -1
  134. package/dist-es/tree/TreeNode.js.map +1 -1
  135. package/dist-es/tree/TreeNodeExpansionIcon.css.js +1 -1
  136. package/dist-es/tree/TreeNodeTrigger.css.js +1 -1
  137. package/dist-es/tree/TreeNodeTrigger.js +2 -2
  138. package/dist-es/tree/TreeNodeTrigger.js.map +1 -1
  139. package/dist-es/utils/useEventCallback.js +5 -5
  140. package/dist-es/utils/useEventCallback.js.map +1 -1
  141. package/dist-types/cascading-menu/internal/useMenuTriggerHandlers.d.ts +1 -1
  142. package/dist-types/list-deprecated/ListStateContext.d.ts +7 -2
  143. package/dist-types/tabs-next/TabListLayoutContext.d.ts +9 -0
  144. package/dist-types/tabs-next/TabNext.d.ts +1 -1
  145. package/dist-types/tabs-next/TabNextPanel.d.ts +2 -1
  146. package/dist-types/tabs-next/TabOverflowList.d.ts +3 -4
  147. package/dist-types/tabs-next/TabSlot.d.ts +6 -0
  148. package/dist-types/tabs-next/TabSlotRegistryContext.d.ts +5 -0
  149. package/dist-types/tabs-next/TabsNext.d.ts +2 -1
  150. package/dist-types/tabs-next/TabsNextContext.d.ts +26 -4
  151. package/dist-types/tabs-next/domUtils.d.ts +1 -0
  152. package/dist-types/tabs-next/hooks/overflowMath.d.ts +18 -0
  153. package/dist-types/tabs-next/hooks/useCollection.d.ts +15 -3
  154. package/dist-types/tabs-next/hooks/useFocusWithRetry.d.ts +9 -0
  155. package/dist-types/tabs-next/hooks/useOverflow.d.ts +5 -5
  156. package/dist-types/tabs-next/hooks/useOverflowLayoutState.d.ts +13 -0
  157. package/dist-types/tabs-next/hooks/useOverflowSelectionState.d.ts +13 -0
  158. package/dist-types/tabs-next/hooks/useRenderedTabWidth.d.ts +12 -0
  159. package/dist-types/tabs-next/hooks/useRenderedTabsRegistry.d.ts +12 -0
  160. package/dist-types/tabs-next/hooks/useTabListRecovery.d.ts +12 -0
  161. package/dist-types/tabs-next/hooks/useTabRemovalHandler.d.ts +32 -0
  162. package/dist-types/tabs-next/hooks/useTabSelectionFocus.d.ts +15 -0
  163. package/dist-types/tabs-next/widthMeasurement.d.ts +5 -0
  164. package/dist-types/tokenized-input/internal/InputPill.d.ts +1 -1
  165. package/dist-types/tokenized-input-next/internal/InputPill.d.ts +1 -1
  166. package/dist-types/utils/useEventCallback.d.ts +1 -1
  167. package/package.json +3 -3
  168. package/dist-cjs/tabs-next/hooks/useFocusOutside.js +0 -25
  169. package/dist-cjs/tabs-next/hooks/useFocusOutside.js.map +0 -1
  170. package/dist-cjs/tabs-next/hooks/useRestoreActiveTab.js +0 -93
  171. package/dist-cjs/tabs-next/hooks/useRestoreActiveTab.js.map +0 -1
  172. package/dist-es/tabs-next/hooks/useFocusOutside.js +0 -23
  173. package/dist-es/tabs-next/hooks/useFocusOutside.js.map +0 -1
  174. package/dist-es/tabs-next/hooks/useRestoreActiveTab.js +0 -91
  175. package/dist-es/tabs-next/hooks/useRestoreActiveTab.js.map +0 -1
  176. package/dist-types/tabs-next/hooks/useFocusOutside.d.ts +0 -2
  177. package/dist-types/tabs-next/hooks/useRestoreActiveTab.d.ts +0 -10
@@ -1,14 +1,22 @@
1
- import { useState, useRef, useCallback } from 'react';
1
+ import { useRef, useState, useCallback, useEffect } from 'react';
2
2
 
3
3
  function sortBasedOnDOMPosition(items) {
4
4
  const indexedItems = items.map((item, index) => [index, item]);
5
5
  let orderChanged = false;
6
6
  indexedItems.sort(([itemAIndex, itemA], [itemBIndex, itemB]) => {
7
+ if (itemA.order != null && itemA.order >= 0 && itemB.order != null && itemB.order >= 0 && itemA.order !== itemB.order) {
8
+ if (itemA.order < itemB.order && itemAIndex > itemBIndex || itemA.order > itemB.order && itemAIndex < itemBIndex) {
9
+ orderChanged = true;
10
+ }
11
+ return itemA.order - itemB.order;
12
+ }
7
13
  const itemAElement = itemA.element;
8
14
  const itemBElement = itemB.element;
9
15
  if (itemAElement === itemBElement) return 0;
10
16
  if (!itemAElement || !itemBElement) return 0;
11
- if (itemAElement.compareDocumentPosition(itemBElement) & Node.DOCUMENT_POSITION_FOLLOWING) {
17
+ const pos = itemAElement.compareDocumentPosition(itemBElement);
18
+ if (pos & Node.DOCUMENT_POSITION_DISCONNECTED) return 0;
19
+ if (pos & Node.DOCUMENT_POSITION_FOLLOWING) {
12
20
  if (itemAIndex > itemBIndex) {
13
21
  orderChanged = true;
14
22
  }
@@ -24,64 +32,162 @@ function sortBasedOnDOMPosition(items) {
24
32
  }
25
33
  return items;
26
34
  }
27
- function useCollection({ wrap }) {
28
- const [items, setItems] = useState([]);
35
+ function useCollection({ wrap, targetWindow }) {
29
36
  const itemsRef = useRef([]);
30
37
  const itemMap = useRef(/* @__PURE__ */ new Map());
31
- const registerItem = useCallback((item) => {
32
- setItems((old) => {
33
- const newItems = old.slice();
34
- const index = newItems.findIndex(({ id }) => id === item.id);
35
- if (index !== -1) {
36
- const newItem = { ...newItems[index], ...item };
37
- newItems[index] = newItem;
38
- itemMap.current.set(item.id, newItem);
39
- } else {
40
- newItems.push(item);
41
- itemMap.current.set(item.id, item);
38
+ const removedItems = useRef(/* @__PURE__ */ new Map());
39
+ const [removalVersion, setRemovalVersion] = useState(0);
40
+ const getOrderedItems = useCallback(() => {
41
+ return sortBasedOnDOMPosition(Array.from(itemMap.current.values()));
42
+ }, []);
43
+ const getNavigableItems = useCallback(() => {
44
+ return getOrderedItems().filter((item) => {
45
+ if (item.location === "hidden") {
46
+ return false;
42
47
  }
43
- const value = sortBasedOnDOMPosition(newItems);
44
- itemsRef.current = value;
45
- return value;
48
+ return !!item.element;
46
49
  });
47
- return () => {
48
- setItems((old) => {
50
+ }, [getOrderedItems]);
51
+ const sortItems = useCallback(() => {
52
+ itemsRef.current = getOrderedItems();
53
+ }, [getOrderedItems]);
54
+ const getRemovedItems = useCallback(() => {
55
+ const items = new Map(removedItems.current);
56
+ removedItems.current.clear();
57
+ return items;
58
+ }, []);
59
+ const rafId = useRef(null);
60
+ const scheduleSort = useCallback(() => {
61
+ if (!(targetWindow == null ? void 0 : targetWindow.requestAnimationFrame)) {
62
+ sortItems();
63
+ return;
64
+ }
65
+ if (rafId.current != null) {
66
+ targetWindow.cancelAnimationFrame(rafId.current);
67
+ }
68
+ rafId.current = targetWindow.requestAnimationFrame(() => {
69
+ rafId.current = null;
70
+ sortItems();
71
+ });
72
+ }, [sortItems, targetWindow]);
73
+ const registerItem = useCallback(
74
+ (item) => {
75
+ itemMap.current.set(item.id, item);
76
+ removedItems.current.delete(item.id);
77
+ scheduleSort();
78
+ return () => {
79
+ const currentItems = getOrderedItems();
80
+ const currentItem = itemMap.current.get(item.id) ?? item;
81
+ const staleIndex = currentItems.findIndex(({ id }) => id === item.id);
82
+ removedItems.current.set(item.id, {
83
+ ...currentItem,
84
+ staleIndex
85
+ });
86
+ itemsRef.current = currentItems.filter(({ id }) => id !== item.id);
49
87
  itemMap.current.delete(item.id);
50
- return old.filter(({ id }) => id !== item.id);
88
+ setRemovalVersion((currentVersion) => currentVersion + 1);
89
+ };
90
+ },
91
+ [getOrderedItems, scheduleSort]
92
+ );
93
+ const updateItem = useCallback(
94
+ (id, updates) => {
95
+ const currentItem = itemMap.current.get(id);
96
+ if (!currentItem) {
97
+ return;
98
+ }
99
+ let changed = false;
100
+ const nextItem = { ...currentItem };
101
+ for (const [key, nextValue] of Object.entries(updates)) {
102
+ const typedKey = key;
103
+ if (nextItem[typedKey] !== nextValue) {
104
+ changed = true;
105
+ nextItem[typedKey] = nextValue;
106
+ }
107
+ }
108
+ if (!changed) {
109
+ return;
110
+ }
111
+ itemMap.current.set(id, nextItem);
112
+ itemsRef.current = itemsRef.current.map((item) => {
113
+ if (item.id !== id) {
114
+ return item;
115
+ }
116
+ return nextItem;
51
117
  });
52
- return itemsRef;
118
+ scheduleSort();
119
+ },
120
+ [scheduleSort]
121
+ );
122
+ useEffect(() => {
123
+ return () => {
124
+ if (rafId.current != null && targetWindow) {
125
+ targetWindow.cancelAnimationFrame(rafId.current);
126
+ }
53
127
  };
54
- }, []);
128
+ }, [targetWindow]);
55
129
  return {
56
130
  registerItem,
57
- item: (id) => {
131
+ item: useCallback((id) => {
58
132
  if (!id) return null;
59
133
  let item = itemMap.current.get(id);
60
134
  if (!item) {
61
- item = items.find((item2) => item2.id === id);
135
+ item = itemsRef.current.find((item2) => item2.id === id);
62
136
  if (item) {
63
137
  itemMap.current.set(item.id, item);
64
138
  }
65
139
  }
66
140
  return item ?? null;
67
- },
68
- getNext: (current) => {
69
- const index = items.findIndex(({ id }) => id === current);
70
- const newIndex = (index + 1) % items.length ;
71
- return items[newIndex] ?? null;
72
- },
73
- getPrevious: (current) => {
74
- const index = items.findIndex(({ id }) => id === current);
75
- const newIndex = (index - 1 + items.length) % items.length ;
76
- return items[newIndex] ?? null;
77
- },
78
- getFirst: () => {
79
- return items[0] ?? null;
80
- },
81
- getLast: () => {
141
+ }, []),
142
+ getNext: useCallback(
143
+ (current) => {
144
+ const items = getNavigableItems();
145
+ if (items.length === 0) return null;
146
+ const index = items.findIndex(({ id }) => id === current);
147
+ if (index === -1) {
148
+ return items[0] ;
149
+ }
150
+ const newIndex = (index + 1) % items.length ;
151
+ return items[newIndex] ?? null;
152
+ },
153
+ [getNavigableItems, wrap]
154
+ ),
155
+ getPrevious: useCallback(
156
+ (current) => {
157
+ const items = getNavigableItems();
158
+ if (items.length === 0) return null;
159
+ const index = items.findIndex(({ id }) => id === current);
160
+ if (index === -1) {
161
+ return items[items.length - 1] ;
162
+ }
163
+ const newIndex = (index - 1 + items.length) % items.length ;
164
+ return items[newIndex] ?? null;
165
+ },
166
+ [getNavigableItems, wrap]
167
+ ),
168
+ getFirst: useCallback(() => {
169
+ return getNavigableItems()[0] ?? null;
170
+ }, [getNavigableItems]),
171
+ getLast: useCallback(() => {
172
+ const items = getNavigableItems();
82
173
  return items[items.length - 1] ?? null;
83
- },
84
- items
174
+ }, [getNavigableItems]),
175
+ getIndex: useCallback(
176
+ (current) => {
177
+ return getNavigableItems().findIndex(({ id }) => id === current);
178
+ },
179
+ [getNavigableItems]
180
+ ),
181
+ itemAt: useCallback(
182
+ (index) => {
183
+ return getNavigableItems()[index] ?? null;
184
+ },
185
+ [getNavigableItems]
186
+ ),
187
+ updateItem,
188
+ getRemovedItems,
189
+ removalVersion,
190
+ sortItems
85
191
  };
86
192
  }
87
193
 
@@ -1 +1 @@
1
- {"version":3,"file":"useCollection.js","sources":["../src/tabs-next/hooks/useCollection.ts"],"sourcesContent":["import { useCallback, useRef, useState } from \"react\";\n\nexport interface Item {\n id: string;\n element?: HTMLElement | null;\n value: string;\n}\n\nfunction sortBasedOnDOMPosition(items: Item[]): Item[] {\n const indexedItems = items.map((item, index) => [index, item] as const);\n let orderChanged = false;\n indexedItems.sort(([itemAIndex, itemA], [itemBIndex, itemB]) => {\n const itemAElement = itemA.element;\n const itemBElement = itemB.element;\n if (itemAElement === itemBElement) return 0;\n if (!itemAElement || !itemBElement) return 0;\n\n if (\n itemAElement.compareDocumentPosition(itemBElement) &\n Node.DOCUMENT_POSITION_FOLLOWING\n ) {\n if (itemAIndex > itemBIndex) {\n orderChanged = true;\n }\n return -1;\n }\n\n if (itemAIndex < itemBIndex) {\n orderChanged = true;\n }\n return 1;\n });\n\n if (orderChanged) {\n return indexedItems.map(([_, item]) => item);\n }\n return items;\n}\n\ninterface UseCollectionProps {\n wrap: boolean;\n}\n\nexport function useCollection({ wrap }: UseCollectionProps) {\n const [items, setItems] = useState<Item[]>([]);\n const itemsRef = useRef<Item[]>([]);\n const itemMap = useRef<Map<string, Item>>(new Map());\n\n const registerItem = useCallback((item: Item) => {\n setItems((old) => {\n const newItems = old.slice();\n const index = newItems.findIndex(({ id }) => id === item.id);\n if (index !== -1) {\n const newItem = { ...newItems[index], ...item };\n newItems[index] = newItem;\n itemMap.current.set(item.id, newItem);\n } else {\n newItems.push(item);\n itemMap.current.set(item.id, item);\n }\n const value = sortBasedOnDOMPosition(newItems);\n itemsRef.current = value;\n return value;\n });\n\n return () => {\n setItems((old) => {\n itemMap.current.delete(item.id);\n return old.filter(({ id }) => id !== item.id);\n });\n return itemsRef;\n };\n }, []);\n\n return {\n registerItem,\n item: (id?: string | null): Item | null => {\n if (!id) return null;\n let item = itemMap.current.get(id);\n if (!item) {\n item = items.find((item) => item.id === id);\n if (item) {\n itemMap.current.set(item.id, item);\n }\n }\n return item ?? null;\n },\n getNext: (current: string): Item | null => {\n const index = items.findIndex(({ id }) => id === current);\n\n const newIndex = wrap\n ? (index + 1) % items.length\n : Math.min(index + 1, items.length - 1);\n\n return items[newIndex] ?? null;\n },\n getPrevious: (current: string): Item | null => {\n const index = items.findIndex(({ id }) => id === current);\n\n const newIndex = wrap\n ? (index - 1 + items.length) % items.length\n : Math.max(index - 1, 0);\n\n return items[newIndex] ?? null;\n },\n getFirst: (): Item | null => {\n return items[0] ?? null;\n },\n getLast: (): Item | null => {\n return items[items.length - 1] ?? null;\n },\n items,\n };\n}\n"],"names":["item"],"mappings":"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"}
1
+ {"version":3,"file":"useCollection.js","sources":["../src/tabs-next/hooks/useCollection.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\n\nexport interface Item {\n id: string;\n element?: HTMLElement | null;\n value: string;\n location?: \"hidden\" | \"main\" | \"overflow\";\n order?: number;\n stale?: boolean;\n}\n\ninterface StaleItem extends Item {\n staleIndex?: number;\n}\n\nfunction sortBasedOnDOMPosition(items: Item[]): Item[] {\n const indexedItems = items.map((item, index) => [index, item] as const);\n let orderChanged = false;\n indexedItems.sort(([itemAIndex, itemA], [itemBIndex, itemB]) => {\n if (\n itemA.order != null &&\n itemA.order >= 0 &&\n itemB.order != null &&\n itemB.order >= 0 &&\n itemA.order !== itemB.order\n ) {\n if (\n (itemA.order < itemB.order && itemAIndex > itemBIndex) ||\n (itemA.order > itemB.order && itemAIndex < itemBIndex)\n ) {\n orderChanged = true;\n }\n return itemA.order - itemB.order;\n }\n\n const itemAElement = itemA.element;\n const itemBElement = itemB.element;\n if (itemAElement === itemBElement) return 0;\n if (!itemAElement || !itemBElement) return 0;\n\n const pos = itemAElement.compareDocumentPosition(itemBElement);\n if (pos & Node.DOCUMENT_POSITION_DISCONNECTED) return 0;\n\n if (pos & Node.DOCUMENT_POSITION_FOLLOWING) {\n if (itemAIndex > itemBIndex) {\n orderChanged = true;\n }\n return -1;\n }\n\n if (itemAIndex < itemBIndex) {\n orderChanged = true;\n }\n return 1;\n });\n\n if (orderChanged) {\n return indexedItems.map(([_, item]) => item);\n }\n return items;\n}\n\ninterface UseCollectionProps {\n targetWindow: Window | null | undefined;\n wrap: boolean;\n}\n\nexport function useCollection({ wrap, targetWindow }: UseCollectionProps) {\n const itemsRef = useRef<Item[]>([]);\n const itemMap = useRef<Map<string, Item>>(new Map());\n const removedItems = useRef<Map<string, StaleItem>>(new Map());\n const [removalVersion, setRemovalVersion] = useState(0);\n\n const getOrderedItems = useCallback(() => {\n return sortBasedOnDOMPosition(Array.from(itemMap.current.values()));\n }, []);\n\n const getNavigableItems = useCallback(() => {\n return getOrderedItems().filter((item) => {\n if (item.location === \"hidden\") {\n return false;\n }\n\n return !!item.element;\n });\n }, [getOrderedItems]);\n\n const sortItems = useCallback(() => {\n itemsRef.current = getOrderedItems();\n }, [getOrderedItems]);\n\n const getRemovedItems = useCallback(() => {\n const items = new Map(removedItems.current);\n removedItems.current.clear();\n\n return items;\n }, []);\n\n const rafId = useRef<number | null>(null);\n\n const scheduleSort = useCallback(() => {\n if (!targetWindow?.requestAnimationFrame) {\n sortItems();\n return;\n }\n\n if (rafId.current != null) {\n targetWindow.cancelAnimationFrame(rafId.current);\n }\n\n rafId.current = targetWindow.requestAnimationFrame(() => {\n rafId.current = null;\n sortItems();\n });\n }, [sortItems, targetWindow]);\n\n const registerItem = useCallback(\n (item: Item) => {\n itemMap.current.set(item.id, item);\n removedItems.current.delete(item.id);\n scheduleSort();\n\n return () => {\n const currentItems = getOrderedItems();\n const currentItem = itemMap.current.get(item.id) ?? item;\n const staleIndex = currentItems.findIndex(({ id }) => id === item.id);\n\n removedItems.current.set(item.id, {\n ...currentItem,\n staleIndex,\n });\n\n itemsRef.current = currentItems.filter(({ id }) => id !== item.id);\n itemMap.current.delete(item.id);\n setRemovalVersion((currentVersion) => currentVersion + 1);\n };\n },\n [getOrderedItems, scheduleSort],\n );\n\n const updateItem = useCallback(\n (id: string, updates: Partial<Omit<Item, \"id\" | \"value\">>) => {\n const currentItem = itemMap.current.get(id);\n if (!currentItem) {\n return;\n }\n\n let changed = false;\n const nextItem = { ...currentItem };\n\n for (const [key, nextValue] of Object.entries(updates)) {\n const typedKey = key as keyof Omit<Item, \"id\" | \"value\">;\n if (nextItem[typedKey] !== nextValue) {\n changed = true;\n nextItem[typedKey] = nextValue as never;\n }\n }\n\n if (!changed) {\n return;\n }\n\n itemMap.current.set(id, nextItem);\n itemsRef.current = itemsRef.current.map((item) => {\n if (item.id !== id) {\n return item;\n }\n\n return nextItem;\n });\n scheduleSort();\n },\n [scheduleSort],\n );\n\n useEffect(() => {\n return () => {\n if (rafId.current != null && targetWindow) {\n targetWindow.cancelAnimationFrame(rafId.current);\n }\n };\n }, [targetWindow]);\n\n return {\n registerItem,\n item: useCallback((id?: string | null): Item | null => {\n if (!id) return null;\n let item = itemMap.current.get(id);\n if (!item) {\n item = itemsRef.current.find((item) => item.id === id);\n if (item) {\n itemMap.current.set(item.id, item);\n }\n }\n return item ?? null;\n }, []),\n getNext: useCallback(\n (current: string): Item | null => {\n const items = getNavigableItems();\n if (items.length === 0) return null;\n\n const index = items.findIndex(({ id }) => id === current);\n\n if (index === -1) {\n return wrap ? items[0] : null;\n }\n\n const newIndex = wrap\n ? (index + 1) % items.length\n : Math.min(index + 1, items.length - 1);\n\n return items[newIndex] ?? null;\n },\n [getNavigableItems, wrap],\n ),\n getPrevious: useCallback(\n (current: string): Item | null => {\n const items = getNavigableItems();\n if (items.length === 0) return null;\n\n const index = items.findIndex(({ id }) => id === current);\n\n if (index === -1) {\n return wrap ? items[items.length - 1] : null;\n }\n\n const newIndex = wrap\n ? (index - 1 + items.length) % items.length\n : Math.max(index - 1, 0);\n\n return items[newIndex] ?? null;\n },\n [getNavigableItems, wrap],\n ),\n getFirst: useCallback((): Item | null => {\n return getNavigableItems()[0] ?? null;\n }, [getNavigableItems]),\n getLast: useCallback((): Item | null => {\n const items = getNavigableItems();\n return items[items.length - 1] ?? null;\n }, [getNavigableItems]),\n getIndex: useCallback(\n (current: string): number => {\n return getNavigableItems().findIndex(({ id }) => id === current);\n },\n [getNavigableItems],\n ),\n itemAt: useCallback(\n (index: number): Item | null => {\n return getNavigableItems()[index] ?? null;\n },\n [getNavigableItems],\n ),\n updateItem,\n getRemovedItems,\n removalVersion,\n sortItems,\n };\n}\n"],"names":["item"],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ import { useRef, useCallback, useEffect } from 'react';
2
+
3
+ function useFocusWithRetry({
4
+ maxAttempts = 120,
5
+ targetWindow
6
+ }) {
7
+ const focusRafRef = useRef(null);
8
+ const cancelScheduledFocus = useCallback(() => {
9
+ if (focusRafRef.current != null && targetWindow) {
10
+ targetWindow.cancelAnimationFrame(focusRafRef.current);
11
+ focusRafRef.current = null;
12
+ }
13
+ }, [targetWindow]);
14
+ const focusElementWithRetry = useCallback(
15
+ (getElement) => {
16
+ var _a;
17
+ const doc = targetWindow == null ? void 0 : targetWindow.document;
18
+ if (!doc) {
19
+ (_a = getElement()) == null ? void 0 : _a.focus({ preventScroll: true });
20
+ return;
21
+ }
22
+ cancelScheduledFocus();
23
+ let attempts = 0;
24
+ const focusElement = () => {
25
+ const element = getElement();
26
+ if (!(element == null ? void 0 : element.isConnected)) {
27
+ if (attempts >= maxAttempts || !(targetWindow == null ? void 0 : targetWindow.requestAnimationFrame)) {
28
+ return;
29
+ }
30
+ attempts += 1;
31
+ focusRafRef.current = targetWindow.requestAnimationFrame(focusElement);
32
+ return;
33
+ }
34
+ element.focus({ preventScroll: true });
35
+ if (doc.activeElement === element || attempts >= maxAttempts) {
36
+ focusRafRef.current = null;
37
+ return;
38
+ }
39
+ attempts += 1;
40
+ if (targetWindow == null ? void 0 : targetWindow.requestAnimationFrame) {
41
+ focusRafRef.current = targetWindow.requestAnimationFrame(focusElement);
42
+ } else {
43
+ queueMicrotask(focusElement);
44
+ }
45
+ };
46
+ focusElement();
47
+ },
48
+ [cancelScheduledFocus, maxAttempts, targetWindow]
49
+ );
50
+ useEffect(() => {
51
+ return () => {
52
+ cancelScheduledFocus();
53
+ };
54
+ }, [cancelScheduledFocus]);
55
+ return {
56
+ cancelScheduledFocus,
57
+ focusElementWithRetry
58
+ };
59
+ }
60
+
61
+ export { useFocusWithRetry };
62
+ //# sourceMappingURL=useFocusWithRetry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFocusWithRetry.js","sources":["../src/tabs-next/hooks/useFocusWithRetry.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from \"react\";\n\ninterface UseFocusWithRetryArgs {\n maxAttempts?: number;\n targetWindow: Window | null | undefined;\n}\n\nexport function useFocusWithRetry({\n maxAttempts = 120,\n targetWindow,\n}: UseFocusWithRetryArgs) {\n const focusRafRef = useRef<number | null>(null);\n\n const cancelScheduledFocus = useCallback(() => {\n if (focusRafRef.current != null && targetWindow) {\n targetWindow.cancelAnimationFrame(focusRafRef.current);\n focusRafRef.current = null;\n }\n }, [targetWindow]);\n\n const focusElementWithRetry = useCallback(\n (getElement: () => HTMLElement | null | undefined) => {\n const doc = targetWindow?.document;\n if (!doc) {\n getElement()?.focus({ preventScroll: true });\n return;\n }\n\n cancelScheduledFocus();\n\n let attempts = 0;\n\n const focusElement = () => {\n const element = getElement();\n if (!element?.isConnected) {\n if (attempts >= maxAttempts || !targetWindow?.requestAnimationFrame) {\n return;\n }\n\n attempts += 1;\n focusRafRef.current =\n targetWindow.requestAnimationFrame(focusElement);\n return;\n }\n\n element.focus({ preventScroll: true });\n\n if (doc.activeElement === element || attempts >= maxAttempts) {\n focusRafRef.current = null;\n return;\n }\n\n attempts += 1;\n if (targetWindow?.requestAnimationFrame) {\n focusRafRef.current =\n targetWindow.requestAnimationFrame(focusElement);\n } else {\n queueMicrotask(focusElement);\n }\n };\n\n focusElement();\n },\n [cancelScheduledFocus, maxAttempts, targetWindow],\n );\n\n useEffect(() => {\n return () => {\n cancelScheduledFocus();\n };\n }, [cancelScheduledFocus]);\n\n return {\n cancelScheduledFocus,\n focusElementWithRetry,\n };\n}\n"],"names":[],"mappings":";;AAOO,SAAS,iBAAA,CAAkB;AAAA,EAChC,WAAA,GAAc,GAAA;AAAA,EACd;AACF,CAAA,EAA0B;AACxB,EAAA,MAAM,WAAA,GAAc,OAAsB,IAAI,CAAA;AAE9C,EAAA,MAAM,oBAAA,GAAuB,YAAY,MAAM;AAC7C,IAAA,IAAI,WAAA,CAAY,OAAA,IAAW,IAAA,IAAQ,YAAA,EAAc;AAC/C,MAAA,YAAA,CAAa,oBAAA,CAAqB,YAAY,OAAO,CAAA;AACrD,MAAA,WAAA,CAAY,OAAA,GAAU,IAAA;AAAA,IACxB;AAAA,EACF,CAAA,EAAG,CAAC,YAAY,CAAC,CAAA;AAEjB,EAAA,MAAM,qBAAA,GAAwB,WAAA;AAAA,IAC5B,CAAC,UAAA,KAAqD;AArB1D,MAAA,IAAA,EAAA;AAsBM,MAAA,MAAM,MAAM,YAAA,IAAA,IAAA,GAAA,MAAA,GAAA,YAAA,CAAc,QAAA;AAC1B,MAAA,IAAI,CAAC,GAAA,EAAK;AACR,QAAA,CAAA,EAAA,GAAA,UAAA,EAAW,KAAX,IAAA,GAAA,MAAA,GAAA,EAAA,CAAc,KAAA,CAAM,EAAE,eAAe,IAAA,EAAK,CAAA;AAC1C,QAAA;AAAA,MACF;AAEA,MAAA,oBAAA,EAAqB;AAErB,MAAA,IAAI,QAAA,GAAW,CAAA;AAEf,MAAA,MAAM,eAAe,MAAM;AACzB,QAAA,MAAM,UAAU,UAAA,EAAW;AAC3B,QAAA,IAAI,EAAC,mCAAS,WAAA,CAAA,EAAa;AACzB,UAAA,IAAI,QAAA,IAAY,WAAA,IAAe,EAAC,YAAA,IAAA,IAAA,GAAA,MAAA,GAAA,YAAA,CAAc,qBAAA,CAAA,EAAuB;AACnE,YAAA;AAAA,UACF;AAEA,UAAA,QAAA,IAAY,CAAA;AACZ,UAAA,WAAA,CAAY,OAAA,GACV,YAAA,CAAa,qBAAA,CAAsB,YAAY,CAAA;AACjD,UAAA;AAAA,QACF;AAEA,QAAA,OAAA,CAAQ,KAAA,CAAM,EAAE,aAAA,EAAe,IAAA,EAAM,CAAA;AAErC,QAAA,IAAI,GAAA,CAAI,aAAA,KAAkB,OAAA,IAAW,QAAA,IAAY,WAAA,EAAa;AAC5D,UAAA,WAAA,CAAY,OAAA,GAAU,IAAA;AACtB,UAAA;AAAA,QACF;AAEA,QAAA,QAAA,IAAY,CAAA;AACZ,QAAA,IAAI,6CAAc,qBAAA,EAAuB;AACvC,UAAA,WAAA,CAAY,OAAA,GACV,YAAA,CAAa,qBAAA,CAAsB,YAAY,CAAA;AAAA,QACnD,CAAA,MAAO;AACL,UAAA,cAAA,CAAe,YAAY,CAAA;AAAA,QAC7B;AAAA,MACF,CAAA;AAEA,MAAA,YAAA,EAAa;AAAA,IACf,CAAA;AAAA,IACA,CAAC,oBAAA,EAAsB,WAAA,EAAa,YAAY;AAAA,GAClD;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,OAAO,MAAM;AACX,MAAA,oBAAA,EAAqB;AAAA,IACvB,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,oBAAoB,CAAC,CAAA;AAEzB,EAAA,OAAO;AAAA,IACL,oBAAA;AAAA,IACA;AAAA,GACF;AACF;;;;"}