@launchpad-ui/menu 0.3.8 → 0.4.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.
- package/dist/index.es.js +249 -189
- package/dist/index.es.js.map +2 -2
- package/dist/index.js +253 -190
- package/dist/index.js.map +2 -2
- package/package.json +7 -7
package/dist/index.js
CHANGED
@@ -17,7 +17,10 @@ var __copyProps = (to, from, except, desc) => {
|
|
17
17
|
}
|
18
18
|
return to;
|
19
19
|
};
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
22
|
+
mod
|
23
|
+
));
|
21
24
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
22
25
|
|
23
26
|
// src/index.ts
|
@@ -41,29 +44,34 @@ var React = __toESM(require("react"));
|
|
41
44
|
var import_clsx = __toESM(require("clsx"));
|
42
45
|
var import_react = require("react");
|
43
46
|
var import_Menu = require("./styles/Menu.css");
|
44
|
-
var
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
47
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
48
|
+
var MenuBase = (0, import_react.forwardRef)(
|
49
|
+
({ children, size, isVirtual, ...props }, ref) => {
|
50
|
+
const classes = (0, import_clsx.default)("Menu", {
|
51
|
+
"Menu--isVirtual": isVirtual,
|
52
|
+
[`MenuSize--${size}`]: size
|
53
|
+
});
|
54
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
55
|
+
...props,
|
56
|
+
role: "menu",
|
57
|
+
className: classes,
|
58
|
+
ref,
|
59
|
+
children
|
60
|
+
});
|
61
|
+
}
|
62
|
+
);
|
56
63
|
MenuBase.displayName = "MenuBase";
|
57
64
|
|
58
65
|
// src/MenuDivider.tsx
|
59
66
|
var import_separator = require("@react-aria/separator");
|
60
67
|
var import_Menu2 = require("./styles/Menu.css");
|
68
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
61
69
|
var MenuDivider = ({ elementType = "div", orientation, innerRef }) => {
|
62
70
|
const { separatorProps } = (0, import_separator.useSeparator)({
|
63
71
|
orientation,
|
64
72
|
elementType
|
65
73
|
});
|
66
|
-
return /* @__PURE__ */
|
74
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
67
75
|
...separatorProps,
|
68
76
|
ref: innerRef,
|
69
77
|
className: "Menu-divider"
|
@@ -78,6 +86,7 @@ var import_focus = require("@react-aria/focus");
|
|
78
86
|
var import_clsx2 = __toESM(require("clsx"));
|
79
87
|
var import_react_router_dom = require("react-router-dom");
|
80
88
|
var import_Menu3 = require("./styles/Menu.css");
|
89
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
81
90
|
var defaultElement = "button";
|
82
91
|
var MenuItem = ({
|
83
92
|
...props
|
@@ -101,28 +110,43 @@ var MenuItem = ({
|
|
101
110
|
...rest
|
102
111
|
} = props;
|
103
112
|
const Component = component || (asChild ? import_react_slot.Slot : defaultElement);
|
104
|
-
const renderedItem = /* @__PURE__ */
|
105
|
-
focusRingClass: "has-focus"
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
113
|
+
const renderedItem = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_focus.FocusRing, {
|
114
|
+
focusRingClass: "has-focus",
|
115
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, {
|
116
|
+
...rest,
|
117
|
+
disabled,
|
118
|
+
"aria-disabled": disabled ? disabled : void 0,
|
119
|
+
className: (0, import_clsx2.default)(
|
120
|
+
"Menu-item",
|
121
|
+
className,
|
122
|
+
{ "is-highlighted": isHighlighted },
|
123
|
+
{ "Menu-item--nested": nested },
|
124
|
+
{ "Menu-item--header": groupHeader }
|
125
|
+
),
|
126
|
+
role,
|
127
|
+
onKeyDown,
|
128
|
+
children: asChild ? children : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, {
|
129
|
+
children: [
|
130
|
+
Icon && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
131
|
+
className: "Menu-item-icon",
|
132
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, {
|
133
|
+
size: import_icons.IconSize.SMALL
|
134
|
+
})
|
135
|
+
}),
|
136
|
+
children
|
137
|
+
]
|
138
|
+
})
|
139
|
+
})
|
140
|
+
});
|
118
141
|
if (tooltip) {
|
119
|
-
return /* @__PURE__ */
|
142
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tooltip.Tooltip, {
|
120
143
|
content: tooltip,
|
121
144
|
rootElementStyle: { display: "block" },
|
122
145
|
allowBoundaryElementOverflow: true,
|
123
146
|
placement: tooltipPlacement ? tooltipPlacement : "bottom",
|
124
|
-
...tooltipOptions || {}
|
125
|
-
|
147
|
+
...tooltipOptions || {},
|
148
|
+
children: renderedItem
|
149
|
+
});
|
126
150
|
}
|
127
151
|
return renderedItem;
|
128
152
|
};
|
@@ -142,40 +166,45 @@ var MenuItemLink = ({
|
|
142
166
|
rel: newTab ? "noopener noreferrer" : void 0,
|
143
167
|
target: newTab ? "_blank" : void 0
|
144
168
|
};
|
145
|
-
return /* @__PURE__ */
|
146
|
-
...finalProps
|
147
|
-
|
169
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuItem, {
|
170
|
+
...finalProps,
|
171
|
+
children
|
172
|
+
});
|
148
173
|
};
|
149
174
|
|
150
175
|
// src/MenuItemList.tsx
|
151
176
|
var import_react2 = require("react");
|
152
177
|
var import_Menu4 = require("./styles/Menu.css");
|
153
|
-
var
|
178
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
179
|
+
var MenuItemList = (0, import_react2.forwardRef)(({ children, ...rest }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
154
180
|
...rest,
|
155
181
|
ref,
|
156
182
|
"data-test-id": "menu-item-list",
|
157
|
-
className: "Menu-item-list"
|
158
|
-
|
183
|
+
className: "Menu-item-list",
|
184
|
+
children
|
185
|
+
}));
|
159
186
|
MenuItemList.displayName = "MenuItemList";
|
160
187
|
|
161
188
|
// src/MenuSearch.tsx
|
162
189
|
var import_form = require("@launchpad-ui/form");
|
163
190
|
var import_react3 = require("react");
|
164
191
|
var import_Menu5 = require("./styles/Menu.css");
|
192
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
165
193
|
var MenuSearch = (0, import_react3.forwardRef)((props, ref) => {
|
166
194
|
const { ariaLabel, placeholder, ...finalProps } = props;
|
167
|
-
return /* @__PURE__ */
|
168
|
-
className: "Menu-search"
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
195
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
196
|
+
className: "Menu-search",
|
197
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_form.TextField, {
|
198
|
+
...finalProps,
|
199
|
+
ref,
|
200
|
+
className: "Menu-search-input",
|
201
|
+
tiny: true,
|
202
|
+
type: "search",
|
203
|
+
autoComplete: "off",
|
204
|
+
placeholder,
|
205
|
+
"aria-label": ariaLabel || "Search"
|
206
|
+
})
|
207
|
+
});
|
179
208
|
});
|
180
209
|
MenuSearch.displayName = "MenuSearch";
|
181
210
|
|
@@ -205,6 +234,7 @@ var chainEventHandlers = (...handlers) => (event) => {
|
|
205
234
|
};
|
206
235
|
|
207
236
|
// src/Menu.tsx
|
237
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
208
238
|
var Menu = (props) => {
|
209
239
|
const {
|
210
240
|
children,
|
@@ -243,65 +273,76 @@ var Menu = (props) => {
|
|
243
273
|
});
|
244
274
|
return { items: elements, searchElement: searchElem };
|
245
275
|
}
|
246
|
-
return childrenProps.reduce(
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
};
|
258
|
-
case MenuItem:
|
259
|
-
case MenuItemLink:
|
260
|
-
return {
|
261
|
-
items: items.concat(child.props.disabled ? (0, import_react4.cloneElement)(child, {
|
262
|
-
onClick: () => void 0,
|
263
|
-
onKeyDown: () => void 0,
|
264
|
-
tabIndex: -1,
|
265
|
-
disabled: true
|
266
|
-
}) : (0, import_react4.cloneElement)(child, {
|
267
|
-
className: (0, import_clsx3.default)(child.props.className, menuItemClassName),
|
268
|
-
item: child.props.item ?? items.length,
|
269
|
-
onClick: chainEventHandlers(child.props.onClick, () => {
|
270
|
-
onSelect?.(child.props.item ?? items.length);
|
271
|
-
}),
|
272
|
-
onKeyDown: (e) => handleKeyboardInteractions(e, {
|
273
|
-
handleDown: handleArrowDown,
|
274
|
-
handleUp: handleArrowUp
|
276
|
+
return childrenProps.reduce(
|
277
|
+
({ items, searchElement }, child) => {
|
278
|
+
switch (child.type) {
|
279
|
+
case MenuSearch:
|
280
|
+
return {
|
281
|
+
items,
|
282
|
+
searchElement: (0, import_react4.cloneElement)(child, {
|
283
|
+
onKeyDown: (e) => handleKeyboardInteractions(e, {
|
284
|
+
handleDown: handleArrowDown,
|
285
|
+
handleUp: handleArrowUp
|
286
|
+
})
|
275
287
|
})
|
276
|
-
}
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
288
|
+
};
|
289
|
+
case MenuItem:
|
290
|
+
case MenuItemLink:
|
291
|
+
return {
|
292
|
+
items: items.concat(
|
293
|
+
child.props.disabled ? (0, import_react4.cloneElement)(child, {
|
294
|
+
onClick: () => void 0,
|
295
|
+
onKeyDown: () => void 0,
|
296
|
+
tabIndex: -1,
|
297
|
+
disabled: true
|
298
|
+
}) : (0, import_react4.cloneElement)(child, {
|
299
|
+
className: (0, import_clsx3.default)(child.props.className, menuItemClassName),
|
300
|
+
item: child.props.item ?? items.length,
|
301
|
+
onClick: chainEventHandlers(child.props.onClick, () => {
|
302
|
+
onSelect?.(child.props.item ?? items.length);
|
303
|
+
}),
|
304
|
+
onKeyDown: (e) => handleKeyboardInteractions(e, {
|
305
|
+
handleDown: handleArrowDown,
|
306
|
+
handleUp: handleArrowUp
|
307
|
+
})
|
308
|
+
})
|
309
|
+
),
|
310
|
+
searchElement
|
311
|
+
};
|
312
|
+
case MenuDivider:
|
313
|
+
return { items: items.concat(child), searchElement };
|
314
|
+
default:
|
315
|
+
return { items, searchElement };
|
316
|
+
}
|
317
|
+
},
|
318
|
+
{ items: [], searchElement: null }
|
319
|
+
);
|
285
320
|
}, [children, enableVirtualization, menuItemClassName, handleArrowDown, handleArrowUp, onSelect]);
|
286
321
|
if (enableVirtualization) {
|
287
|
-
return /* @__PURE__ */
|
322
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuBase, {
|
288
323
|
isVirtual: true,
|
289
|
-
size
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
324
|
+
size,
|
325
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ItemVirtualizer, {
|
326
|
+
items: import_react4.Children.toArray(reduceItems.items),
|
327
|
+
searchElement: reduceItems.searchElement,
|
328
|
+
overscan,
|
329
|
+
menuItemClassName,
|
330
|
+
onSelect,
|
331
|
+
itemHeight,
|
332
|
+
focusManager
|
333
|
+
})
|
334
|
+
});
|
299
335
|
}
|
300
|
-
return /* @__PURE__ */
|
301
|
-
size
|
302
|
-
|
303
|
-
|
304
|
-
|
336
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(MenuBase, {
|
337
|
+
size,
|
338
|
+
children: [
|
339
|
+
reduceItems.searchElement,
|
340
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuItemList, {
|
341
|
+
role: "presentation",
|
342
|
+
children: reduceItems.items
|
343
|
+
})
|
344
|
+
]
|
345
|
+
});
|
305
346
|
};
|
306
347
|
var ItemVirtualizer = (props) => {
|
307
348
|
const {
|
@@ -330,63 +371,72 @@ var ItemVirtualizer = (props) => {
|
|
330
371
|
rowVirtualizer.scrollToIndex(0);
|
331
372
|
searchRef.current?.focus?.();
|
332
373
|
}, [rowVirtualizer]);
|
333
|
-
const focusMenuItem = (0, import_react4.useCallback)(
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
if (hasSearch) {
|
345
|
-
focusSearchBar();
|
346
|
-
} else {
|
347
|
-
focusMenuItem(direction === "next" ? 0 : lastVirtualItemIndex);
|
374
|
+
const focusMenuItem = (0, import_react4.useCallback)(
|
375
|
+
(index) => {
|
376
|
+
rowVirtualizer.scrollToIndex(index);
|
377
|
+
setNextFocusValue(index);
|
378
|
+
},
|
379
|
+
[rowVirtualizer]
|
380
|
+
);
|
381
|
+
const handleKeyboardFocusInteraction = (0, import_react4.useCallback)(
|
382
|
+
(direction) => {
|
383
|
+
if (focusedItemIndex.current === null || focusedItemIndex.current === void 0) {
|
384
|
+
return;
|
348
385
|
}
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
386
|
+
const nextIndex = direction === "next" ? focusedItemIndex.current + 1 : focusedItemIndex.current - 1;
|
387
|
+
const shouldWrap = direction === "next" && focusedItemIndex.current === lastVirtualItemIndex || direction === "previous" && focusedItemIndex.current === 0;
|
388
|
+
if (shouldWrap) {
|
389
|
+
if (hasSearch) {
|
390
|
+
focusSearchBar();
|
391
|
+
} else {
|
392
|
+
focusMenuItem(direction === "next" ? 0 : lastVirtualItemIndex);
|
393
|
+
}
|
394
|
+
return;
|
395
|
+
}
|
396
|
+
switch (direction) {
|
397
|
+
case "next":
|
398
|
+
rowVirtualizer.scrollToIndex(nextIndex);
|
399
|
+
focusManager.focusNext();
|
400
|
+
break;
|
401
|
+
case "previous":
|
402
|
+
rowVirtualizer.scrollToIndex(nextIndex);
|
403
|
+
focusManager.focusPrevious();
|
404
|
+
break;
|
405
|
+
default:
|
406
|
+
break;
|
407
|
+
}
|
408
|
+
},
|
409
|
+
[focusManager, focusMenuItem, focusSearchBar, hasSearch, lastVirtualItemIndex, rowVirtualizer]
|
410
|
+
);
|
411
|
+
const getItemProps = (0, import_react4.useCallback)(
|
412
|
+
(itemElem, index) => {
|
413
|
+
const childProps = itemElem.props;
|
414
|
+
switch (itemElem.type) {
|
415
|
+
case MenuItem:
|
416
|
+
case MenuItemLink:
|
417
|
+
return {
|
418
|
+
className: (0, import_clsx3.default)(childProps.className, menuItemClassName),
|
419
|
+
onKeyDown: childProps.disabled ? () => void 0 : (e) => handleKeyboardFocusKeydown(e, {
|
420
|
+
handleFocusBackward: handleKeyboardFocusInteraction,
|
421
|
+
handleFocusForward: handleKeyboardFocusInteraction
|
422
|
+
}),
|
423
|
+
onFocus: chainEventHandlers(childProps.onFocus, () => {
|
424
|
+
focusedItemIndex.current = index;
|
425
|
+
}),
|
426
|
+
id: createItemId(index, menuId.current),
|
427
|
+
onBlur: chainEventHandlers(childProps.onBlur, () => {
|
428
|
+
focusedItemIndex.current = null;
|
429
|
+
}),
|
430
|
+
onClick: childProps.disabled ? () => void 0 : chainEventHandlers(childProps.onClick, () => {
|
431
|
+
onSelect?.(childProps.item);
|
432
|
+
})
|
433
|
+
};
|
434
|
+
default:
|
435
|
+
return {};
|
436
|
+
}
|
437
|
+
},
|
438
|
+
[handleKeyboardFocusInteraction, menuItemClassName, onSelect]
|
439
|
+
);
|
390
440
|
(0, import_react4.useEffect)(() => {
|
391
441
|
if (nextFocusValue !== null) {
|
392
442
|
requestAnimationFrame(() => {
|
@@ -408,38 +458,51 @@ var ItemVirtualizer = (props) => {
|
|
408
458
|
}
|
409
459
|
}
|
410
460
|
};
|
411
|
-
const renderSearch = (0, import_react4.useMemo)(
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
ref: elem.type !== MenuItem || elem.type !== MenuItemLink ? virtualRow.measureRef : void 0,
|
426
|
-
role: "presentation",
|
427
|
-
className: (0, import_clsx3.default)("VirtualMenu-item"),
|
428
|
-
style: {
|
429
|
-
transform: `translateY(${virtualRow.start}px)`
|
461
|
+
const renderSearch = (0, import_react4.useMemo)(
|
462
|
+
() => searchElement ? (0, import_react4.cloneElement)(searchElement, {
|
463
|
+
onKeyDown: (e) => handleKeyboardFocusKeydown(e, {
|
464
|
+
handleFocusBackward: () => focusMenuItem(lastVirtualItemIndex),
|
465
|
+
handleFocusForward: () => focusMenuItem(0)
|
466
|
+
}),
|
467
|
+
ref: searchRef
|
468
|
+
}) : null,
|
469
|
+
[searchElement, lastVirtualItemIndex, focusMenuItem]
|
470
|
+
);
|
471
|
+
const renderItems = (0, import_react4.useMemo)(
|
472
|
+
() => rowVirtualizer.virtualItems.map((virtualRow) => {
|
473
|
+
if (!items) {
|
474
|
+
return null;
|
430
475
|
}
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
}
|
442
|
-
|
476
|
+
const elem = items[virtualRow.index];
|
477
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
478
|
+
ref: elem.type !== MenuItem || elem.type !== MenuItemLink ? virtualRow.measureRef : void 0,
|
479
|
+
role: "presentation",
|
480
|
+
className: (0, import_clsx3.default)("VirtualMenu-item"),
|
481
|
+
style: {
|
482
|
+
transform: `translateY(${virtualRow.start}px)`
|
483
|
+
},
|
484
|
+
children: (0, import_react4.cloneElement)(elem, getItemProps(elem, virtualRow.index))
|
485
|
+
}, virtualRow.index);
|
486
|
+
}),
|
487
|
+
[rowVirtualizer.virtualItems, items, getItemProps]
|
488
|
+
);
|
489
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, {
|
490
|
+
children: [
|
491
|
+
renderSearch,
|
492
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuItemList, {
|
493
|
+
ref: parentRef,
|
494
|
+
role: "presentation",
|
495
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
496
|
+
role: "presentation",
|
497
|
+
className: "VirtualMenu-item-list",
|
498
|
+
style: {
|
499
|
+
height: `${rowVirtualizer.totalSize}px`
|
500
|
+
},
|
501
|
+
children: renderItems
|
502
|
+
})
|
503
|
+
})
|
504
|
+
]
|
505
|
+
});
|
443
506
|
};
|
444
507
|
|
445
508
|
// src/types.ts
|