@actview/floating-ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/LICENSE +21 -0
  2. package/dist/_deprecated-inner.d.ts +82 -0
  3. package/dist/components/Composite.d.ts +109 -0
  4. package/dist/components/FloatingArrow.d.ts +66 -0
  5. package/dist/components/FloatingDelayGroup.d.ts +70 -0
  6. package/dist/components/FloatingFocusManager.d.ts +92 -0
  7. package/dist/components/FloatingList.d.ts +43 -0
  8. package/dist/components/FloatingOverlay.d.ts +18 -0
  9. package/dist/components/FloatingPortal.d.ts +63 -0
  10. package/dist/components/FloatingTree.d.ts +45 -0
  11. package/dist/components/FocusGuard.d.ts +19 -0
  12. package/dist/components/NextFloatingDelayGroup.d.ts +57 -0
  13. package/dist/floating-ui.actview.d.mts +37 -0
  14. package/dist/floating-ui.actview.d.ts +37 -0
  15. package/dist/floating-ui.actview.esm.js +6688 -0
  16. package/dist/floating-ui.actview.mjs +6688 -0
  17. package/dist/floating-ui.actview.umd.js +6772 -0
  18. package/dist/floating-ui.actview.umd.min.js +1 -0
  19. package/dist/floating-ui.actview.utils.d.mts +7 -0
  20. package/dist/floating-ui.actview.utils.d.ts +7 -0
  21. package/dist/floating-ui.actview.utils.esm.js +587 -0
  22. package/dist/floating-ui.actview.utils.mjs +587 -0
  23. package/dist/floating-ui.actview.utils.umd.js +634 -0
  24. package/dist/floating-ui.actview.utils.umd.min.js +1 -0
  25. package/dist/hooks/gridNavigation.d.ts +39 -0
  26. package/dist/hooks/useClick.d.ts +45 -0
  27. package/dist/hooks/useClientPoint.d.ts +32 -0
  28. package/dist/hooks/useDismiss.d.ts +80 -0
  29. package/dist/hooks/useFloating.d.ts +18 -0
  30. package/dist/hooks/useFloatingRootContext.d.ts +22 -0
  31. package/dist/hooks/useFocus.d.ts +21 -0
  32. package/dist/hooks/useHover.d.ts +57 -0
  33. package/dist/hooks/useId.d.ts +11 -0
  34. package/dist/hooks/useInteractions.d.ts +13 -0
  35. package/dist/hooks/useListNavigation.d.ts +176 -0
  36. package/dist/hooks/useMergeRefs.d.ts +20 -0
  37. package/dist/hooks/useRole.d.ts +33 -0
  38. package/dist/hooks/useTransition.d.ts +68 -0
  39. package/dist/hooks/useTypeahead.d.ts +66 -0
  40. package/dist/index.d.ts +37 -0
  41. package/dist/safePolygon.d.ts +12 -0
  42. package/dist/types.d.ts +140 -0
  43. package/dist/useFloating.d.ts +57 -0
  44. package/dist/utils/clearTimeoutIfSet.d.ts +2 -0
  45. package/dist/utils/composite.d.ts +41 -0
  46. package/dist/utils/constants.d.ts +8 -0
  47. package/dist/utils/createAttribute.d.ts +1 -0
  48. package/dist/utils/createEventEmitter.d.ts +5 -0
  49. package/dist/utils/deepEqual.d.ts +1 -0
  50. package/dist/utils/element.d.ts +10 -0
  51. package/dist/utils/enqueueFocus.d.ts +8 -0
  52. package/dist/utils/event.d.ts +10 -0
  53. package/dist/utils/getDPR.d.ts +1 -0
  54. package/dist/utils/hooks.d.ts +16 -0
  55. package/dist/utils/log.d.ts +2 -0
  56. package/dist/utils/markOthers.d.ts +4 -0
  57. package/dist/utils/nodes.d.ts +4 -0
  58. package/dist/utils/platform.d.ts +6 -0
  59. package/dist/utils/roundByDPR.d.ts +1 -0
  60. package/dist/utils/safeReact.d.ts +8 -0
  61. package/dist/utils/tabbable.d.ts +13 -0
  62. package/dist/utils/useLiteMergeRefs.d.ts +14 -0
  63. package/dist/utils.d.ts +7 -0
  64. package/package.json +83 -0
