@antscorp/antsomi-ui 1.3.7-beta.4 → 1.3.7-beta.41
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.
- package/es/components/atoms/InputDynamic/InputDynamic.js +3 -3
- package/es/components/icons/QRCodeManagementIcon.d.ts +3 -0
- package/es/components/icons/QRCodeManagementIcon.js +7 -0
- package/es/components/icons/QRSetDashboardIcon.d.ts +3 -0
- package/es/components/icons/QRSetDashboardIcon.js +7 -0
- package/es/components/icons/index.d.ts +2 -0
- package/es/components/icons/index.js +2 -0
- package/es/components/molecules/AddDynamicContent/AddDynamicContent.js +28 -2
- package/es/components/molecules/AddDynamicContent/constants.d.ts +2 -0
- package/es/components/molecules/AddDynamicContent/constants.js +2 -0
- package/es/components/molecules/ColorPicker/index.d.ts +2 -0
- package/es/components/molecules/ColorPicker/index.js +8 -3
- package/es/components/molecules/EmojiPopover/EmojiPopover.d.ts +1 -0
- package/es/components/molecules/EmojiPopover/EmojiPopover.js +2 -2
- package/es/components/molecules/EmojiPopover/styled.d.ts +2 -2
- package/es/components/molecules/EmojiPopover/styled.js +1 -1
- package/es/components/molecules/SearchPopover/SearchPopover.js +2 -2
- package/es/components/molecules/SearchPopover/styled.d.ts +12 -1
- package/es/components/molecules/SearchPopover/styled.js +1 -2
- package/es/components/molecules/SearchPopover/types.d.ts +4 -3
- package/es/components/molecules/TagifyInput/TagifyInput.js +53 -18
- package/es/components/molecules/TagifyInput/types.d.ts +21 -2
- package/es/components/molecules/TagifyInput/utils.d.ts +6 -1
- package/es/components/molecules/TagifyInput/utils.js +19 -0
- package/es/components/molecules/VirtualizedMenu/VirtualizedMenu.d.ts +1 -0
- package/es/components/molecules/VirtualizedMenu/components/Item/Item.js +3 -7
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/MenuInline.d.ts +10 -10
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/MenuInline.js +46 -327
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/index.d.ts +9 -0
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/index.js +5 -0
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useFocusManagement.d.ts +23 -0
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useFocusManagement.js +81 -0
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useItemInteraction.d.ts +24 -0
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useItemInteraction.js +32 -0
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useKeyboardNavigation.d.ts +26 -0
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useKeyboardNavigation.js +93 -0
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useTreeState.d.ts +24 -0
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useTreeState.js +94 -0
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useVisibleItems.d.ts +7 -0
- package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useVisibleItems.js +132 -0
- package/es/components/molecules/VirtualizedMenu/styled.js +14 -3
- package/es/components/molecules/VirtualizedMenu/types.d.ts +1 -0
- package/es/components/molecules/VirtualizedMenu/utils.d.ts +1 -0
- package/es/components/molecules/VirtualizedMenu/utils.js +1 -0
- package/es/components/organism/ActivityTimeline/ActivityTimeline.js +3 -3
- package/es/components/organism/ActivityTimeline/constants.d.ts +9 -9
- package/es/components/organism/ActivityTimeline/constants.js +3 -3
- package/es/components/organism/ActivityTimeline/index.d.ts +530 -1
- package/es/components/organism/ActivityTimeline/index.js +9 -1
- package/es/components/organism/ActivityTimeline/utils.js +7 -6
- package/es/components/organism/TextEditor/TextEditor.d.ts +9 -2
- package/es/components/organism/TextEditor/TextEditor.js +187 -42
- package/es/components/organism/TextEditor/constants.d.ts +9 -0
- package/es/components/organism/TextEditor/constants.js +66 -0
- package/es/components/organism/TextEditor/extensions/BubbleMenu/bubble-menu-plugin.d.ts +6 -128
- package/es/components/organism/TextEditor/extensions/BubbleMenu/bubble-menu-plugin.js +7 -292
- package/es/components/organism/TextEditor/extensions/BubbleMenu/bubble-menu.d.ts +1 -1
- package/es/components/organism/TextEditor/extensions/BubbleMenu/bubble-menu.js +4 -0
- package/es/components/organism/TextEditor/extensions/Link.js +33 -14
- package/es/components/organism/TextEditor/extensions/ListItem.d.ts +10 -0
- package/es/components/organism/TextEditor/extensions/ListItem.js +93 -0
- package/es/components/organism/TextEditor/extensions/SmartTag.d.ts +5 -6
- package/es/components/organism/TextEditor/extensions/SmartTag.js +96 -4
- package/es/components/organism/TextEditor/hooks/useColorSet.js +7 -0
- package/es/components/organism/TextEditor/hooks/useMarkTracking.js +2 -1
- package/es/components/organism/TextEditor/index.d.ts +7 -5
- package/es/components/organism/TextEditor/index.scss +4 -7
- package/es/components/organism/TextEditor/provider.d.ts +1 -0
- package/es/components/organism/TextEditor/provider.js +6 -3
- package/es/components/organism/TextEditor/store.d.ts +11 -4
- package/es/components/organism/TextEditor/store.js +22 -2
- package/es/components/organism/TextEditor/stories/WithOldDynAndLink/froala-legacy-format.settings.json +95 -0
- package/es/components/organism/TextEditor/stories/WithOldDynAndLink/shared.d.ts +111 -0
- package/es/components/organism/TextEditor/stories/WithOldDynAndLink/shared.js +82 -0
- package/es/components/organism/TextEditor/stories/shared.d.ts +64 -0
- package/es/components/organism/TextEditor/stories/shared.js +57 -0
- package/es/components/organism/TextEditor/styled.d.ts +1 -1
- package/es/components/organism/TextEditor/styled.js +1 -0
- package/es/components/organism/TextEditor/types.d.ts +157 -11
- package/es/components/organism/TextEditor/types.js +1 -0
- package/es/components/organism/TextEditor/ui/BubbleMenu/BubbleMenu.d.ts +2 -1
- package/es/components/organism/TextEditor/ui/BubbleMenu/BubbleMenu.js +80 -51
- package/es/components/organism/TextEditor/ui/Emoji/EmojiList.js +1 -1
- package/es/components/organism/TextEditor/ui/Emoji/suggestion.d.ts +1 -1
- package/es/components/organism/TextEditor/ui/Emoji/suggestion.js +2 -2
- package/es/components/organism/TextEditor/ui/FontPopover/FontPopover.js +12 -2
- package/es/components/organism/TextEditor/ui/LinkInsertForm/LinkInsertForm.d.ts +16 -0
- package/es/components/organism/TextEditor/ui/LinkInsertForm/LinkInsertForm.js +61 -0
- package/es/components/organism/TextEditor/ui/LinkInsertForm/index.d.ts +2 -0
- package/es/components/organism/TextEditor/ui/LinkInsertForm/index.js +1 -0
- package/es/components/organism/TextEditor/ui/LinkPopover/LinkPopover.d.ts +9 -0
- package/es/components/organism/TextEditor/ui/LinkPopover/LinkPopover.js +126 -0
- package/es/components/organism/TextEditor/ui/LinkPopover/index.d.ts +2 -0
- package/es/components/organism/TextEditor/ui/LinkPopover/index.js +1 -0
- package/es/components/organism/TextEditor/ui/Popover/Popover.js +1 -1
- package/es/components/organism/TextEditor/ui/TextAlignSelect/TextAlignSelect.js +1 -3
- package/es/components/organism/TextEditor/ui/Toolbar/{Toolbar.d.ts → FormattingToolbar.d.ts} +3 -4
- package/es/components/organism/TextEditor/ui/Toolbar/FormattingToolbar.js +85 -0
- package/es/components/organism/TextEditor/ui/Toolbar/LinkPreviewToolbar.d.ts +10 -0
- package/es/components/organism/TextEditor/ui/Toolbar/LinkPreviewToolbar.js +39 -0
- package/es/components/organism/TextEditor/ui/Toolbar/actions/EmojiAction.js +4 -3
- package/es/components/organism/TextEditor/ui/Toolbar/actions/FontFamilyAction.d.ts +1 -0
- package/es/components/organism/TextEditor/ui/Toolbar/actions/FontFamilyAction.js +2 -2
- package/es/components/organism/TextEditor/ui/Toolbar/actions/FontSizeAction.js +6 -1
- package/es/components/organism/TextEditor/ui/Toolbar/index.d.ts +2 -1
- package/es/components/organism/TextEditor/ui/Toolbar/index.js +2 -1
- package/es/components/organism/TextEditor/utils/documentState.d.ts +14 -0
- package/es/components/organism/TextEditor/utils/documentState.js +25 -0
- package/es/components/organism/TextEditor/utils/htmlProcessing.js +60 -0
- package/es/components/organism/TextEditor/utils/link.d.ts +10 -1
- package/es/components/organism/TextEditor/utils/link.js +161 -7
- package/es/components/organism/TextEditor/utils/menu.js +2 -1
- package/es/components/organism/TextEditor/utils/selection.js +3 -2
- package/es/components/organism/TextEditor/utils/smartTag.js +2 -1
- package/es/components/organism/index.d.ts +1 -1
- package/es/hooks/index.d.ts +1 -1
- package/es/hooks/index.js +1 -1
- package/es/services/MediaTemplateDesign/UploadFile/index.js +4 -4
- package/es/utils/common.d.ts +1 -1
- package/es/utils/common.js +3 -3
- package/package.json +15 -20
- package/es/components/organism/TextEditor/ui/BubbleToolbar/BubbleToolbar.d.ts +0 -1
- package/es/components/organism/TextEditor/ui/BubbleToolbar/BubbleToolbar.js +0 -1
- package/es/components/organism/TextEditor/ui/BubbleToolbar/index.d.ts +0 -0
- package/es/components/organism/TextEditor/ui/BubbleToolbar/index.js +0 -1
- package/es/components/organism/TextEditor/ui/Toolbar/Toolbar.js +0 -39
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
items: ItemType[];
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
export declare const MenuInline: import("react").MemoExoticComponent<import("react").ForwardRefExoticComponent<Partial<{
|
|
3
|
+
items: import("../../types").ItemType[];
|
|
5
4
|
inlineIndent: number;
|
|
6
5
|
inlinePadding: number;
|
|
7
6
|
itemSpacing: number;
|
|
@@ -9,15 +8,16 @@ export declare const MenuInline: React.MemoExoticComponent<React.ForwardRefExoti
|
|
|
9
8
|
className: string;
|
|
10
9
|
itemSize: number;
|
|
11
10
|
selected: string | string[];
|
|
11
|
+
focusedKey: string;
|
|
12
12
|
expanded: string[];
|
|
13
13
|
onClick: (args: {
|
|
14
|
-
item: ItemType;
|
|
15
|
-
domEvent?:
|
|
14
|
+
item: import("../../types").ItemType;
|
|
15
|
+
domEvent?: import("react").MouseEvent<Element, MouseEvent> | undefined;
|
|
16
16
|
elKey: "item" | "item-expand-el";
|
|
17
17
|
}) => void;
|
|
18
|
-
action:
|
|
19
|
-
expandEl:
|
|
20
|
-
}) =>
|
|
18
|
+
action: import("react").ReactNode | ((item: import("../../types").ItemType, others: {
|
|
19
|
+
expandEl: import("react").ReactNode;
|
|
20
|
+
}) => import("react").ReactNode);
|
|
21
21
|
}> & {
|
|
22
22
|
mode?: "inline" | undefined;
|
|
23
|
-
} &
|
|
23
|
+
} & import("react").RefAttributes<import("../../types").VirtualizedMenuBaseHandle>>>;
|
|
@@ -1,328 +1,55 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { forwardRef,
|
|
2
|
+
import { forwardRef, useImperativeHandle, useRef, memo } from 'react';
|
|
3
3
|
import { StyledAutoSizer, VirtualizedMenuContainer } from '../../styled';
|
|
4
4
|
import { INLINE_INDENT, INLINE_PADDING, ITEM_SIZE, ITEM_SPACING } from '../../config';
|
|
5
|
-
import { CLS,
|
|
5
|
+
import { CLS, getItemSize } from '../../utils';
|
|
6
6
|
import { Item } from '../Item';
|
|
7
|
-
import { useDeepCompareEffect } from '@antscorp/antsomi-ui/es/hooks';
|
|
8
7
|
import clsx from 'clsx';
|
|
9
|
-
import {
|
|
8
|
+
import { useTreeState } from './hooks/useTreeState';
|
|
9
|
+
import { useVisibleItems } from './hooks/useVisibleItems';
|
|
10
|
+
import { useFocusManagement } from './hooks/useFocusManagement';
|
|
11
|
+
import { useKeyboardNavigation } from './hooks/useKeyboardNavigation';
|
|
12
|
+
import { useItemInteraction } from './hooks/useItemInteraction';
|
|
10
13
|
const innerElementType = forwardRef(({ style, ...rest }, ref) => (_jsx("ul", { role: "tree", "aria-label": "Virtualized Menu", ref: ref, style: style, ...rest })));
|
|
11
|
-
/**
|
|
12
|
-
* Optimized function to compute visible items using breadth-first traversal
|
|
13
|
-
* instead of filtering all items
|
|
14
|
-
*/
|
|
15
|
-
const computeVisibleItemsOptimized = (normalizeTreeItems, rootItemIds, expandedKeys) => {
|
|
16
|
-
const visibleItems = [];
|
|
17
|
-
const queue = Array.from(rootItemIds);
|
|
18
|
-
// Process queue in breadth-first manner
|
|
19
|
-
let index = 0;
|
|
20
|
-
while (index < queue.length) {
|
|
21
|
-
const itemId = queue[index++];
|
|
22
|
-
const item = normalizeTreeItems.get(itemId);
|
|
23
|
-
if (!item)
|
|
24
|
-
continue;
|
|
25
|
-
visibleItems.push(item);
|
|
26
|
-
// Add children to queue only if this item is expanded
|
|
27
|
-
if (expandedKeys.has(item.id) && item.childIds.length > 0) {
|
|
28
|
-
queue.push(...item.childIds);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
return visibleItems;
|
|
32
|
-
};
|
|
33
|
-
/**
|
|
34
|
-
* Alternative: Path-based optimization with memoization
|
|
35
|
-
* Caches path calculations to avoid redundant work
|
|
36
|
-
*/
|
|
37
|
-
const computeVisibleItemsWithPathCache = (normalizeTreeItems, expandedKeys, pathCache) => {
|
|
38
|
-
const visibleItems = [];
|
|
39
|
-
for (const item of normalizeTreeItems.values()) {
|
|
40
|
-
const isRootItem = item.level === 0;
|
|
41
|
-
if (isRootItem) {
|
|
42
|
-
visibleItems.push(item);
|
|
43
|
-
continue;
|
|
44
|
-
}
|
|
45
|
-
if (!item.parentId)
|
|
46
|
-
continue;
|
|
47
|
-
// Use cached path or compute and cache
|
|
48
|
-
let pathToParent = pathCache.get(item.parentId);
|
|
49
|
-
if (!pathToParent) {
|
|
50
|
-
pathToParent = getPathToNode(item.parentId, normalizeTreeItems);
|
|
51
|
-
pathCache.set(item.parentId, pathToParent);
|
|
52
|
-
}
|
|
53
|
-
// Check if all parents are expanded
|
|
54
|
-
const allParentExpanded = pathToParent.every(parent => expandedKeys.has(parent.id));
|
|
55
|
-
if (allParentExpanded) {
|
|
56
|
-
visibleItems.push(item);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return visibleItems;
|
|
60
|
-
};
|
|
61
|
-
/**
|
|
62
|
-
* Level-based optimization: Process items level by level
|
|
63
|
-
* More efficient for deep trees with many collapsed branches
|
|
64
|
-
*/
|
|
65
|
-
const computeVisibleItemsByLevel = (normalizeTreeItems, rootItemIds, expandedKeys) => {
|
|
66
|
-
const visibleItems = [];
|
|
67
|
-
const expandedParents = new Set();
|
|
68
|
-
// Add root items and track expanded ones
|
|
69
|
-
for (const rootId of rootItemIds) {
|
|
70
|
-
const rootItem = normalizeTreeItems.get(rootId);
|
|
71
|
-
if (rootItem) {
|
|
72
|
-
visibleItems.push(rootItem);
|
|
73
|
-
if (expandedKeys.has(rootId)) {
|
|
74
|
-
expandedParents.add(rootId);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
// Process each level
|
|
79
|
-
let currentLevelParents = expandedParents;
|
|
80
|
-
let currentLevel = 1;
|
|
81
|
-
while (currentLevelParents.size > 0) {
|
|
82
|
-
const nextLevelParents = new Set();
|
|
83
|
-
// Process all items at current level
|
|
84
|
-
for (const parentId of currentLevelParents) {
|
|
85
|
-
const parent = normalizeTreeItems.get(parentId);
|
|
86
|
-
if (!parent)
|
|
87
|
-
continue;
|
|
88
|
-
// Add all children of this expanded parent
|
|
89
|
-
for (const childId of parent.childIds) {
|
|
90
|
-
const child = normalizeTreeItems.get(childId);
|
|
91
|
-
if (child && child.level === currentLevel) {
|
|
92
|
-
visibleItems.push(child);
|
|
93
|
-
// Track if this child is expanded for next level
|
|
94
|
-
if (expandedKeys.has(childId)) {
|
|
95
|
-
nextLevelParents.add(childId);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
currentLevelParents = nextLevelParents;
|
|
101
|
-
currentLevel++;
|
|
102
|
-
}
|
|
103
|
-
return visibleItems;
|
|
104
|
-
};
|
|
105
14
|
const MenuInlineInner = forwardRef((props, ref) => {
|
|
106
|
-
const { items: itemsProp = [], expanded: expandedProp = [], selected: selectedProp = [], inlineIndent = INLINE_INDENT, inlinePadding = INLINE_PADDING, itemSize = ITEM_SIZE, itemSpacing = ITEM_SPACING, selectable = false, action, className, onClick, } = props;
|
|
107
|
-
|
|
108
|
-
const [expandedKeys, setExpandedKeys] = useState(new Set());
|
|
109
|
-
const [selectedKeys, setSelectedKeys] = useState(new Set());
|
|
15
|
+
const { items: itemsProp = [], expanded: expandedProp = [], selected: selectedProp = [], focusedKey, inlineIndent = INLINE_INDENT, inlinePadding = INLINE_PADDING, itemSize = ITEM_SIZE, itemSpacing = ITEM_SPACING, selectable = false, action, className, onClick, } = props;
|
|
16
|
+
// Refs for list and items
|
|
110
17
|
const listRef = useRef(null);
|
|
111
18
|
const itemRefs = useRef(new Map());
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
19
|
+
const isMouseDownRef = useRef(false);
|
|
20
|
+
// Tree state management
|
|
21
|
+
const { normalizeTreeItems, rootItemIds, expandedKeys, selectedKeys, handleExpandItems, handleCollapseItems, handleToggleExpandItem, handleSelectItem, expandAll, } = useTreeState({
|
|
22
|
+
items: itemsProp,
|
|
23
|
+
expanded: expandedProp,
|
|
24
|
+
selected: selectedProp,
|
|
25
|
+
selectable,
|
|
115
26
|
});
|
|
116
|
-
//
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
return [];
|
|
138
|
-
// Choose optimization strategy based on tree characteristics
|
|
139
|
-
const treeDepth = Math.max(...Array.from(normalizeTreeItems.values()).map(item => item.level));
|
|
140
|
-
const totalItems = normalizeTreeItems.size;
|
|
141
|
-
const expandedCount = expandedKeys.size;
|
|
142
|
-
// Strategy selection heuristics:
|
|
143
|
-
// - For shallow trees with many expanded items: use breadth-first
|
|
144
|
-
// - For deep trees with few expanded items: use level-based
|
|
145
|
-
// - For medium trees: use path-cache optimization
|
|
146
|
-
if (treeDepth <= 3 && expandedCount > totalItems * 0.3) {
|
|
147
|
-
// Shallow tree with many expanded items
|
|
148
|
-
return computeVisibleItemsOptimized(normalizeTreeItems, rootItemIds, expandedKeys);
|
|
149
|
-
}
|
|
150
|
-
if (treeDepth > 5 && expandedCount < totalItems * 0.2) {
|
|
151
|
-
// Deep tree with few expanded items
|
|
152
|
-
return computeVisibleItemsByLevel(normalizeTreeItems, rootItemIds, expandedKeys);
|
|
153
|
-
}
|
|
154
|
-
// Medium complexity - use cached path approach
|
|
155
|
-
return computeVisibleItemsWithPathCache(normalizeTreeItems, expandedKeys, pathCache);
|
|
156
|
-
}, [expandedKeys, normalizeTreeItems, rootItemIds, pathCache]);
|
|
157
|
-
const handleCollapseItems = useCallback((items) => {
|
|
158
|
-
setExpandedKeys(prev => {
|
|
159
|
-
const newOpenKeys = new Set(prev);
|
|
160
|
-
items.forEach(({ data }) => {
|
|
161
|
-
if (prev.has(data.key)) {
|
|
162
|
-
newOpenKeys.delete(data.key);
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
return newOpenKeys;
|
|
166
|
-
});
|
|
167
|
-
}, []);
|
|
168
|
-
useEffect(() => {
|
|
169
|
-
if (focusId && listRef.current) {
|
|
170
|
-
const index = visibleItems.findIndex(item => item.id === focusId);
|
|
171
|
-
if (index !== -1) {
|
|
172
|
-
listRef.current.scrollToItem(index, 'auto');
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}, [focusId, visibleItems]);
|
|
176
|
-
const handleExpandItems = useCallback((items, deep = 0) => {
|
|
177
|
-
setExpandedKeys(prev => {
|
|
178
|
-
const updatedExpandedKeys = new Set(prev);
|
|
179
|
-
items.forEach(item => {
|
|
180
|
-
const normalizeItem = normalizeTreeItems.get(item.data.key);
|
|
181
|
-
if (normalizeItem) {
|
|
182
|
-
updatedExpandedKeys.add(normalizeItem.id);
|
|
183
|
-
if (deep > 0) {
|
|
184
|
-
getChildrenRecursively(normalizeItem.id, normalizeTreeItems, normalizeItem.level + deep).forEach(v => updatedExpandedKeys.add(v.id));
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
return updatedExpandedKeys;
|
|
189
|
-
});
|
|
190
|
-
}, [normalizeTreeItems]);
|
|
191
|
-
useImperativeHandle(ref, () => ({
|
|
192
|
-
expandAll: () => {
|
|
193
|
-
handleExpandItems(rootNodes, Infinity);
|
|
194
|
-
},
|
|
195
|
-
}));
|
|
196
|
-
const handleSelectItem = useCallback((item) => {
|
|
197
|
-
const { key } = item.data;
|
|
198
|
-
if (!selectable || selectedKeys.has(key) || item.data.displayOnly)
|
|
199
|
-
return;
|
|
200
|
-
setSelectedKeys(new Set([key]));
|
|
201
|
-
}, [selectable, selectedKeys]);
|
|
202
|
-
const handleToggleExpandItem = useCallback((item) => {
|
|
203
|
-
const { key } = item.data;
|
|
204
|
-
const isExpanded = expandedKeys.has(key);
|
|
205
|
-
if (isExpanded) {
|
|
206
|
-
handleCollapseItems([item]);
|
|
207
|
-
}
|
|
208
|
-
else {
|
|
209
|
-
handleExpandItems([item]);
|
|
210
|
-
}
|
|
211
|
-
}, [expandedKeys, handleCollapseItems, handleExpandItems]);
|
|
212
|
-
const handleClickItem = useCallback((args) => {
|
|
213
|
-
const { item, elKey, domEvent } = args;
|
|
214
|
-
const node = normalizeTreeItems.get(item.id);
|
|
215
|
-
if (!node || node.data.displayOnly)
|
|
216
|
-
return;
|
|
217
|
-
const hasChilren = node.childIds.length > 0;
|
|
218
|
-
handleSelectItem(node);
|
|
219
|
-
if (hasChilren) {
|
|
220
|
-
handleToggleExpandItem(node);
|
|
221
|
-
}
|
|
222
|
-
setFocusId(node.id);
|
|
223
|
-
onClick?.({ item: node.data, elKey, domEvent });
|
|
224
|
-
}, [normalizeTreeItems, handleSelectItem, handleToggleExpandItem, onClick]);
|
|
225
|
-
// Helper function to find next focusable item (skip displayOnly items)
|
|
226
|
-
const findNextFocusableItem = useCallback((startIndex, direction) => {
|
|
227
|
-
const increment = direction === 'next' ? 1 : -1;
|
|
228
|
-
let index = startIndex + increment;
|
|
229
|
-
while (index >= 0 && index < visibleItems.length) {
|
|
230
|
-
const item = visibleItems[index];
|
|
231
|
-
if (!item.data.displayOnly) {
|
|
232
|
-
return index;
|
|
233
|
-
}
|
|
234
|
-
index += increment;
|
|
235
|
-
}
|
|
236
|
-
return startIndex;
|
|
237
|
-
}, [visibleItems]);
|
|
238
|
-
const findFirstFocusableItem = useCallback(() => {
|
|
239
|
-
for (let i = 0; i < visibleItems.length; i++) {
|
|
240
|
-
if (!visibleItems[i].data.displayOnly) {
|
|
241
|
-
return i;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
return 0;
|
|
245
|
-
}, [visibleItems]);
|
|
246
|
-
const findLastFocusableItem = useCallback(() => {
|
|
247
|
-
for (let i = visibleItems.length - 1; i >= 0; i--) {
|
|
248
|
-
if (!visibleItems[i].data.displayOnly) {
|
|
249
|
-
return i;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
return visibleItems.length - 1;
|
|
253
|
-
}, [visibleItems]);
|
|
254
|
-
const handleKeyDown = useCallback((e) => {
|
|
255
|
-
if (visibleItems.length === 0)
|
|
256
|
-
return;
|
|
257
|
-
e.preventDefault();
|
|
258
|
-
const currentFocusIndex = visibleItems.findIndex(item => item.id === focusId);
|
|
259
|
-
if (currentFocusIndex === -1) {
|
|
260
|
-
const firstFocusableIndex = findFirstFocusableItem();
|
|
261
|
-
setFocusId(visibleItems[firstFocusableIndex]?.id ?? null);
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
const currentFocusItem = visibleItems[currentFocusIndex];
|
|
265
|
-
switch (e.key) {
|
|
266
|
-
case 'ArrowDown': {
|
|
267
|
-
const nextFocusIndex = findNextFocusableItem(currentFocusIndex, 'next');
|
|
268
|
-
setFocusId(visibleItems[nextFocusIndex].id);
|
|
269
|
-
break;
|
|
270
|
-
}
|
|
271
|
-
case 'ArrowUp': {
|
|
272
|
-
const nextFocusIndex = findNextFocusableItem(currentFocusIndex, 'prev');
|
|
273
|
-
setFocusId(visibleItems[nextFocusIndex].id);
|
|
274
|
-
break;
|
|
275
|
-
}
|
|
276
|
-
case 'ArrowRight': {
|
|
277
|
-
if (currentFocusItem.childIds.length > 0 && !expandedKeys.has(currentFocusItem.id)) {
|
|
278
|
-
handleExpandItems([currentFocusItem]);
|
|
279
|
-
}
|
|
280
|
-
break;
|
|
281
|
-
}
|
|
282
|
-
case 'ArrowLeft': {
|
|
283
|
-
if (currentFocusItem.childIds.length > 0 && expandedKeys.has(currentFocusItem.id)) {
|
|
284
|
-
handleCollapseItems([currentFocusItem]);
|
|
285
|
-
}
|
|
286
|
-
else if (currentFocusItem?.parentId) {
|
|
287
|
-
// Find parent and ensure it's focusable
|
|
288
|
-
const parentItem = normalizeTreeItems.get(currentFocusItem.parentId);
|
|
289
|
-
if (parentItem && !parentItem.data.displayOnly) {
|
|
290
|
-
setFocusId(currentFocusItem.parentId);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
break;
|
|
294
|
-
}
|
|
295
|
-
case 'Home': {
|
|
296
|
-
const firstFocusableIndex = findFirstFocusableItem();
|
|
297
|
-
setFocusId(visibleItems[firstFocusableIndex].id);
|
|
298
|
-
break;
|
|
299
|
-
}
|
|
300
|
-
case 'End': {
|
|
301
|
-
const lastFocusableIndex = findLastFocusableItem();
|
|
302
|
-
setFocusId(visibleItems[lastFocusableIndex].id);
|
|
303
|
-
break;
|
|
304
|
-
}
|
|
305
|
-
case 'Enter': {
|
|
306
|
-
if (currentFocusItem && !currentFocusItem.data.displayOnly) {
|
|
307
|
-
handleSelectItem(currentFocusItem);
|
|
308
|
-
if (currentFocusItem.childIds.length > 0) {
|
|
309
|
-
handleToggleExpandItem(currentFocusItem);
|
|
310
|
-
}
|
|
311
|
-
onClick?.({
|
|
312
|
-
item: currentFocusItem.data,
|
|
313
|
-
elKey: 'item',
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
break;
|
|
317
|
-
}
|
|
318
|
-
default:
|
|
319
|
-
break;
|
|
320
|
-
}
|
|
321
|
-
}, [
|
|
27
|
+
// Visible items computation
|
|
28
|
+
const visibleItems = useVisibleItems(normalizeTreeItems, rootItemIds, expandedKeys);
|
|
29
|
+
// Focus management
|
|
30
|
+
const { focusId, setFocusId, findNextFocusableItem, findFirstFocusableItem, findLastFocusableItem, handleFocus, } = useFocusManagement({
|
|
31
|
+
visibleItems,
|
|
32
|
+
focusedKey,
|
|
33
|
+
listRef,
|
|
34
|
+
itemRefs,
|
|
35
|
+
isMouseDownRef,
|
|
36
|
+
});
|
|
37
|
+
// Item interaction
|
|
38
|
+
const { handleClickItem, handleMouseDown } = useItemInteraction({
|
|
39
|
+
normalizeTreeItems,
|
|
40
|
+
handleSelectItem,
|
|
41
|
+
handleToggleExpandItem,
|
|
42
|
+
setFocusId,
|
|
43
|
+
onClick,
|
|
44
|
+
isMouseDownRef,
|
|
45
|
+
});
|
|
46
|
+
// Keyboard navigation
|
|
47
|
+
const { handleKeyDown } = useKeyboardNavigation({
|
|
322
48
|
visibleItems,
|
|
323
49
|
focusId,
|
|
324
50
|
expandedKeys,
|
|
325
|
-
|
|
51
|
+
normalizeTreeItems,
|
|
52
|
+
setFocusId,
|
|
326
53
|
handleExpandItems,
|
|
327
54
|
handleCollapseItems,
|
|
328
55
|
handleSelectItem,
|
|
@@ -330,20 +57,12 @@ const MenuInlineInner = forwardRef((props, ref) => {
|
|
|
330
57
|
findNextFocusableItem,
|
|
331
58
|
findFirstFocusableItem,
|
|
332
59
|
findLastFocusableItem,
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
break;
|
|
340
|
-
isClickFont = itemEl.isSameNode(e.target) || itemEl.contains(e.target);
|
|
341
|
-
}
|
|
342
|
-
if (!isClickFont && !focusId && visibleItems.length > 0) {
|
|
343
|
-
const firstFocusableIndex = findFirstFocusableItem();
|
|
344
|
-
setFocusId(visibleItems[firstFocusableIndex]?.id || null);
|
|
345
|
-
}
|
|
346
|
-
};
|
|
60
|
+
onClick,
|
|
61
|
+
});
|
|
62
|
+
// Expose expandAll method via ref
|
|
63
|
+
useImperativeHandle(ref, () => ({
|
|
64
|
+
expandAll,
|
|
65
|
+
}));
|
|
347
66
|
const itemData = {
|
|
348
67
|
itemSpacing,
|
|
349
68
|
inlineIndent,
|
|
@@ -362,6 +81,6 @@ const MenuInlineInner = forwardRef((props, ref) => {
|
|
|
362
81
|
})),
|
|
363
82
|
onClick: handleClickItem,
|
|
364
83
|
};
|
|
365
|
-
return (_jsx(StyledAutoSizer, { className: clsx(CLS.Root.default, className), tabIndex: 0, onFocus: handleFocus, onKeyDown: handleKeyDown, children: autoSize => (_jsx(VirtualizedMenuContainer, { ref: listRef, className: clsx(CLS.MenuInline.default), itemSize: getItemSize(itemSize, itemSpacing), itemCount: visibleItems.length, height: autoSize.height, width: autoSize.width, innerElementType: innerElementType, itemData: itemData, useIsScrolling: true, children: Item })) }));
|
|
84
|
+
return (_jsx(StyledAutoSizer, { className: clsx(CLS.Root.default, className), tabIndex: 0, onFocus: handleFocus, onKeyDown: handleKeyDown, onMouseDown: handleMouseDown, children: autoSize => (_jsx(VirtualizedMenuContainer, { ref: listRef, className: clsx(CLS.MenuInline.default), itemSize: getItemSize(itemSize, itemSpacing), itemCount: visibleItems.length, height: autoSize.height, width: autoSize.width, innerElementType: innerElementType, itemData: itemData, useIsScrolling: true, children: Item })) }));
|
|
366
85
|
});
|
|
367
86
|
export const MenuInline = memo(MenuInlineInner);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { useTreeState } from './useTreeState';
|
|
2
|
+
export type { UseTreeStateReturn, UseTreeStateProps } from './useTreeState';
|
|
3
|
+
export { useVisibleItems } from './useVisibleItems';
|
|
4
|
+
export { useFocusManagement } from './useFocusManagement';
|
|
5
|
+
export type { UseFocusManagementReturn, UseFocusManagementProps } from './useFocusManagement';
|
|
6
|
+
export { useKeyboardNavigation } from './useKeyboardNavigation';
|
|
7
|
+
export type { UseKeyboardNavigationReturn, UseKeyboardNavigationProps, } from './useKeyboardNavigation';
|
|
8
|
+
export { useItemInteraction } from './useItemInteraction';
|
|
9
|
+
export type { UseItemInteractionReturn, UseItemInteractionProps } from './useItemInteraction';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { useTreeState } from './useTreeState';
|
|
2
|
+
export { useVisibleItems } from './useVisibleItems';
|
|
3
|
+
export { useFocusManagement } from './useFocusManagement';
|
|
4
|
+
export { useKeyboardNavigation } from './useKeyboardNavigation';
|
|
5
|
+
export { useItemInteraction } from './useItemInteraction';
|
package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useFocusManagement.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { VariableSizeList } from 'react-window';
|
|
3
|
+
import { NormalizedNode } from '@antscorp/antsomi-ui/es/utils/tree';
|
|
4
|
+
import { ItemType } from '../../../types';
|
|
5
|
+
export interface UseFocusManagementReturn {
|
|
6
|
+
focusId: string | null;
|
|
7
|
+
setFocusId: (id: string | null) => void;
|
|
8
|
+
findNextFocusableItem: (startIndex: number, direction: 'next' | 'prev') => number;
|
|
9
|
+
findFirstFocusableItem: () => number;
|
|
10
|
+
findLastFocusableItem: () => number;
|
|
11
|
+
handleFocus: (e: React.FocusEvent) => void;
|
|
12
|
+
}
|
|
13
|
+
export interface UseFocusManagementProps {
|
|
14
|
+
visibleItems: NormalizedNode<ItemType>[];
|
|
15
|
+
focusedKey?: string;
|
|
16
|
+
listRef: React.RefObject<VariableSizeList | null>;
|
|
17
|
+
itemRefs: React.RefObject<Map<string, HTMLLIElement>>;
|
|
18
|
+
isMouseDownRef: React.MutableRefObject<boolean>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Custom hook to manage focus state and navigation for tree items
|
|
22
|
+
*/
|
|
23
|
+
export declare const useFocusManagement: (props: UseFocusManagementProps) => UseFocusManagementReturn;
|
package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useFocusManagement.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { useState, useCallback, useEffect } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Custom hook to manage focus state and navigation for tree items
|
|
4
|
+
*/
|
|
5
|
+
export const useFocusManagement = (props) => {
|
|
6
|
+
const { visibleItems, focusedKey, listRef, itemRefs, isMouseDownRef } = props;
|
|
7
|
+
const [focusId, setFocusId] = useState(null);
|
|
8
|
+
// Sync external focusedKey prop with internal focusId state for auto-scrolling
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
if (focusedKey !== undefined) {
|
|
11
|
+
setFocusId(focusedKey);
|
|
12
|
+
}
|
|
13
|
+
}, [focusedKey]);
|
|
14
|
+
// Auto-scroll to focused item
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (focusId && listRef.current) {
|
|
17
|
+
const index = visibleItems.findIndex(item => item.id === focusId);
|
|
18
|
+
if (index !== -1) {
|
|
19
|
+
listRef.current.scrollToItem(index, 'auto');
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}, [focusId, visibleItems, listRef]);
|
|
23
|
+
// Helper function to find next focusable item (skip displayOnly items)
|
|
24
|
+
const findNextFocusableItem = useCallback((startIndex, direction) => {
|
|
25
|
+
const increment = direction === 'next' ? 1 : -1;
|
|
26
|
+
let index = startIndex + increment;
|
|
27
|
+
while (index >= 0 && index < visibleItems.length) {
|
|
28
|
+
const item = visibleItems[index];
|
|
29
|
+
if (!item.data.displayOnly) {
|
|
30
|
+
return index;
|
|
31
|
+
}
|
|
32
|
+
index += increment;
|
|
33
|
+
}
|
|
34
|
+
return startIndex;
|
|
35
|
+
}, [visibleItems]);
|
|
36
|
+
// Find first focusable item
|
|
37
|
+
const findFirstFocusableItem = useCallback(() => {
|
|
38
|
+
for (let i = 0; i < visibleItems.length; i++) {
|
|
39
|
+
if (!visibleItems[i].data.displayOnly) {
|
|
40
|
+
return i;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return 0;
|
|
44
|
+
}, [visibleItems]);
|
|
45
|
+
// Find last focusable item
|
|
46
|
+
const findLastFocusableItem = useCallback(() => {
|
|
47
|
+
for (let i = visibleItems.length - 1; i >= 0; i--) {
|
|
48
|
+
if (!visibleItems[i].data.displayOnly) {
|
|
49
|
+
return i;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return visibleItems.length - 1;
|
|
53
|
+
}, [visibleItems]);
|
|
54
|
+
// Handle focus event with auto-focusing logic
|
|
55
|
+
const handleFocus = useCallback((e) => {
|
|
56
|
+
// Skip auto-focusing if user is clicking on menu items
|
|
57
|
+
if (isMouseDownRef.current) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
let isClickFont = false;
|
|
61
|
+
if (itemRefs.current) {
|
|
62
|
+
for (const itemEl of itemRefs.current.values()) {
|
|
63
|
+
if (isClickFont)
|
|
64
|
+
break;
|
|
65
|
+
isClickFont = itemEl.isSameNode(e.target) || itemEl.contains(e.target);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (!isClickFont && !focusId && visibleItems.length > 0) {
|
|
69
|
+
const firstFocusableIndex = findFirstFocusableItem();
|
|
70
|
+
setFocusId(visibleItems[firstFocusableIndex]?.id || null);
|
|
71
|
+
}
|
|
72
|
+
}, [isMouseDownRef, itemRefs, focusId, visibleItems, findFirstFocusableItem]);
|
|
73
|
+
return {
|
|
74
|
+
focusId,
|
|
75
|
+
setFocusId,
|
|
76
|
+
findNextFocusableItem,
|
|
77
|
+
findFirstFocusableItem,
|
|
78
|
+
findLastFocusableItem,
|
|
79
|
+
handleFocus,
|
|
80
|
+
};
|
|
81
|
+
};
|
package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useItemInteraction.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { NormalizedNode } from '@antscorp/antsomi-ui/es/utils/tree';
|
|
3
|
+
import { ItemType, MenuInlineProps } from '../../../types';
|
|
4
|
+
export interface UseItemInteractionReturn {
|
|
5
|
+
handleClickItem: (args: {
|
|
6
|
+
item: NormalizedNode<ItemType>;
|
|
7
|
+
elKey: 'item' | 'item-expand-el';
|
|
8
|
+
domEvent: React.MouseEvent;
|
|
9
|
+
}) => void;
|
|
10
|
+
handleMouseDown: () => void;
|
|
11
|
+
}
|
|
12
|
+
export interface UseItemInteractionProps {
|
|
13
|
+
normalizeTreeItems: Map<string, NormalizedNode<ItemType>>;
|
|
14
|
+
handleSelectItem: (item: NormalizedNode<ItemType>) => void;
|
|
15
|
+
handleToggleExpandItem: (item: NormalizedNode<ItemType>) => void;
|
|
16
|
+
setFocusId: (id: string) => void;
|
|
17
|
+
onClick?: MenuInlineProps['onClick'];
|
|
18
|
+
isMouseDownRef: React.MutableRefObject<boolean>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Custom hook to handle user interactions with menu items
|
|
22
|
+
* Manages click events and mouse down state
|
|
23
|
+
*/
|
|
24
|
+
export declare const useItemInteraction: (props: UseItemInteractionProps) => UseItemInteractionReturn;
|
package/es/components/molecules/VirtualizedMenu/components/MenuInline/hooks/useItemInteraction.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Custom hook to handle user interactions with menu items
|
|
4
|
+
* Manages click events and mouse down state
|
|
5
|
+
*/
|
|
6
|
+
export const useItemInteraction = (props) => {
|
|
7
|
+
const { normalizeTreeItems, handleSelectItem, handleToggleExpandItem, setFocusId, onClick, isMouseDownRef, } = props;
|
|
8
|
+
const handleClickItem = useCallback((args) => {
|
|
9
|
+
const { item, elKey, domEvent } = args;
|
|
10
|
+
const node = normalizeTreeItems.get(item.id);
|
|
11
|
+
if (!node || node.data.displayOnly)
|
|
12
|
+
return;
|
|
13
|
+
const hasChilren = node.childIds.length > 0;
|
|
14
|
+
handleSelectItem(node);
|
|
15
|
+
if (hasChilren) {
|
|
16
|
+
handleToggleExpandItem(node);
|
|
17
|
+
}
|
|
18
|
+
setFocusId(node.id);
|
|
19
|
+
onClick?.({ item: node.data, elKey, domEvent });
|
|
20
|
+
}, [normalizeTreeItems, handleSelectItem, handleToggleExpandItem, setFocusId, onClick]);
|
|
21
|
+
const handleMouseDown = useCallback(() => {
|
|
22
|
+
isMouseDownRef.current = true;
|
|
23
|
+
// Reset flag after a short delay to handle the focus event
|
|
24
|
+
setTimeout(() => {
|
|
25
|
+
isMouseDownRef.current = false;
|
|
26
|
+
}, 0);
|
|
27
|
+
}, [isMouseDownRef]);
|
|
28
|
+
return {
|
|
29
|
+
handleClickItem,
|
|
30
|
+
handleMouseDown,
|
|
31
|
+
};
|
|
32
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { NormalizedNode } from '@antscorp/antsomi-ui/es/utils/tree';
|
|
3
|
+
import { ItemType, MenuInlineProps } from '../../../types';
|
|
4
|
+
export interface UseKeyboardNavigationReturn {
|
|
5
|
+
handleKeyDown: (e: React.KeyboardEvent) => void;
|
|
6
|
+
}
|
|
7
|
+
export interface UseKeyboardNavigationProps {
|
|
8
|
+
visibleItems: NormalizedNode<ItemType>[];
|
|
9
|
+
focusId: string | null;
|
|
10
|
+
expandedKeys: Set<string>;
|
|
11
|
+
normalizeTreeItems: Map<string, NormalizedNode<ItemType>>;
|
|
12
|
+
setFocusId: (id: string | null) => void;
|
|
13
|
+
handleExpandItems: (items: NormalizedNode<ItemType>[]) => void;
|
|
14
|
+
handleCollapseItems: (items: NormalizedNode<ItemType>[]) => void;
|
|
15
|
+
handleSelectItem: (item: NormalizedNode<ItemType>) => void;
|
|
16
|
+
handleToggleExpandItem: (item: NormalizedNode<ItemType>) => void;
|
|
17
|
+
findNextFocusableItem: (startIndex: number, direction: 'next' | 'prev') => number;
|
|
18
|
+
findFirstFocusableItem: () => number;
|
|
19
|
+
findLastFocusableItem: () => number;
|
|
20
|
+
onClick?: MenuInlineProps['onClick'];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Custom hook to handle keyboard navigation for tree menu
|
|
24
|
+
* Implements ARIA-compliant keyboard interaction patterns
|
|
25
|
+
*/
|
|
26
|
+
export declare const useKeyboardNavigation: (props: UseKeyboardNavigationProps) => UseKeyboardNavigationReturn;
|