@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 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
- ({ children, size, isVirtual, ...props }, ref) => {
34
- const classes = cx(
35
- styles.Menu,
36
- isVirtual && styles["Menu--isVirtual"],
37
- size && styles[`MenuSize--${size}`]
38
- );
39
- return /* @__PURE__ */ jsx("div", { ...props, role: "menu", className: classes, ref, children });
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 { separatorProps } = useSeparator({
54
+ const {
55
+ separatorProps
56
+ } = useSeparator({
50
57
  orientation,
51
58
  elementType
52
59
  });
53
- return /* @__PURE__ */ jsx(
54
- "div",
55
- {
56
- ...separatorProps,
57
- "data-test-id": testId,
58
- ref: innerRef,
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, { size: "small" });
89
- const renderedItem = /* @__PURE__ */ jsx(FocusRing, { focusRingClass: styles["has-focus"], children: /* @__PURE__ */ jsx(
90
- Component,
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, { children: [
106
- icon && /* @__PURE__ */ jsx("span", { className: styles["Menu-item-icon"], children: renderIcon }),
107
- children
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
- Tooltip,
114
- {
115
- content: tooltip,
116
- rootElementStyle: { display: "block" },
117
- allowBoundaryElementOverflow: true,
118
- placement: tooltipPlacement ? tooltipPlacement : "bottom",
119
- ...tooltipOptions || {},
120
- children: renderedItem
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(({ children, ...rest }, ref) => /* @__PURE__ */ jsx("div", { ...rest, ref, "data-test-id": "menu-item-list", className: styles["Menu-item-list"], children }));
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", { className: styles["Menu-search"], children: /* @__PURE__ */ jsx(
137
- TextField,
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({ wrap: true });
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({ wrap: true });
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 { items: elements, searchElement: searchElem };
218
+ return {
219
+ items: elements,
220
+ searchElement: searchElem
221
+ };
205
222
  }
206
- return childrenProps.reduce(
207
- ({ items, searchElement }, child) => {
208
- switch (child.type) {
209
- case MenuSearch:
210
- return {
211
- items,
212
- searchElement: /* @__PURE__ */ cloneElement(child, {
213
- onKeyDown: (e) => handleKeyboardInteractions(e, {
214
- handleDown: handleArrowDown,
215
- handleUp: handleArrowUp
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
- case MenuItem:
220
- return {
221
- items: items.concat(
222
- child.props.disabled ? /* @__PURE__ */ cloneElement(child, {
223
- className: cx(child.props.className, menuItemClassName),
224
- onClick: () => void 0,
225
- onKeyDown: () => void 0,
226
- tabIndex: -1,
227
- disabled: true
228
- }) : /* @__PURE__ */ cloneElement(child, {
229
- className: cx(child.props.className, menuItemClassName),
230
- item: child.props.item ?? items.length,
231
- // set focus on the first menu item if there is no search input, and set in the tab order
232
- onClick: chainEventHandlers(child.props.onClick, () => {
233
- onSelect == null ? void 0 : onSelect(child.props.item ?? items.length);
234
- }),
235
- onKeyDown: (e) => handleKeyboardInteractions(e, {
236
- handleDown: handleArrowDown,
237
- handleUp: handleArrowUp
238
- })
239
- })
240
- ),
241
- searchElement
242
- };
243
- case MenuDivider:
244
- return { items: items.concat(child), searchElement };
245
- default:
246
- return { items, searchElement };
247
- }
248
- },
249
- { items: [], searchElement: null }
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, { "data-test-id": testId, isVirtual: true, size, children: /* @__PURE__ */ jsx(
254
- ItemVirtualizer,
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, { "data-test-id": testId, size, children: [
267
- reduceItems.searchElement,
268
- /* @__PURE__ */ jsx(MenuItemList, { role: "presentation", children: reduceItems.items })
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
- rowVirtualizer.scrollToIndex(index);
302
- setNextFocusValue(index);
303
- },
304
- [rowVirtualizer]
305
- );
306
- const handleKeyboardFocusInteraction = useCallback(
307
- (direction) => {
308
- if (focusedItemIndex.current === null || focusedItemIndex.current === void 0) {
309
- return;
310
- }
311
- const nextIndex = direction === "next" ? focusedItemIndex.current + 1 : focusedItemIndex.current - 1;
312
- const shouldWrap = direction === "next" && focusedItemIndex.current === lastVirtualItemIndex || direction === "previous" && focusedItemIndex.current === 0;
313
- if (shouldWrap) {
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
- [handleKeyboardFocusInteraction, menuItemClassName, onSelect]
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
- () => searchElement ? /* @__PURE__ */ cloneElement(searchElement, {
387
- onKeyDown: (e) => handleKeyboardFocusKeydown(e, {
388
- handleFocusBackward: () => focusMenuItem(lastVirtualItemIndex),
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
- [rowVirtualizer.virtualItems, items, getItemProps]
416
- );
417
- return /* @__PURE__ */ jsxs(Fragment, { children: [
418
- renderSearch,
419
- /* @__PURE__ */ jsx(MenuItemList, { ref: parentRef, role: "presentation", children: /* @__PURE__ */ jsx(
420
- "div",
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,