@@ -0,0 +1,587 @@
1
+ import { ref } from '@actview/core';
2
+ import { floor } from '@floating-ui/utils';
3
+ import { tabbable } from 'tabbable';
4
+
5
+ function hasWindow() {
6
+ return typeof window !== 'undefined';
7
+ }
8
+ function getWindow(node) {
9
+ var _node$ownerDocument;
10
+ return (node == null || (_node$ownerDocument = node.ownerDocument) == null ? void 0 : _node$ownerDocument.defaultView) || window;
11
+ }
12
+ function isHTMLElement(value) {
13
+ if (!hasWindow()) {
14
+ return false;
15
+ }
16
+ return value instanceof HTMLElement || value instanceof getWindow(value).HTMLElement;
17
+ }
18
+ function isShadowRoot(value) {
19
+ if (!hasWindow() || typeof ShadowRoot === 'undefined') {
20
+ return false;
21
+ }
22
+ return value instanceof ShadowRoot || value instanceof getWindow(value).ShadowRoot;
23
+ }
24
+
25
+ // Avoid Chrome DevTools blue warning.
26
+ function getPlatform() {
27
+ const uaData = navigator.userAgentData;
28
+ if (uaData != null && uaData.platform) {
29
+ return uaData.platform;
30
+ }
31
+ return navigator.platform;
32
+ }
33
+ function getUserAgent() {
34
+ const uaData = navigator.userAgentData;
35
+ if (uaData && Array.isArray(uaData.brands)) {
36
+ return uaData.brands.map(_ref => {
37
+ let {
38
+ brand,
39
+ version
40
+ } = _ref;
41
+ return brand + "/" + version;
42
+ }).join(' ');
43
+ }
44
+ return navigator.userAgent;
45
+ }
46
+ function isSafari() {
47
+ // Chrome DevTools does not complain about navigator.vendor
48
+ return /apple/i.test(navigator.vendor);
49
+ }
50
+ function isAndroid() {
51
+ const re = /android/i;
52
+ return re.test(getPlatform()) || re.test(getUserAgent());
53
+ }
54
+ function isMac() {
55
+ return getPlatform().toLowerCase().startsWith('mac') && !navigator.maxTouchPoints;
56
+ }
57
+ function isJSDOM() {
58
+ return getUserAgent().includes('jsdom/');
59
+ }
60
+
61
+ const FOCUSABLE_ATTRIBUTE = 'data-floating-ui-focusable';
62
+ const TYPEABLE_SELECTOR = "input:not([type='hidden']):not([disabled])," + "[contenteditable]:not([contenteditable='false']),textarea:not([disabled])";
63
+ const ARROW_LEFT = 'ArrowLeft';
64
+ const ARROW_RIGHT = 'ArrowRight';
65
+ const ARROW_UP = 'ArrowUp';
66
+ const ARROW_DOWN = 'ArrowDown';
67
+
68
+ function activeElement(doc) {
69
+ let activeElement = doc.activeElement;
70
+ while (((_activeElement = activeElement) == null || (_activeElement = _activeElement.shadowRoot) == null ? void 0 : _activeElement.activeElement) != null) {
71
+ var _activeElement;
72
+ activeElement = activeElement.shadowRoot.activeElement;
73
+ }
74
+ return activeElement;
75
+ }
76
+ function contains(parent, child) {
77
+ if (!parent || !child) {
78
+ return false;
79
+ }
80
+ const rootNode = child.getRootNode == null ? void 0 : child.getRootNode();
81
+
82
+ // First, attempt with faster native method
83
+ // `parent.contains(window)` 在真实浏览器抛 TypeError(window 不是 Node),
84
+ // jsdom 则宽容返回 false;加 Node 防护对齐两环境行为(window mousemove 等
85
+ // 事件经 getTarget 取到 window 时)。
86
+ if (child instanceof Node && parent.contains(child)) {
87
+ return true;
88
+ }
89
+
90
+ // then fallback to custom implementation with Shadow DOM support
91
+ if (rootNode && isShadowRoot(rootNode)) {
92
+ let next = child;
93
+ while (next) {
94
+ if (parent === next) {
95
+ return true;
96
+ }
97
+ // @ts-ignore
98
+ next = next.parentNode || next.host;
99
+ }
100
+ }
101
+
102
+ // Give up, the result is false
103
+ return false;
104
+ }
105
+ function getTarget(event) {
106
+ if ('composedPath' in event) {
107
+ return event.composedPath()[0];
108
+ }
109
+
110
+ // TS thinks `event` is of type never as it assumes all browsers support
111
+ // `composedPath()`, but browsers without shadow DOM don't.
112
+ return event.target;
113
+ }
114
+ function isEventTargetWithin(event, node) {
115
+ if (node == null) {
116
+ return false;
117
+ }
118
+ if ('composedPath' in event) {
119
+ return event.composedPath().includes(node);
120
+ }
121
+
122
+ // TS thinks `event` is of type never as it assumes all browsers support composedPath, but browsers without shadow dom don't
123
+ const e = event;
124
+ return e.target != null && node.contains(e.target);
125
+ }
126
+ function isRootElement(element) {
127
+ return element.matches('html,body');
128
+ }
129
+ function getDocument(node) {
130
+ return (node == null ? void 0 : node.ownerDocument) || document;
131
+ }
132
+ function isTypeableElement(element) {
133
+ return isHTMLElement(element) && element.matches(TYPEABLE_SELECTOR);
134
+ }
135
+ function isTypeableCombobox(element) {
136
+ if (!element) return false;
137
+ return element.getAttribute('role') === 'combobox' && isTypeableElement(element);
138
+ }
139
+ function matchesFocusVisible(element) {
140
+ // We don't want to block focus from working with `visibleOnly`
141
+ // (JSDOM doesn't match `:focus-visible` when the element has `:focus`)
142
+ if (!element || isJSDOM()) return true;
143
+ try {
144
+ return element.matches(':focus-visible');
145
+ } catch (_e) {
146
+ return true;
147
+ }
148
+ }
149
+ function getFloatingFocusElement(floatingElement) {
150
+ if (!floatingElement) {
151
+ return null;
152
+ }
153
+ // Try to find the element that has `{...getFloatingProps()}` spread on it.
154
+ // This indicates the floating element is acting as a positioning wrapper, and
155
+ // so focus should be managed on the child element with the event handlers and
156
+ // aria props.
157
+ return floatingElement.hasAttribute(FOCUSABLE_ATTRIBUTE) ? floatingElement : floatingElement.querySelector("[" + FOCUSABLE_ATTRIBUTE + "]") || floatingElement;
158
+ }
159
+
160
+ function getNodeChildren(nodes, id, onlyOpenChildren) {
161
+ if (onlyOpenChildren === void 0) {
162
+ onlyOpenChildren = true;
163
+ }
164
+ const directChildren = nodes.filter(node => {
165
+ var _node$context;
166
+ return node.parentId === id && (!onlyOpenChildren || ((_node$context = node.context) == null ? void 0 : _node$context.open.value));
167
+ });
168
+ return directChildren.flatMap(child => [child, ...getNodeChildren(nodes, child.id, onlyOpenChildren)]);
169
+ }
170
+ function getDeepestNode(nodes, id) {
171
+ let deepestNodeId;
172
+ let maxDepth = -1;
173
+ function findDeepest(nodeId, depth) {
174
+ if (depth > maxDepth) {
175
+ deepestNodeId = nodeId;
176
+ maxDepth = depth;
177
+ }
178
+ const children = getNodeChildren(nodes, nodeId);
179
+ children.forEach(child => {
180
+ findDeepest(child.id, depth + 1);
181
+ });
182
+ }
183
+ findDeepest(id, 0);
184
+ return nodes.find(node => node.id === deepestNodeId);
185
+ }
186
+ function getNodeAncestors(nodes, id) {
187
+ var _nodes$find;
188
+ let allAncestors = [];
189
+ let currentParentId = (_nodes$find = nodes.find(node => node.id === id)) == null ? void 0 : _nodes$find.parentId;
190
+ while (currentParentId) {
191
+ const currentNode = nodes.find(node => node.id === currentParentId);
192
+ currentParentId = currentNode == null ? void 0 : currentNode.parentId;
193
+ if (currentNode) {
194
+ allAncestors = allAncestors.concat(currentNode);
195
+ }
196
+ }
197
+ return allAncestors;
198
+ }
199
+
200
+ // actview: `React.SyntheticEvent` → 结构类型(actview 事件是原生 Event)
201
+
202
+ function stopEvent(event) {
203
+ event.preventDefault();
204
+ event.stopPropagation();
205
+ }
206
+ function isReactEvent(event) {
207
+ return 'nativeEvent' in event;
208
+ }
209
+
210
+ // License: https://github.com/adobe/react-spectrum/blob/b35d5c02fe900badccd0cf1a8f23bb593419f238/packages/@react-aria/utils/src/isVirtualEvent.ts
211
+ function isVirtualClick(event) {
212
+ // FIXME: Firefox is now emitting a deprecation warning for `mozInputSource`.
213
+ // Try to find a workaround for this. `react-aria` source still has the check.
214
+ if (event.mozInputSource === 0 && event.isTrusted) {
215
+ return true;
216
+ }
217
+ if (isAndroid() && event.pointerType) {
218
+ return event.type === 'click' && event.buttons === 1;
219
+ }
220
+ return event.detail === 0 && !event.pointerType;
221
+ }
222
+ function isVirtualPointerEvent(event) {
223
+ if (isJSDOM()) return false;
224
+ return !isAndroid() && event.width === 0 && event.height === 0 || isAndroid() && event.width === 1 && event.height === 1 && event.pressure === 0 && event.detail === 0 && event.pointerType === 'mouse' ||
225
+ // iOS VoiceOver returns 0.333• for width/height.
226
+ event.width < 1 && event.height < 1 && event.pressure === 0 && event.detail === 0 && event.pointerType === 'touch';
227
+ }
228
+ function isMouseLikePointerType(pointerType, strict) {
229
+ // On some Linux machines with Chromium, mouse inputs return a `pointerType`
230
+ // of "pen": https://github.com/floating-ui/floating-ui/issues/2015
231
+ const values = ['mouse', 'pen'];
232
+ if (!strict) {
233
+ values.push('', undefined);
234
+ }
235
+ return values.includes(pointerType);
236
+ }
237
+
238
+ /**
239
+ * actview 版(upstream 为 React hooks:useLatestRef / useEffectEvent)。
240
+ *
241
+ * 与 upstream 的差异:
242
+ * - ref 为 actview 框架类型 `Ref<T>`(.value,非 React 的 .current),创建用 `ref()`
243
+ * - actview 无渲染循环与 effect 概念(setup 只执行一次、render 闭包每次渲染执行)——
244
+ * `useLatestRef` 每次调用返回新的 `ref()`(引用稳定性由调用方负责)
245
+ * - `useEffectEvent` 无 useInsertionEffect 概念:回调在调用时同步写入 ref,
246
+ * 返回的稳定闭包始终调用最新回调。
247
+ * - `useModernLayoutEffect` 不再导出(React 专属,actview 无 layout effect)。
248
+ */
249
+ function useLatestRef(value) {
250
+ const r = ref(value);
251
+ return r;
252
+ }
253
+ function useEffectEvent(callback) {
254
+ const r = ref(callback);
255
+ return function () {
256
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
257
+ args[_key] = arguments[_key];
258
+ }
259
+ return r.value == null ? void 0 : r.value(...args);
260
+ };
261
+ }
262
+
263
+ // actview: `React.MutableRefObject<T>` → actview 框架类型 `Ref<T>`(.value)、
264
+ // `React.KeyboardEvent` → `KeyboardEventLike`(结构类型,无 React 依赖)
265
+
266
+ function isDifferentGridRow(index, cols, prevRow) {
267
+ return Math.floor(index / cols) !== prevRow;
268
+ }
269
+ function isIndexOutOfListBounds(listRef, index) {
270
+ return index < 0 || index >= listRef.value.length;
271
+ }
272
+ function getMinListIndex(listRef, disabledIndices) {
273
+ return findNonDisabledListIndex(listRef, {
274
+ disabledIndices
275
+ });
276
+ }
277
+ function getMaxListIndex(listRef, disabledIndices) {
278
+ return findNonDisabledListIndex(listRef, {
279
+ decrement: true,
280
+ startingIndex: listRef.value.length,
281
+ disabledIndices
282
+ });
283
+ }
284
+ function findNonDisabledListIndex(listRef, _temp) {
285
+ let {
286
+ startingIndex = -1,
287
+ decrement = false,
288
+ disabledIndices,
289
+ amount = 1
290
+ } = _temp === void 0 ? {} : _temp;
291
+ let index = startingIndex;
292
+ do {
293
+ index += decrement ? -amount : amount;
294
+ } while (index >= 0 && index <= listRef.value.length - 1 && isListIndexDisabled(listRef, index, disabledIndices));
295
+ return index;
296
+ }
297
+ function getGridNavigatedIndex(listRef, _ref) {
298
+ let {
299
+ event,
300
+ orientation,
301
+ loop,
302
+ rtl,
303
+ cols,
304
+ disabledIndices,
305
+ minIndex,
306
+ maxIndex,
307
+ prevIndex,
308
+ stopEvent: stop = false
309
+ } = _ref;
310
+ let nextIndex = prevIndex;
311
+ if (event.key === ARROW_UP) {
312
+ stop && stopEvent(event);
313
+ if (prevIndex === -1) {
314
+ nextIndex = maxIndex;
315
+ } else {
316
+ nextIndex = findNonDisabledListIndex(listRef, {
317
+ startingIndex: nextIndex,
318
+ amount: cols,
319
+ decrement: true,
320
+ disabledIndices
321
+ });
322
+ if (loop && (prevIndex - cols < minIndex || nextIndex < 0)) {
323
+ const col = prevIndex % cols;
324
+ const maxCol = maxIndex % cols;
325
+ const offset = maxIndex - (maxCol - col);
326
+ if (maxCol === col) {
327
+ nextIndex = maxIndex;
328
+ } else {
329
+ nextIndex = maxCol > col ? offset : offset - cols;
330
+ }
331
+ }
332
+ }
333
+ if (isIndexOutOfListBounds(listRef, nextIndex)) {
334
+ nextIndex = prevIndex;
335
+ }
336
+ }
337
+ if (event.key === ARROW_DOWN) {
338
+ stop && stopEvent(event);
339
+ if (prevIndex === -1) {
340
+ nextIndex = minIndex;
341
+ } else {
342
+ nextIndex = findNonDisabledListIndex(listRef, {
343
+ startingIndex: prevIndex,
344
+ amount: cols,
345
+ disabledIndices
346
+ });
347
+ if (loop && prevIndex + cols > maxIndex) {
348
+ nextIndex = findNonDisabledListIndex(listRef, {
349
+ startingIndex: prevIndex % cols - cols,
350
+ amount: cols,
351
+ disabledIndices
352
+ });
353
+ }
354
+ }
355
+ if (isIndexOutOfListBounds(listRef, nextIndex)) {
356
+ nextIndex = prevIndex;
357
+ }
358
+ }
359
+
360
+ // Remains on the same row/column.
361
+ if (orientation === 'both') {
362
+ const prevRow = floor(prevIndex / cols);
363
+ if (event.key === (rtl ? ARROW_LEFT : ARROW_RIGHT)) {
364
+ stop && stopEvent(event);
365
+ if (prevIndex % cols !== cols - 1) {
366
+ nextIndex = findNonDisabledListIndex(listRef, {
367
+ startingIndex: prevIndex,
368
+ disabledIndices
369
+ });
370
+ if (loop && isDifferentGridRow(nextIndex, cols, prevRow)) {
371
+ nextIndex = findNonDisabledListIndex(listRef, {
372
+ startingIndex: prevIndex - prevIndex % cols - 1,
373
+ disabledIndices
374
+ });
375
+ }
376
+ } else if (loop) {
377
+ nextIndex = findNonDisabledListIndex(listRef, {
378
+ startingIndex: prevIndex - prevIndex % cols - 1,
379
+ disabledIndices
380
+ });
381
+ }
382
+ if (isDifferentGridRow(nextIndex, cols, prevRow)) {
383
+ nextIndex = prevIndex;
384
+ }
385
+ }
386
+ if (event.key === (rtl ? ARROW_RIGHT : ARROW_LEFT)) {
387
+ stop && stopEvent(event);
388
+ if (prevIndex % cols !== 0) {
389
+ nextIndex = findNonDisabledListIndex(listRef, {
390
+ startingIndex: prevIndex,
391
+ decrement: true,
392
+ disabledIndices
393
+ });
394
+ if (loop && isDifferentGridRow(nextIndex, cols, prevRow)) {
395
+ nextIndex = findNonDisabledListIndex(listRef, {
396
+ startingIndex: prevIndex + (cols - prevIndex % cols),
397
+ decrement: true,
398
+ disabledIndices
399
+ });
400
+ }
401
+ } else if (loop) {
402
+ nextIndex = findNonDisabledListIndex(listRef, {
403
+ startingIndex: prevIndex + (cols - prevIndex % cols),
404
+ decrement: true,
405
+ disabledIndices
406
+ });
407
+ }
408
+ if (isDifferentGridRow(nextIndex, cols, prevRow)) {
409
+ nextIndex = prevIndex;
410
+ }
411
+ }
412
+ const lastRow = floor(maxIndex / cols) === prevRow;
413
+ if (isIndexOutOfListBounds(listRef, nextIndex)) {
414
+ if (loop && lastRow) {
415
+ nextIndex = event.key === (rtl ? ARROW_RIGHT : ARROW_LEFT) ? maxIndex : findNonDisabledListIndex(listRef, {
416
+ startingIndex: prevIndex - prevIndex % cols - 1,
417
+ disabledIndices
418
+ });
419
+ } else {
420
+ nextIndex = prevIndex;
421
+ }
422
+ }
423
+ }
424
+ return nextIndex;
425
+ }
426
+
427
+ /** For each cell index, gets the item index that occupies that cell */
428
+ function createGridCellMap(sizes, cols, dense) {
429
+ const cellMap = [];
430
+ let startIndex = 0;
431
+ sizes.forEach((_ref2, index) => {
432
+ let {
433
+ width,
434
+ height
435
+ } = _ref2;
436
+ if (width > cols) {
437
+ if (process.env.NODE_ENV !== "production") {
438
+ throw new Error("[Floating UI]: Invalid grid - item width at index " + index + " is greater than grid columns");
439
+ }
440
+ }
441
+ let itemPlaced = false;
442
+ if (dense) {
443
+ startIndex = 0;
444
+ }
445
+ while (!itemPlaced) {
446
+ const targetCells = [];
447
+ for (let i = 0; i < width; i++) {
448
+ for (let j = 0; j < height; j++) {
449
+ targetCells.push(startIndex + i + j * cols);
450
+ }
451
+ }
452
+ if (startIndex % cols + width <= cols && targetCells.every(cell => cellMap[cell] == null)) {
453
+ targetCells.forEach(cell => {
454
+ cellMap[cell] = index;
455
+ });
456
+ itemPlaced = true;
457
+ } else {
458
+ startIndex++;
459
+ }
460
+ }
461
+ });
462
+
463
+ // convert into a non-sparse array
464
+ return [...cellMap];
465
+ }
466
+
467
+ /** Gets cell index of an item's corner or -1 when index is -1. */
468
+ function getGridCellIndexOfCorner(index, sizes, cellMap, cols, corner) {
469
+ if (index === -1) return -1;
470
+ const firstCellIndex = cellMap.indexOf(index);
471
+ const sizeItem = sizes[index];
472
+ switch (corner) {
473
+ case 'tl':
474
+ return firstCellIndex;
475
+ case 'tr':
476
+ if (!sizeItem) {
477
+ return firstCellIndex;
478
+ }
479
+ return firstCellIndex + sizeItem.width - 1;
480
+ case 'bl':
481
+ if (!sizeItem) {
482
+ return firstCellIndex;
483
+ }
484
+ return firstCellIndex + (sizeItem.height - 1) * cols;
485
+ case 'br':
486
+ return cellMap.lastIndexOf(index);
487
+ }
488
+ }
489
+
490
+ /** Gets all cell indices that correspond to the specified indices */
491
+ function getGridCellIndices(indices, cellMap) {
492
+ return cellMap.flatMap((index, cellIndex) => indices.includes(index) ? [cellIndex] : []);
493
+ }
494
+ function isListIndexDisabled(listRef, index, disabledIndices) {
495
+ var _disabledIndices$incl;
496
+ const isExplicitlyDisabled = typeof disabledIndices === 'function' ? disabledIndices(index) : (_disabledIndices$incl = disabledIndices == null ? void 0 : disabledIndices.includes(index)) != null ? _disabledIndices$incl : false;
497
+ if (isExplicitlyDisabled) {
498
+ return true;
499
+ }
500
+ const element = listRef.value[index];
501
+ if (!element) {
502
+ return false;
503
+ }
504
+ if (!isElementVisible(element)) {
505
+ return true;
506
+ }
507
+
508
+ // A natively disabled element can never receive focus, so it must always be
509
+ // skipped, even when `disabledIndices` marks it as enabled. Only
510
+ // `aria-disabled` items can be focusable-while-disabled.
511
+ if (element.matches(':disabled')) {
512
+ return true;
513
+ }
514
+
515
+ // base-ui 语义:只有未显式传入 disabledIndices 时才检查属性
516
+ // (disabled/aria-disabled)。initial sync 故意不传 disabledIndices
517
+ // (mui/base-ui#2604),使属性禁用的项在打开时也被跳过;导航时传入
518
+ // disabledIndices 数组,由数组控制(aria-disabled 项可聚焦)。
519
+ return !disabledIndices && (element.hasAttribute('disabled') || element.getAttribute('aria-disabled') === 'true');
520
+ }
521
+ function isHiddenByStyles(styles) {
522
+ return styles.visibility === 'hidden' || styles.visibility === 'collapse';
523
+ }
524
+ function isElementVisible(element, styles) {
525
+ if (styles === void 0) {
526
+ styles = element ? getComputedStyle(element) : null;
527
+ }
528
+ if (!element || !element.isConnected || !styles || isHiddenByStyles(styles)) {
529
+ return false;
530
+ }
531
+ if (typeof element.checkVisibility === 'function') {
532
+ return element.checkVisibility();
533
+ }
534
+ return styles.display !== 'none' && styles.display !== 'contents';
535
+ }
536
+
537
+ const getTabbableOptions = () => ({
538
+ getShadowRoot: true,
539
+ displayCheck:
540
+ // JSDOM does not support the `tabbable` library. To solve this we can
541
+ // check if `ResizeObserver` is a real function (not polyfilled), which
542
+ // determines if the current environment is JSDOM-like.
543
+ typeof ResizeObserver === 'function' && ResizeObserver.toString().includes('[native code]') ? 'full' : 'none'
544
+ });
545
+ function getTabbableIn(container, dir) {
546
+ const list = tabbable(container, getTabbableOptions());
547
+ const len = list.length;
548
+ if (len === 0) return;
549
+ const active = activeElement(getDocument(container));
550
+ const index = list.indexOf(active);
551
+ const nextIndex = index === -1 ? dir === 1 ? 0 : len - 1 : index + dir;
552
+ return list[nextIndex];
553
+ }
554
+ function getNextTabbable(referenceElement) {
555
+ return getTabbableIn(getDocument(referenceElement).body, 1) || referenceElement;
556
+ }
557
+ function getPreviousTabbable(referenceElement) {
558
+ return getTabbableIn(getDocument(referenceElement).body, -1) || referenceElement;
559
+ }
560
+
561
+ // actview: `React.FocusEvent` → 结构类型(actview 事件是原生 FocusEvent)
562
+ function isOutsideEvent(event, container) {
563
+ const containerElement = container || event.currentTarget;
564
+ const relatedTarget = event.relatedTarget;
565
+ return !relatedTarget || !contains(containerElement, relatedTarget);
566
+ }
567
+ function disableFocusInside(container) {
568
+ const tabbableElements = tabbable(container, getTabbableOptions());
569
+ tabbableElements.forEach(element => {
570
+ element.dataset.tabindex = element.getAttribute('tabindex') || '';
571
+ element.setAttribute('tabindex', '-1');
572
+ });
573
+ }
574
+ function enableFocusInside(container) {
575
+ const elements = container.querySelectorAll('[data-tabindex]');
576
+ elements.forEach(element => {
577
+ const tabindex = element.dataset.tabindex;
578
+ delete element.dataset.tabindex;
579
+ if (tabindex) {
580
+ element.setAttribute('tabindex', tabindex);
581
+ } else {
582
+ element.removeAttribute('tabindex');
583
+ }
584
+ });
585
+ }
586
+
587
+ export { activeElement, contains, createGridCellMap, disableFocusInside, enableFocusInside, findNonDisabledListIndex, getDeepestNode, getDocument, getFloatingFocusElement, getGridCellIndexOfCorner, getGridCellIndices, getGridNavigatedIndex, getMaxListIndex, getMinListIndex, getNextTabbable, getNodeAncestors, getNodeChildren, getPlatform, getPreviousTabbable, getTabbableOptions, getTarget, getUserAgent, isAndroid, isDifferentGridRow, isElementVisible, isEventTargetWithin, isHiddenByStyles, isIndexOutOfListBounds, isJSDOM, isListIndexDisabled, isMac, isMouseLikePointerType, isOutsideEvent, isReactEvent, isRootElement, isSafari, isTypeableCombobox, isTypeableElement, isVirtualClick, isVirtualPointerEvent, matchesFocusVisible, stopEvent, useEffectEvent, useLatestRef };