@launchpad-ui/menu 0.12.7 → 0.12.8
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/dist/index.es.js +223 -212
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +223 -212
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.es.js
CHANGED
@@ -29,16 +29,21 @@ const styles = {
|
|
29
29
|
"VirtualMenu-item-list": "_VirtualMenu-item-list_dlpdi_142",
|
30
30
|
"VirtualMenu-item": "_VirtualMenu-item_dlpdi_142"
|
31
31
|
};
|
32
|
-
const MenuBase = /* @__PURE__ */ forwardRef(
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
32
|
+
const MenuBase = /* @__PURE__ */ forwardRef(({
|
33
|
+
children,
|
34
|
+
size,
|
35
|
+
isVirtual,
|
36
|
+
...props
|
37
|
+
}, ref) => {
|
38
|
+
const classes = cx(styles.Menu, isVirtual && styles["Menu--isVirtual"], size && styles[`MenuSize--${size}`]);
|
39
|
+
return /* @__PURE__ */ jsx("div", {
|
40
|
+
...props,
|
41
|
+
role: "menu",
|
42
|
+
className: classes,
|
43
|
+
ref,
|
44
|
+
children
|
45
|
+
});
|
46
|
+
});
|
42
47
|
MenuBase.displayName = "MenuBase";
|
43
48
|
const MenuDivider = ({
|
44
49
|
elementType = "div",
|
@@ -46,19 +51,18 @@ const MenuDivider = ({
|
|
46
51
|
innerRef,
|
47
52
|
"data-test-id": testId = "menu-divider"
|
48
53
|
}) => {
|
49
|
-
const {
|
54
|
+
const {
|
55
|
+
separatorProps
|
56
|
+
} = useSeparator({
|
50
57
|
orientation,
|
51
58
|
elementType
|
52
59
|
});
|
53
|
-
return /* @__PURE__ */ jsx(
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
className: styles["Menu-divider"]
|
60
|
-
}
|
61
|
-
);
|
60
|
+
return /* @__PURE__ */ jsx("div", {
|
61
|
+
...separatorProps,
|
62
|
+
"data-test-id": testId,
|
63
|
+
ref: innerRef,
|
64
|
+
className: styles["Menu-divider"]
|
65
|
+
});
|
62
66
|
};
|
63
67
|
const defaultElement = "button";
|
64
68
|
const MenuItem = ({
|
@@ -85,45 +89,51 @@ const MenuItem = ({
|
|
85
89
|
...rest
|
86
90
|
} = props;
|
87
91
|
const Component = component || (asChild ? Slot : defaultElement);
|
88
|
-
const renderIcon = icon && /* @__PURE__ */ cloneElement(icon, {
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
+
const renderIcon = icon && /* @__PURE__ */ cloneElement(icon, {
|
93
|
+
size: "small"
|
94
|
+
});
|
95
|
+
const renderedItem = /* @__PURE__ */ jsx(FocusRing, {
|
96
|
+
focusRingClass: styles["has-focus"],
|
97
|
+
children: /* @__PURE__ */ jsx(Component, {
|
92
98
|
...rest,
|
93
99
|
disabled,
|
94
100
|
"aria-disabled": disabled ? disabled : void 0,
|
95
|
-
className: cx(
|
96
|
-
styles["Menu-item"],
|
97
|
-
className,
|
98
|
-
isHighlighted && styles["is-highlighted"],
|
99
|
-
nested && styles["Menu-item--nested"],
|
100
|
-
groupHeader && styles["Menu-item--header"]
|
101
|
-
),
|
101
|
+
className: cx(styles["Menu-item"], className, isHighlighted && styles["is-highlighted"], nested && styles["Menu-item--nested"], groupHeader && styles["Menu-item--header"]),
|
102
102
|
"data-test-id": testId,
|
103
103
|
role,
|
104
104
|
onKeyDown,
|
105
|
-
children: asChild ? children : /* @__PURE__ */ jsxs(Fragment, {
|
106
|
-
icon && /* @__PURE__ */ jsx("span", {
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
105
|
+
children: asChild ? children : /* @__PURE__ */ jsxs(Fragment, {
|
106
|
+
children: [icon && /* @__PURE__ */ jsx("span", {
|
107
|
+
className: styles["Menu-item-icon"],
|
108
|
+
children: renderIcon
|
109
|
+
}), children]
|
110
|
+
})
|
111
|
+
})
|
112
|
+
});
|
111
113
|
if (tooltip) {
|
112
|
-
return /* @__PURE__ */ jsx(
|
113
|
-
|
114
|
-
{
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
);
|
114
|
+
return /* @__PURE__ */ jsx(Tooltip, {
|
115
|
+
content: tooltip,
|
116
|
+
rootElementStyle: {
|
117
|
+
display: "block"
|
118
|
+
},
|
119
|
+
allowBoundaryElementOverflow: true,
|
120
|
+
placement: tooltipPlacement ? tooltipPlacement : "bottom",
|
121
|
+
...tooltipOptions || {},
|
122
|
+
children: renderedItem
|
123
|
+
});
|
123
124
|
}
|
124
125
|
return renderedItem;
|
125
126
|
};
|
126
|
-
const MenuItemList = /* @__PURE__ */ forwardRef(({
|
127
|
+
const MenuItemList = /* @__PURE__ */ forwardRef(({
|
128
|
+
children,
|
129
|
+
...rest
|
130
|
+
}, ref) => /* @__PURE__ */ jsx("div", {
|
131
|
+
...rest,
|
132
|
+
ref,
|
133
|
+
"data-test-id": "menu-item-list",
|
134
|
+
className: styles["Menu-item-list"],
|
135
|
+
children
|
136
|
+
}));
|
127
137
|
MenuItemList.displayName = "MenuItemList";
|
128
138
|
const MenuSearch = /* @__PURE__ */ forwardRef((props, ref) => {
|
129
139
|
const {
|
@@ -133,9 +143,9 @@ const MenuSearch = /* @__PURE__ */ forwardRef((props, ref) => {
|
|
133
143
|
"data-test-id": testId = "menu-search",
|
134
144
|
...finalProps
|
135
145
|
} = props;
|
136
|
-
return /* @__PURE__ */ jsx("div", {
|
137
|
-
|
138
|
-
{
|
146
|
+
return /* @__PURE__ */ jsx("div", {
|
147
|
+
className: styles["Menu-search"],
|
148
|
+
children: /* @__PURE__ */ jsx(TextField, {
|
139
149
|
...finalProps,
|
140
150
|
ref,
|
141
151
|
className: styles["Menu-search-input"],
|
@@ -146,8 +156,8 @@ const MenuSearch = /* @__PURE__ */ forwardRef((props, ref) => {
|
|
146
156
|
autoComplete: "off",
|
147
157
|
placeholder,
|
148
158
|
"aria-label": ariaLabel || "Search"
|
149
|
-
}
|
150
|
-
|
159
|
+
})
|
160
|
+
});
|
151
161
|
});
|
152
162
|
MenuSearch.displayName = "MenuSearch";
|
153
163
|
const createItemId = (index, id) => `${id}-item-${index}`;
|
@@ -180,10 +190,14 @@ const Menu = (props) => {
|
|
180
190
|
} = props;
|
181
191
|
const focusManager = useFocusManager();
|
182
192
|
const handleArrowDown = useCallback(() => {
|
183
|
-
focusManager == null ? void 0 : focusManager.focusNext({
|
193
|
+
focusManager == null ? void 0 : focusManager.focusNext({
|
194
|
+
wrap: true
|
195
|
+
});
|
184
196
|
}, [focusManager]);
|
185
197
|
const handleArrowUp = useCallback(() => {
|
186
|
-
focusManager == null ? void 0 : focusManager.focusPrevious({
|
198
|
+
focusManager == null ? void 0 : focusManager.focusPrevious({
|
199
|
+
wrap: true
|
200
|
+
});
|
187
201
|
}, [focusManager]);
|
188
202
|
const reduceItems = useMemo(() => {
|
189
203
|
const childrenProps = Children.toArray(children);
|
@@ -201,58 +215,70 @@ const Menu = (props) => {
|
|
201
215
|
break;
|
202
216
|
}
|
203
217
|
});
|
204
|
-
return {
|
218
|
+
return {
|
219
|
+
items: elements,
|
220
|
+
searchElement: searchElem
|
221
|
+
};
|
205
222
|
}
|
206
|
-
return childrenProps.reduce(
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
223
|
+
return childrenProps.reduce(({
|
224
|
+
items,
|
225
|
+
searchElement
|
226
|
+
}, child) => {
|
227
|
+
switch (child.type) {
|
228
|
+
case MenuSearch:
|
229
|
+
return {
|
230
|
+
items,
|
231
|
+
searchElement: /* @__PURE__ */ cloneElement(child, {
|
232
|
+
onKeyDown: (e) => handleKeyboardInteractions(e, {
|
233
|
+
handleDown: handleArrowDown,
|
234
|
+
handleUp: handleArrowUp
|
217
235
|
})
|
218
|
-
}
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
236
|
+
})
|
237
|
+
};
|
238
|
+
case MenuItem:
|
239
|
+
return {
|
240
|
+
items: items.concat(child.props.disabled ? /* @__PURE__ */ cloneElement(child, {
|
241
|
+
className: cx(child.props.className, menuItemClassName),
|
242
|
+
onClick: () => void 0,
|
243
|
+
onKeyDown: () => void 0,
|
244
|
+
tabIndex: -1,
|
245
|
+
disabled: true
|
246
|
+
}) : /* @__PURE__ */ cloneElement(child, {
|
247
|
+
className: cx(child.props.className, menuItemClassName),
|
248
|
+
item: child.props.item ?? items.length,
|
249
|
+
// set focus on the first menu item if there is no search input, and set in the tab order
|
250
|
+
onClick: chainEventHandlers(child.props.onClick, () => {
|
251
|
+
onSelect == null ? void 0 : onSelect(child.props.item ?? items.length);
|
252
|
+
}),
|
253
|
+
onKeyDown: (e) => handleKeyboardInteractions(e, {
|
254
|
+
handleDown: handleArrowDown,
|
255
|
+
handleUp: handleArrowUp
|
256
|
+
})
|
257
|
+
})),
|
258
|
+
searchElement
|
259
|
+
};
|
260
|
+
case MenuDivider:
|
261
|
+
return {
|
262
|
+
items: items.concat(child),
|
263
|
+
searchElement
|
264
|
+
};
|
265
|
+
default:
|
266
|
+
return {
|
267
|
+
items,
|
268
|
+
searchElement
|
269
|
+
};
|
270
|
+
}
|
271
|
+
}, {
|
272
|
+
items: [],
|
273
|
+
searchElement: null
|
274
|
+
});
|
251
275
|
}, [children, enableVirtualization, menuItemClassName, handleArrowDown, handleArrowUp, onSelect]);
|
252
276
|
if (enableVirtualization) {
|
253
|
-
return /* @__PURE__ */ jsx(MenuBase, {
|
254
|
-
|
255
|
-
|
277
|
+
return /* @__PURE__ */ jsx(MenuBase, {
|
278
|
+
"data-test-id": testId,
|
279
|
+
isVirtual: true,
|
280
|
+
size,
|
281
|
+
children: /* @__PURE__ */ jsx(ItemVirtualizer, {
|
256
282
|
items: Children.toArray(reduceItems.items),
|
257
283
|
searchElement: reduceItems.searchElement,
|
258
284
|
overscan,
|
@@ -260,13 +286,17 @@ const Menu = (props) => {
|
|
260
286
|
onSelect,
|
261
287
|
itemHeight,
|
262
288
|
focusManager
|
263
|
-
}
|
264
|
-
|
289
|
+
})
|
290
|
+
});
|
265
291
|
}
|
266
|
-
return /* @__PURE__ */ jsxs(MenuBase, {
|
267
|
-
|
268
|
-
|
269
|
-
|
292
|
+
return /* @__PURE__ */ jsxs(MenuBase, {
|
293
|
+
"data-test-id": testId,
|
294
|
+
size,
|
295
|
+
children: [reduceItems.searchElement, /* @__PURE__ */ jsx(MenuItemList, {
|
296
|
+
role: "presentation",
|
297
|
+
children: reduceItems.items
|
298
|
+
})]
|
299
|
+
});
|
270
300
|
};
|
271
301
|
const ItemVirtualizer = (props) => {
|
272
302
|
const {
|
@@ -296,70 +326,61 @@ const ItemVirtualizer = (props) => {
|
|
296
326
|
rowVirtualizer.scrollToIndex(0);
|
297
327
|
(_b = (_a = searchRef.current) == null ? void 0 : _a.focus) == null ? void 0 : _b.call(_a);
|
298
328
|
}, [rowVirtualizer]);
|
299
|
-
const focusMenuItem = useCallback(
|
300
|
-
(index)
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
if (hasSearch) {
|
315
|
-
focusSearchBar();
|
316
|
-
} else {
|
317
|
-
focusMenuItem(direction === "next" ? 0 : lastVirtualItemIndex);
|
318
|
-
}
|
319
|
-
return;
|
320
|
-
}
|
321
|
-
switch (direction) {
|
322
|
-
case "next":
|
323
|
-
rowVirtualizer.scrollToIndex(nextIndex);
|
324
|
-
focusManager == null ? void 0 : focusManager.focusNext();
|
325
|
-
break;
|
326
|
-
case "previous":
|
327
|
-
rowVirtualizer.scrollToIndex(nextIndex);
|
328
|
-
focusManager == null ? void 0 : focusManager.focusPrevious();
|
329
|
-
break;
|
330
|
-
}
|
331
|
-
},
|
332
|
-
[focusManager, focusMenuItem, focusSearchBar, hasSearch, lastVirtualItemIndex, rowVirtualizer]
|
333
|
-
);
|
334
|
-
const getItemProps = useCallback(
|
335
|
-
(itemElem, index) => {
|
336
|
-
const childProps = itemElem.props;
|
337
|
-
switch (itemElem.type) {
|
338
|
-
case MenuItem:
|
339
|
-
return {
|
340
|
-
className: cx(childProps.className, menuItemClassName),
|
341
|
-
// set focus on the first menu item if there is no search input, and set in the tab order
|
342
|
-
onKeyDown: childProps.disabled ? () => void 0 : (e) => handleKeyboardFocusKeydown(e, {
|
343
|
-
handleFocusBackward: handleKeyboardFocusInteraction,
|
344
|
-
handleFocusForward: handleKeyboardFocusInteraction
|
345
|
-
}),
|
346
|
-
onFocus: chainEventHandlers(childProps.onFocus, () => {
|
347
|
-
focusedItemIndex.current = index;
|
348
|
-
}),
|
349
|
-
id: createItemId(index, menuId.current),
|
350
|
-
onBlur: chainEventHandlers(childProps.onBlur, () => {
|
351
|
-
focusedItemIndex.current = null;
|
352
|
-
}),
|
353
|
-
onClick: childProps.disabled ? () => void 0 : chainEventHandlers(childProps.onClick, () => {
|
354
|
-
onSelect == null ? void 0 : onSelect(childProps.item);
|
355
|
-
})
|
356
|
-
};
|
357
|
-
default:
|
358
|
-
return {};
|
329
|
+
const focusMenuItem = useCallback((index) => {
|
330
|
+
rowVirtualizer.scrollToIndex(index);
|
331
|
+
setNextFocusValue(index);
|
332
|
+
}, [rowVirtualizer]);
|
333
|
+
const handleKeyboardFocusInteraction = useCallback((direction) => {
|
334
|
+
if (focusedItemIndex.current === null || focusedItemIndex.current === void 0) {
|
335
|
+
return;
|
336
|
+
}
|
337
|
+
const nextIndex = direction === "next" ? focusedItemIndex.current + 1 : focusedItemIndex.current - 1;
|
338
|
+
const shouldWrap = direction === "next" && focusedItemIndex.current === lastVirtualItemIndex || direction === "previous" && focusedItemIndex.current === 0;
|
339
|
+
if (shouldWrap) {
|
340
|
+
if (hasSearch) {
|
341
|
+
focusSearchBar();
|
342
|
+
} else {
|
343
|
+
focusMenuItem(direction === "next" ? 0 : lastVirtualItemIndex);
|
359
344
|
}
|
360
|
-
|
361
|
-
|
362
|
-
|
345
|
+
return;
|
346
|
+
}
|
347
|
+
switch (direction) {
|
348
|
+
case "next":
|
349
|
+
rowVirtualizer.scrollToIndex(nextIndex);
|
350
|
+
focusManager == null ? void 0 : focusManager.focusNext();
|
351
|
+
break;
|
352
|
+
case "previous":
|
353
|
+
rowVirtualizer.scrollToIndex(nextIndex);
|
354
|
+
focusManager == null ? void 0 : focusManager.focusPrevious();
|
355
|
+
break;
|
356
|
+
}
|
357
|
+
}, [focusManager, focusMenuItem, focusSearchBar, hasSearch, lastVirtualItemIndex, rowVirtualizer]);
|
358
|
+
const getItemProps = useCallback((itemElem, index) => {
|
359
|
+
const childProps = itemElem.props;
|
360
|
+
switch (itemElem.type) {
|
361
|
+
case MenuItem:
|
362
|
+
return {
|
363
|
+
className: cx(childProps.className, menuItemClassName),
|
364
|
+
// set focus on the first menu item if there is no search input, and set in the tab order
|
365
|
+
onKeyDown: childProps.disabled ? () => void 0 : (e) => handleKeyboardFocusKeydown(e, {
|
366
|
+
handleFocusBackward: handleKeyboardFocusInteraction,
|
367
|
+
handleFocusForward: handleKeyboardFocusInteraction
|
368
|
+
}),
|
369
|
+
onFocus: chainEventHandlers(childProps.onFocus, () => {
|
370
|
+
focusedItemIndex.current = index;
|
371
|
+
}),
|
372
|
+
id: createItemId(index, menuId.current),
|
373
|
+
onBlur: chainEventHandlers(childProps.onBlur, () => {
|
374
|
+
focusedItemIndex.current = null;
|
375
|
+
}),
|
376
|
+
onClick: childProps.disabled ? () => void 0 : chainEventHandlers(childProps.onClick, () => {
|
377
|
+
onSelect == null ? void 0 : onSelect(childProps.item);
|
378
|
+
})
|
379
|
+
};
|
380
|
+
default:
|
381
|
+
return {};
|
382
|
+
}
|
383
|
+
}, [handleKeyboardFocusInteraction, menuItemClassName, onSelect]);
|
363
384
|
useEffect(() => {
|
364
385
|
if (nextFocusValue !== null) {
|
365
386
|
requestAnimationFrame(() => {
|
@@ -382,52 +403,42 @@ const ItemVirtualizer = (props) => {
|
|
382
403
|
}
|
383
404
|
}
|
384
405
|
};
|
385
|
-
const renderSearch = useMemo(
|
386
|
-
() =>
|
387
|
-
|
388
|
-
|
389
|
-
handleFocusForward: () => focusMenuItem(0)
|
390
|
-
}),
|
391
|
-
ref: searchRef
|
392
|
-
}) : null,
|
393
|
-
[searchElement, lastVirtualItemIndex, focusMenuItem]
|
394
|
-
);
|
395
|
-
const renderItems = useMemo(
|
396
|
-
() => rowVirtualizer.virtualItems.map((virtualRow) => {
|
397
|
-
if (!items) {
|
398
|
-
return null;
|
399
|
-
}
|
400
|
-
const elem = items[virtualRow.index];
|
401
|
-
return /* @__PURE__ */ jsx(
|
402
|
-
"div",
|
403
|
-
{
|
404
|
-
ref: virtualRow.measureRef,
|
405
|
-
role: "presentation",
|
406
|
-
className: styles["VirtualMenu-item"],
|
407
|
-
style: {
|
408
|
-
transform: `translateY(${virtualRow.start}px)`
|
409
|
-
},
|
410
|
-
children: /* @__PURE__ */ cloneElement(elem, getItemProps(elem, virtualRow.index))
|
411
|
-
},
|
412
|
-
virtualRow.index
|
413
|
-
);
|
406
|
+
const renderSearch = useMemo(() => searchElement ? /* @__PURE__ */ cloneElement(searchElement, {
|
407
|
+
onKeyDown: (e) => handleKeyboardFocusKeydown(e, {
|
408
|
+
handleFocusBackward: () => focusMenuItem(lastVirtualItemIndex),
|
409
|
+
handleFocusForward: () => focusMenuItem(0)
|
414
410
|
}),
|
415
|
-
|
416
|
-
);
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
411
|
+
ref: searchRef
|
412
|
+
}) : null, [searchElement, lastVirtualItemIndex, focusMenuItem]);
|
413
|
+
const renderItems = useMemo(() => rowVirtualizer.virtualItems.map((virtualRow) => {
|
414
|
+
if (!items) {
|
415
|
+
return null;
|
416
|
+
}
|
417
|
+
const elem = items[virtualRow.index];
|
418
|
+
return /* @__PURE__ */ jsx("div", {
|
419
|
+
ref: virtualRow.measureRef,
|
420
|
+
role: "presentation",
|
421
|
+
className: styles["VirtualMenu-item"],
|
422
|
+
style: {
|
423
|
+
transform: `translateY(${virtualRow.start}px)`
|
424
|
+
},
|
425
|
+
children: /* @__PURE__ */ cloneElement(elem, getItemProps(elem, virtualRow.index))
|
426
|
+
}, virtualRow.index);
|
427
|
+
}), [rowVirtualizer.virtualItems, items, getItemProps]);
|
428
|
+
return /* @__PURE__ */ jsxs(Fragment, {
|
429
|
+
children: [renderSearch, /* @__PURE__ */ jsx(MenuItemList, {
|
430
|
+
ref: parentRef,
|
431
|
+
role: "presentation",
|
432
|
+
children: /* @__PURE__ */ jsx("div", {
|
422
433
|
role: "presentation",
|
423
434
|
className: styles["VirtualMenu-item-list"],
|
424
435
|
style: {
|
425
436
|
height: `${rowVirtualizer.totalSize}px`
|
426
437
|
},
|
427
438
|
children: renderItems
|
428
|
-
}
|
429
|
-
|
430
|
-
|
439
|
+
})
|
440
|
+
})]
|
441
|
+
});
|
431
442
|
};
|
432
443
|
export {
|
433
444
|
Menu,
|