@launchpad-ui/menu 0.3.4 → 0.3.5
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/Menu.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.js +6 -8
- package/dist/index.es.js.map +2 -2
- package/dist/index.js +6 -8
- package/dist/index.js.map +2 -2
- package/dist/utils.d.ts +2 -3
- package/dist/utils.d.ts.map +1 -1
- package/package.json +3 -5
package/dist/Menu.d.ts.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"Menu.d.ts","sourceRoot":"","sources":["../src/Menu.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAiB,YAAY,EAAE,MAAM,OAAO,CAAC;
|
1
|
+
{"version":3,"file":"Menu.d.ts","sourceRoot":"","sources":["../src/Menu.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAiB,YAAY,EAAE,MAAM,OAAO,CAAC;AAoBzD,aAAK,mBAAmB,CAAC,CAAC,IAAI;IAC5B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IAC7B;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,aAAK,SAAS,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,mBAAmB,CAAC,CAAC,CAAC,CAAC;AAEnE,QAAA,MAAM,IAAI,iEAwHT,CAAC;AAEF,aAAK,oBAAoB,CAAC,CAAC,IAAI,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,GAAG;IACxE,KAAK,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;IAC7B,aAAa,CAAC,EAAE,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC;IAC1C,YAAY,EAAE,YAAY,CAAC;CAC5B,CAAC;AAEF,QAAA,MAAM,eAAe,4EAoNpB,CAAC;AAEF,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC;AACjC,YAAY,EAAE,SAAS,EAAE,oBAAoB,EAAE,CAAC"}
|
package/dist/index.d.ts.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACnE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,YAAY,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACnE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,YAAY,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAExC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEpD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.es.js
CHANGED
@@ -147,13 +147,11 @@ MenuSearch.displayName = "MenuSearch";
|
|
147
147
|
// src/Menu.tsx
|
148
148
|
import { useFocusManager } from "@react-aria/focus";
|
149
149
|
import cx3 from "clsx";
|
150
|
-
import { isNil, noop } from "lodash-es";
|
151
150
|
import { Children, cloneElement, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
152
151
|
import { useVirtual } from "react-virtual";
|
153
152
|
import { v4 } from "uuid";
|
154
153
|
|
155
154
|
// src/utils.ts
|
156
|
-
import { isFunction } from "lodash-es";
|
157
155
|
var createItemId = (index, id) => `${id}-item-${index}`;
|
158
156
|
var getNodeForIndex = (index, menuId) => index === null ? index : document.getElementById(createItemId(index, menuId));
|
159
157
|
var handleKeyboardInteractions = (event, keyHandlers) => {
|
@@ -168,7 +166,7 @@ var handleKeyboardInteractions = (event, keyHandlers) => {
|
|
168
166
|
}
|
169
167
|
};
|
170
168
|
var chainEventHandlers = (...handlers) => (event) => {
|
171
|
-
handlers.forEach((h) =>
|
169
|
+
handlers.forEach((h) => typeof h === "function" && h(event));
|
172
170
|
};
|
173
171
|
|
174
172
|
// src/Menu.tsx
|
@@ -226,8 +224,8 @@ var Menu = (props) => {
|
|
226
224
|
case MenuItemLink:
|
227
225
|
return {
|
228
226
|
items: items.concat(child.props.disabled ? cloneElement(child, {
|
229
|
-
onClick:
|
230
|
-
onKeyDown:
|
227
|
+
onClick: () => void 0,
|
228
|
+
onKeyDown: () => void 0,
|
231
229
|
tabIndex: -1,
|
232
230
|
disabled: true
|
233
231
|
}) : cloneElement(child, {
|
@@ -302,7 +300,7 @@ var ItemVirtualizer = (props) => {
|
|
302
300
|
setNextFocusValue(index);
|
303
301
|
}, [rowVirtualizer]);
|
304
302
|
const handleKeyboardFocusInteraction = useCallback((direction) => {
|
305
|
-
if (
|
303
|
+
if (focusedItemIndex.current === null || focusedItemIndex.current === void 0) {
|
306
304
|
return;
|
307
305
|
}
|
308
306
|
const nextIndex = direction === "next" ? focusedItemIndex.current + 1 : focusedItemIndex.current - 1;
|
@@ -335,7 +333,7 @@ var ItemVirtualizer = (props) => {
|
|
335
333
|
case MenuItemLink:
|
336
334
|
return {
|
337
335
|
className: cx3(childProps.className, menuItemClassName),
|
338
|
-
onKeyDown: childProps.disabled ?
|
336
|
+
onKeyDown: childProps.disabled ? () => void 0 : (e) => handleKeyboardFocusKeydown(e, {
|
339
337
|
handleFocusBackward: handleKeyboardFocusInteraction,
|
340
338
|
handleFocusForward: handleKeyboardFocusInteraction
|
341
339
|
}),
|
@@ -346,7 +344,7 @@ var ItemVirtualizer = (props) => {
|
|
346
344
|
onBlur: chainEventHandlers(childProps.onBlur, () => {
|
347
345
|
focusedItemIndex.current = null;
|
348
346
|
}),
|
349
|
-
onClick: childProps.disabled ?
|
347
|
+
onClick: childProps.disabled ? () => void 0 : chainEventHandlers(childProps.onClick, () => {
|
350
348
|
onSelect?.(childProps.item);
|
351
349
|
})
|
352
350
|
};
|
package/dist/index.es.js.map
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"version": 3,
|
3
3
|
"sources": ["../../../scripts/react-shim.js", "../src/MenuBase.tsx", "../src/MenuDivider.tsx", "../src/MenuItem.tsx", "../src/MenuItemList.tsx", "../src/MenuSearch.tsx", "../src/Menu.tsx", "../src/utils.ts", "../src/types.ts"],
|
4
|
-
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import type { MenuSize } from './types';\n\nimport cx from 'clsx';\nimport { forwardRef } from 'react';\n\nimport './styles/Menu.css';\n\ntype MenuBaseProps = React.ComponentPropsWithRef<'div'> & {\n isVirtual?: boolean;\n size?: MenuSize;\n};\n\nconst MenuBase = forwardRef<HTMLDivElement, MenuBaseProps>(\n ({ children, size, isVirtual, ...props }, ref) => {\n const classes = cx('Menu', {\n 'Menu--isVirtual': isVirtual,\n [`MenuSize--${size}`]: size,\n });\n\n return (\n <div {...props} role=\"menu\" className={classes} ref={ref}>\n {children}\n </div>\n );\n }\n);\n\nMenuBase.displayName = 'MenuBase';\n\nexport { MenuBase };\nexport type { MenuBaseProps };\n", "import type { SeparatorProps } from '@react-aria/separator';\n\nimport { useSeparator } from '@react-aria/separator';\n\nimport './styles/Menu.css';\n\ntype MenuDividerProps = SeparatorProps & {\n innerRef?: React.RefObject<HTMLDivElement>;\n};\n\nconst MenuDivider = ({ elementType = 'div', orientation, innerRef }: MenuDividerProps) => {\n const { separatorProps } = useSeparator({\n orientation,\n elementType,\n });\n\n return <div {...separatorProps} ref={innerRef} className=\"Menu-divider\" />;\n};\n\nexport { MenuDivider };\nexport type { MenuDividerProps };\n", "import type { Icon } from '@launchpad-ui/icons';\nimport type { PopoverPlacement } from '@launchpad-ui/popover';\n\nimport { IconSize } from '@launchpad-ui/icons';\nimport { Tooltip } from '@launchpad-ui/tooltip';\nimport { Slot } from '@radix-ui/react-slot';\nimport { FocusRing } from '@react-aria/focus';\nimport cx from 'clsx';\nimport { Link } from 'react-router-dom';\n\nimport './styles/Menu.css';\n\n// Merge two types and get rid of overlapping definitions\ntype Merge<T, U> = Omit<T, keyof U> & U;\n\ntype PropsWithComponent<P, T extends React.ElementType> = P & { component?: T };\n\ntype PolymorphicPropsWithRef<P, T extends React.ElementType> = Merge<\n T extends keyof JSX.IntrinsicElements\n ? React.PropsWithRef<JSX.IntrinsicElements[T]>\n : React.ComponentPropsWithRef<T>,\n PropsWithComponent<P, T>\n>;\n\ntype MenuItemOwnProps = {\n isHighlighted?: boolean;\n icon?: typeof Icon | null;\n disabled?: boolean;\n nested?: boolean;\n groupHeader?: boolean;\n tooltip?: string | React.ReactElement;\n tooltipOptions?: typeof Tooltip;\n tooltipPlacement?: PopoverPlacement;\n asChild?: boolean;\n};\n\nconst defaultElement = 'button';\n\ntype MenuItemProps<\n P,\n T extends React.ElementType = typeof defaultElement\n> = PolymorphicPropsWithRef<\n | (MenuItemOwnProps & {\n item: P; // Infer the type if it is included\n })\n | (MenuItemOwnProps & {\n item?: undefined;\n }),\n T\n>;\n\nconst MenuItem = <P, T extends React.ElementType = typeof defaultElement>({\n ...props\n}: MenuItemProps<P, T>) => {\n const {\n // TODO: remove component prop once we migrate over to asChild format\n component,\n children,\n isHighlighted,\n icon: Icon,\n nested,\n groupHeader,\n item,\n disabled,\n className,\n tooltip,\n role = 'menuitem',\n tooltipPlacement,\n onKeyDown,\n tooltipOptions,\n asChild,\n ...rest\n } = props;\n\n const Component: React.ElementType = component || (asChild ? Slot : defaultElement);\n\n const renderedItem = (\n <FocusRing focusRingClass=\"has-focus\">\n <Component\n {...rest}\n disabled={disabled}\n aria-disabled={disabled ? disabled : undefined}\n className={cx(\n 'Menu-item',\n className,\n { 'is-highlighted': isHighlighted },\n { 'Menu-item--nested': nested },\n { 'Menu-item--header': groupHeader }\n )}\n role={role}\n onKeyDown={onKeyDown}\n >\n {asChild ? (\n children\n ) : (\n <>\n {Icon && (\n <span className=\"Menu-item-icon\">\n <Icon size={IconSize.SMALL} />\n </span>\n )}\n {children}\n </>\n )}\n </Component>\n </FocusRing>\n );\n\n if (tooltip) {\n return (\n <Tooltip\n content={tooltip}\n rootElementStyle={{ display: 'block' }}\n allowBoundaryElementOverflow\n placement={tooltipPlacement ? tooltipPlacement : 'bottom'}\n {...(tooltipOptions || {})}\n >\n {renderedItem}\n </Tooltip>\n );\n }\n\n return renderedItem;\n};\n\ntype MenuItemLinkOwnProps = {\n disabled?: boolean;\n useHistory?: boolean;\n newTab?: boolean;\n};\n\ntype MenuItemLinkProps<P, T extends React.ElementType = typeof Link> =\n | Merge<Omit<MenuItemProps<P, T>, 'component' | 'item'>, MenuItemLinkOwnProps> &\n (\n | {\n item?: undefined;\n }\n | {\n item: P;\n }\n );\n\n// By default, this is a Link component whenever useHistory is\n// explicitly not false\n// TODO: deprecate this component\nconst MenuItemLink = <P, T extends React.ElementType = typeof Link>({\n to,\n disabled = false,\n useHistory = true,\n newTab = false,\n children,\n ...props\n}: MenuItemLinkProps<P, T>) => {\n const finalProps = {\n ...props,\n disabled,\n component: useHistory ? Link : ('a' as const),\n [useHistory ? 'to' : 'href']: disabled ? '' : to,\n rel: newTab ? 'noopener noreferrer' : undefined,\n target: newTab ? '_blank' : undefined,\n };\n\n // Ideally if this item is disabled, it should be a button rather\n // than a link https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/anchor-is-valid.md\n\n return <MenuItem {...finalProps}>{children}</MenuItem>;\n};\n\nexport { MenuItem, MenuItemLink };\nexport type { MenuItemProps, MenuItemLinkProps };\n", "import { forwardRef } from 'react';\n\nimport './styles/Menu.css';\n\ntype MenuItemListProps = Omit<React.ComponentPropsWithRef<'div'>, 'className'>;\n\nconst MenuItemList = forwardRef<HTMLDivElement, MenuItemListProps>(({ children, ...rest }, ref) => (\n <div {...rest} ref={ref} data-test-id=\"menu-item-list\" className=\"Menu-item-list\">\n {children}\n </div>\n));\n\nMenuItemList.displayName = 'MenuItemList';\n\nexport { MenuItemList };\nexport type { MenuItemListProps };\n", "import type { ChangeEvent } from 'react';\n\nimport { forwardRef } from 'react';\n\nimport './styles/Menu.css';\n\ntype MenuSearchProps = {\n ariaLabel?: string;\n value?: string;\n placeholder?: string;\n onChange?(event: ChangeEvent<HTMLInputElement>): void;\n};\n\nconst MenuSearch = forwardRef<HTMLInputElement, MenuSearchProps>((props, ref) => {\n const { ariaLabel, placeholder, ...finalProps } = props;\n\n return (\n <div className=\"Menu-search\">\n <input\n {...finalProps}\n ref={ref}\n className=\"Menu-search-input FormInput FormInput--tiny\"\n type=\"search\"\n autoComplete=\"off\"\n placeholder={placeholder}\n aria-label={ariaLabel || 'Search'}\n />\n <div\n className=\"Menu-search-hidden-placeholder Menu-search-input FormInput FormInput--tiny\"\n aria-hidden=\"true\"\n >\n {placeholder}\n </div>\n </div>\n );\n});\n\nMenuSearch.displayName = 'MenuSearch';\n\nexport { MenuSearch };\nexport type { MenuSearchProps };\n", "import type { MenuItemProps } from './MenuItem';\nimport type { MenuSize } from './types';\nimport type { FocusManager } from '@react-aria/focus';\nimport type { KeyboardEvent, ReactElement } from 'react';\n\nimport { useFocusManager } from '@react-aria/focus';\nimport cx from 'clsx';\nimport { isNil, noop } from 'lodash-es';\nimport { Children, cloneElement, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useVirtual } from 'react-virtual';\nimport { v4 } from 'uuid';\n\nimport { MenuBase } from './MenuBase';\nimport { MenuDivider } from './MenuDivider';\nimport { MenuItem, MenuItemLink } from './MenuItem';\nimport { MenuItemList } from './MenuItemList';\nimport { MenuSearch } from './MenuSearch';\nimport {\n chainEventHandlers,\n createItemId,\n getNodeForIndex,\n handleKeyboardInteractions,\n} from './utils';\n\ntype ControlledMenuProps<T> = {\n children: React.ReactNode;\n onSelect?: (item: T) => void;\n /**\n * Menus items are rendered using react-virtual for\n * additional rendering performance.\n */\n enableVirtualization?: boolean;\n /**\n * Class name to be applied to all MenuItem and MenuItemLink components\n * in the menu.\n */\n menuItemClassName?: string;\n /**\n * Sets the width of the menu. This is especially useful when using virtual items\n * since the width cannot be automatically set by the widest element.\n */\n size?: MenuSize;\n /**\n * Sets the number out of elements rendered outside of the view window\n * when using virtualization\n */\n overscan?: number;\n /**\n * Sets the height for each menu item when using virtualization.\n *\n */\n itemHeight?: number;\n};\n\ntype MenuProps<T extends number | string> = ControlledMenuProps<T>;\n\nconst Menu = <T extends number | string>(props: MenuProps<T>) => {\n const {\n children,\n menuItemClassName,\n onSelect,\n enableVirtualization,\n itemHeight,\n size,\n overscan = 1,\n } = props;\n\n const focusManager = useFocusManager();\n\n const handleArrowDown = useCallback(() => {\n focusManager.focusNext({ wrap: true });\n }, [focusManager]);\n\n const handleArrowUp = useCallback(() => {\n focusManager.focusPrevious({ wrap: true });\n }, [focusManager]);\n\n const reduceItems = useMemo(() => {\n const childrenProps = Children.toArray(children);\n if (enableVirtualization) {\n // the virtualized menu has its own handlers and props\n let searchElem = null;\n let elements: ReactElement[] = [];\n (childrenProps as ReactElement[]).forEach((child: ReactElement) => {\n switch (child.type) {\n case MenuSearch:\n searchElem = child;\n break;\n case MenuItem:\n case MenuItemLink:\n case MenuDivider:\n elements = elements.concat(child);\n break;\n default:\n break;\n }\n });\n return { items: elements, searchElement: searchElem };\n }\n\n return (childrenProps as ReactElement[]).reduce(\n (\n { items, searchElement }: { items: ReactElement[]; searchElement: null | ReactElement },\n child\n ) => {\n switch (child.type) {\n case MenuSearch:\n return {\n items,\n searchElement: cloneElement(child, {\n onKeyDown: (e: KeyboardEvent) =>\n handleKeyboardInteractions(e, {\n handleDown: handleArrowDown,\n handleUp: handleArrowUp,\n }),\n }),\n };\n case MenuItem:\n case MenuItemLink:\n return {\n items: items.concat(\n child.props.disabled\n ? cloneElement(child, {\n onClick: noop,\n onKeyDown: noop,\n tabIndex: -1,\n disabled: true,\n })\n : cloneElement(child, {\n className: cx(child.props.className, menuItemClassName),\n item: child.props.item ?? items.length,\n // set focus on the first menu item if there is no search input, and set in the tab order\n onClick: chainEventHandlers(child.props.onClick, () => {\n onSelect?.(child.props.item ?? items.length);\n }),\n onKeyDown: (e: KeyboardEvent) =>\n handleKeyboardInteractions(e, {\n handleDown: handleArrowDown,\n handleUp: handleArrowUp,\n }),\n })\n ),\n searchElement,\n };\n case MenuDivider:\n return { items: items.concat(child), searchElement };\n default:\n return { items, searchElement };\n }\n },\n { items: [], searchElement: null }\n );\n }, [children, enableVirtualization, menuItemClassName, handleArrowDown, handleArrowUp, onSelect]);\n\n if (enableVirtualization) {\n return (\n <MenuBase isVirtual size={size}>\n <ItemVirtualizer<T>\n items={Children.toArray(reduceItems.items) as ReactElement[]}\n searchElement={reduceItems.searchElement}\n overscan={overscan}\n menuItemClassName={menuItemClassName}\n onSelect={onSelect}\n itemHeight={itemHeight}\n focusManager={focusManager}\n />\n </MenuBase>\n );\n }\n\n return (\n <MenuBase size={size}>\n {reduceItems.searchElement}\n <MenuItemList role=\"presentation\">{reduceItems.items}</MenuItemList>\n </MenuBase>\n );\n};\n\ntype ItemVirtualizerProps<T> = Omit<ControlledMenuProps<T>, 'children'> & {\n items: ReactElement[] | null;\n searchElement?: React.ReactElement | null;\n focusManager: FocusManager;\n};\n\nconst ItemVirtualizer = <T extends number | string>(props: ItemVirtualizerProps<T>) => {\n const {\n overscan,\n searchElement,\n itemHeight = 33,\n menuItemClassName,\n items: items,\n focusManager,\n onSelect,\n } = props;\n\n const menuId = useRef(`menu-ctrl-${v4()}`);\n\n const focusedItemIndex = useRef<number | null>(null);\n const parentRef = useRef<HTMLDivElement | null>(null);\n const searchRef = useRef<HTMLInputElement>();\n\n const [nextFocusValue, setNextFocusValue] = useState<number | null>(null);\n\n const hasSearch = !!searchElement;\n\n const lastVirtualItemIndex = items ? items.length - 1 : 0;\n\n const rowVirtualizer = useVirtual({\n size: items !== null ? items.length : 0,\n parentRef,\n estimateSize: useCallback(() => itemHeight, [itemHeight]),\n overscan,\n });\n\n const focusSearchBar = useCallback(() => {\n rowVirtualizer.scrollToIndex(0);\n searchRef.current?.focus?.();\n }, [rowVirtualizer]);\n\n /**\n * Scrolls to the menu item with the index provided and\n * then manually focuses it using a side effect in useEffect\n */\n const focusMenuItem = useCallback(\n (index: number) => {\n rowVirtualizer.scrollToIndex(index);\n setNextFocusValue(index);\n },\n [rowVirtualizer]\n );\n\n const handleKeyboardFocusInteraction = useCallback(\n (direction: 'next' | 'previous') => {\n if (isNil(focusedItemIndex.current)) {\n return;\n }\n const nextIndex =\n direction === 'next' ? focusedItemIndex.current + 1 : focusedItemIndex.current - 1;\n const shouldWrap =\n (direction === 'next' && focusedItemIndex.current === lastVirtualItemIndex) ||\n (direction === 'previous' && focusedItemIndex.current === 0);\n if (shouldWrap) {\n // we are at the end of the list so we will\n // scroll back to the beginning of the list\n if (hasSearch) {\n focusSearchBar();\n } else {\n // if at end, wrap to beginning, else focus last item\n focusMenuItem(direction === 'next' ? 0 : lastVirtualItemIndex);\n }\n return;\n }\n switch (direction) {\n case 'next':\n rowVirtualizer.scrollToIndex(nextIndex);\n focusManager.focusNext();\n break;\n case 'previous':\n rowVirtualizer.scrollToIndex(nextIndex);\n focusManager.focusPrevious();\n break;\n default:\n break;\n }\n },\n [focusManager, focusMenuItem, focusSearchBar, hasSearch, lastVirtualItemIndex, rowVirtualizer]\n );\n\n const getItemProps = useCallback(\n (itemElem: ReactElement, index: number) => {\n const childProps = itemElem.props as MenuItemProps<T>;\n switch (itemElem.type) {\n case MenuItem:\n case MenuItemLink:\n return {\n className: cx(childProps.className, menuItemClassName),\n // set focus on the first menu item if there is no search input, and set in the tab order\n onKeyDown: childProps.disabled\n ? noop\n : (e: KeyboardEvent) =>\n handleKeyboardFocusKeydown(e, {\n handleFocusBackward: handleKeyboardFocusInteraction,\n handleFocusForward: handleKeyboardFocusInteraction,\n }),\n onFocus: chainEventHandlers(childProps.onFocus, () => {\n focusedItemIndex.current = index;\n }),\n id: createItemId(index, menuId.current),\n onBlur: chainEventHandlers(childProps.onBlur, () => {\n focusedItemIndex.current = null;\n }),\n onClick: childProps.disabled\n ? noop\n : chainEventHandlers(childProps.onClick, () => {\n onSelect?.(childProps.item as T);\n }),\n } as MenuItemProps<T>;\n default:\n return {};\n }\n },\n [handleKeyboardFocusInteraction, menuItemClassName, onSelect]\n );\n\n useEffect(() => {\n if (nextFocusValue !== null) {\n requestAnimationFrame(() => {\n const element = getNodeForIndex(nextFocusValue, menuId.current);\n element?.focus();\n });\n setNextFocusValue(null);\n }\n }, [nextFocusValue]);\n\n /**\n * Calls handleFocusForward when the user is attempting to focus forward using\n * tab or arrow keys. Calls handleFocusBackward when the users wants to move backward.\n */\n const handleKeyboardFocusKeydown = (\n e: KeyboardEvent,\n callbacks: Record<\n 'handleFocusForward' | 'handleFocusBackward',\n (direction: 'next' | 'previous') => void\n >\n ) => {\n const keyOps = ['Tab', 'ArrowUp', 'ArrowDown'];\n if (keyOps.includes(e.key)) {\n e.preventDefault();\n e.stopPropagation();\n if ((e.key === 'Tab' && e.shiftKey) || e.key === 'ArrowUp') {\n callbacks.handleFocusBackward?.('previous');\n } else if (e.key === 'ArrowDown' || e.key === 'Tab') {\n callbacks.handleFocusForward?.('next');\n }\n }\n };\n\n const renderSearch = useMemo(\n () =>\n searchElement\n ? cloneElement(searchElement, {\n onKeyDown: (e: KeyboardEvent) =>\n handleKeyboardFocusKeydown(e, {\n handleFocusBackward: () => focusMenuItem(lastVirtualItemIndex),\n handleFocusForward: () => focusMenuItem(0),\n }),\n ref: searchRef,\n })\n : null,\n [searchElement, lastVirtualItemIndex, focusMenuItem]\n );\n\n const renderItems = useMemo(\n () =>\n rowVirtualizer.virtualItems.map((virtualRow) => {\n if (!items) {\n return null;\n }\n const elem = items[virtualRow.index];\n return (\n <div\n key={virtualRow.index}\n ref={\n elem.type !== MenuItem || elem.type !== MenuItemLink\n ? virtualRow.measureRef\n : undefined\n }\n role=\"presentation\"\n className={cx('VirtualMenu-item')}\n style={{\n transform: `translateY(${virtualRow.start}px)`,\n }}\n >\n {cloneElement(elem, getItemProps(elem, virtualRow.index))}\n </div>\n );\n }),\n [rowVirtualizer.virtualItems, items, getItemProps]\n );\n\n return (\n <>\n {renderSearch}\n <MenuItemList ref={parentRef} role=\"presentation\">\n <div\n role=\"presentation\"\n className=\"VirtualMenu-item-list\"\n style={{\n height: `${rowVirtualizer.totalSize}px`,\n }}\n >\n {renderItems}\n </div>\n </MenuItemList>\n </>\n );\n};\n\nexport { Menu, ItemVirtualizer };\nexport type { MenuProps, ItemVirtualizerProps };\n", "import type { KeyboardEvent } from 'react';\n\nimport { isFunction } from 'lodash-es';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyFunction = (...args: any[]) => any;\n\nconst createItemId = (index: number, id: string) => `${id}-item-${index}`;\n\nconst getNodeForIndex = (index: number | null, menuId: string) =>\n index === null ? index : document.getElementById(createItemId(index, menuId));\n\nconst handleKeyboardInteractions = (\n event: React.KeyboardEvent,\n keyHandlers: Partial<\n Record<'handleUp' | 'handleDown' | 'handleEnter', (e: KeyboardEvent) => void>\n >\n) => {\n const ops = {\n ArrowUp: keyHandlers.handleUp,\n ArrowDown: keyHandlers.handleDown,\n Enter: keyHandlers.handleEnter,\n } as Record<string, (e: KeyboardEvent) => void | undefined>;\n\n if (ops[event.key]) {\n event.preventDefault();\n ops[event.key]?.call(globalThis, event);\n }\n};\n\nconst chainEventHandlers =\n (...handlers: Array<AnyFunction | undefined>) =>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (event: any) => {\n handlers.forEach((h) => isFunction(h) && h(event));\n };\n\nexport { createItemId, getNodeForIndex, handleKeyboardInteractions, chainEventHandlers };\n", "enum MenuSize {\n SMALL = 'sm',\n MEDIUM = 'md',\n LARGE = 'lg',\n EXTRA_LARGE = 'xl',\n}\n\nexport { MenuSize };\n"],
|
5
|
-
"mappings": "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
|
4
|
+
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import type { MenuSize } from './types';\n\nimport cx from 'clsx';\nimport { forwardRef } from 'react';\n\nimport './styles/Menu.css';\n\ntype MenuBaseProps = React.ComponentPropsWithRef<'div'> & {\n isVirtual?: boolean;\n size?: MenuSize;\n};\n\nconst MenuBase = forwardRef<HTMLDivElement, MenuBaseProps>(\n ({ children, size, isVirtual, ...props }, ref) => {\n const classes = cx('Menu', {\n 'Menu--isVirtual': isVirtual,\n [`MenuSize--${size}`]: size,\n });\n\n return (\n <div {...props} role=\"menu\" className={classes} ref={ref}>\n {children}\n </div>\n );\n }\n);\n\nMenuBase.displayName = 'MenuBase';\n\nexport { MenuBase };\nexport type { MenuBaseProps };\n", "import type { SeparatorProps } from '@react-aria/separator';\n\nimport { useSeparator } from '@react-aria/separator';\n\nimport './styles/Menu.css';\n\ntype MenuDividerProps = SeparatorProps & {\n innerRef?: React.RefObject<HTMLDivElement>;\n};\n\nconst MenuDivider = ({ elementType = 'div', orientation, innerRef }: MenuDividerProps) => {\n const { separatorProps } = useSeparator({\n orientation,\n elementType,\n });\n\n return <div {...separatorProps} ref={innerRef} className=\"Menu-divider\" />;\n};\n\nexport { MenuDivider };\nexport type { MenuDividerProps };\n", "import type { Icon } from '@launchpad-ui/icons';\nimport type { PopoverPlacement } from '@launchpad-ui/popover';\n\nimport { IconSize } from '@launchpad-ui/icons';\nimport { Tooltip } from '@launchpad-ui/tooltip';\nimport { Slot } from '@radix-ui/react-slot';\nimport { FocusRing } from '@react-aria/focus';\nimport cx from 'clsx';\nimport { Link } from 'react-router-dom';\n\nimport './styles/Menu.css';\n\n// Merge two types and get rid of overlapping definitions\ntype Merge<T, U> = Omit<T, keyof U> & U;\n\ntype PropsWithComponent<P, T extends React.ElementType> = P & { component?: T };\n\ntype PolymorphicPropsWithRef<P, T extends React.ElementType> = Merge<\n T extends keyof JSX.IntrinsicElements\n ? React.PropsWithRef<JSX.IntrinsicElements[T]>\n : React.ComponentPropsWithRef<T>,\n PropsWithComponent<P, T>\n>;\n\ntype MenuItemOwnProps = {\n isHighlighted?: boolean;\n icon?: typeof Icon | null;\n disabled?: boolean;\n nested?: boolean;\n groupHeader?: boolean;\n tooltip?: string | React.ReactElement;\n tooltipOptions?: typeof Tooltip;\n tooltipPlacement?: PopoverPlacement;\n asChild?: boolean;\n};\n\nconst defaultElement = 'button';\n\ntype MenuItemProps<\n P,\n T extends React.ElementType = typeof defaultElement\n> = PolymorphicPropsWithRef<\n | (MenuItemOwnProps & {\n item: P; // Infer the type if it is included\n })\n | (MenuItemOwnProps & {\n item?: undefined;\n }),\n T\n>;\n\nconst MenuItem = <P, T extends React.ElementType = typeof defaultElement>({\n ...props\n}: MenuItemProps<P, T>) => {\n const {\n // TODO: remove component prop once we migrate over to asChild format\n component,\n children,\n isHighlighted,\n icon: Icon,\n nested,\n groupHeader,\n item,\n disabled,\n className,\n tooltip,\n role = 'menuitem',\n tooltipPlacement,\n onKeyDown,\n tooltipOptions,\n asChild,\n ...rest\n } = props;\n\n const Component: React.ElementType = component || (asChild ? Slot : defaultElement);\n\n const renderedItem = (\n <FocusRing focusRingClass=\"has-focus\">\n <Component\n {...rest}\n disabled={disabled}\n aria-disabled={disabled ? disabled : undefined}\n className={cx(\n 'Menu-item',\n className,\n { 'is-highlighted': isHighlighted },\n { 'Menu-item--nested': nested },\n { 'Menu-item--header': groupHeader }\n )}\n role={role}\n onKeyDown={onKeyDown}\n >\n {asChild ? (\n children\n ) : (\n <>\n {Icon && (\n <span className=\"Menu-item-icon\">\n <Icon size={IconSize.SMALL} />\n </span>\n )}\n {children}\n </>\n )}\n </Component>\n </FocusRing>\n );\n\n if (tooltip) {\n return (\n <Tooltip\n content={tooltip}\n rootElementStyle={{ display: 'block' }}\n allowBoundaryElementOverflow\n placement={tooltipPlacement ? tooltipPlacement : 'bottom'}\n {...(tooltipOptions || {})}\n >\n {renderedItem}\n </Tooltip>\n );\n }\n\n return renderedItem;\n};\n\ntype MenuItemLinkOwnProps = {\n disabled?: boolean;\n useHistory?: boolean;\n newTab?: boolean;\n};\n\ntype MenuItemLinkProps<P, T extends React.ElementType = typeof Link> =\n | Merge<Omit<MenuItemProps<P, T>, 'component' | 'item'>, MenuItemLinkOwnProps> &\n (\n | {\n item?: undefined;\n }\n | {\n item: P;\n }\n );\n\n// By default, this is a Link component whenever useHistory is\n// explicitly not false\n// TODO: deprecate this component\nconst MenuItemLink = <P, T extends React.ElementType = typeof Link>({\n to,\n disabled = false,\n useHistory = true,\n newTab = false,\n children,\n ...props\n}: MenuItemLinkProps<P, T>) => {\n const finalProps = {\n ...props,\n disabled,\n component: useHistory ? Link : ('a' as const),\n [useHistory ? 'to' : 'href']: disabled ? '' : to,\n rel: newTab ? 'noopener noreferrer' : undefined,\n target: newTab ? '_blank' : undefined,\n };\n\n // Ideally if this item is disabled, it should be a button rather\n // than a link https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/anchor-is-valid.md\n\n return <MenuItem {...finalProps}>{children}</MenuItem>;\n};\n\nexport { MenuItem, MenuItemLink };\nexport type { MenuItemProps, MenuItemLinkProps };\n", "import { forwardRef } from 'react';\n\nimport './styles/Menu.css';\n\ntype MenuItemListProps = Omit<React.ComponentPropsWithRef<'div'>, 'className'>;\n\nconst MenuItemList = forwardRef<HTMLDivElement, MenuItemListProps>(({ children, ...rest }, ref) => (\n <div {...rest} ref={ref} data-test-id=\"menu-item-list\" className=\"Menu-item-list\">\n {children}\n </div>\n));\n\nMenuItemList.displayName = 'MenuItemList';\n\nexport { MenuItemList };\nexport type { MenuItemListProps };\n", "import type { ChangeEvent } from 'react';\n\nimport { forwardRef } from 'react';\n\nimport './styles/Menu.css';\n\ntype MenuSearchProps = {\n ariaLabel?: string;\n value?: string;\n placeholder?: string;\n onChange?(event: ChangeEvent<HTMLInputElement>): void;\n};\n\nconst MenuSearch = forwardRef<HTMLInputElement, MenuSearchProps>((props, ref) => {\n const { ariaLabel, placeholder, ...finalProps } = props;\n\n return (\n <div className=\"Menu-search\">\n <input\n {...finalProps}\n ref={ref}\n className=\"Menu-search-input FormInput FormInput--tiny\"\n type=\"search\"\n autoComplete=\"off\"\n placeholder={placeholder}\n aria-label={ariaLabel || 'Search'}\n />\n <div\n className=\"Menu-search-hidden-placeholder Menu-search-input FormInput FormInput--tiny\"\n aria-hidden=\"true\"\n >\n {placeholder}\n </div>\n </div>\n );\n});\n\nMenuSearch.displayName = 'MenuSearch';\n\nexport { MenuSearch };\nexport type { MenuSearchProps };\n", "import type { MenuItemProps } from './MenuItem';\nimport type { MenuSize } from './types';\nimport type { FocusManager } from '@react-aria/focus';\nimport type { KeyboardEvent, ReactElement } from 'react';\n\nimport { useFocusManager } from '@react-aria/focus';\nimport cx from 'clsx';\nimport { Children, cloneElement, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useVirtual } from 'react-virtual';\nimport { v4 } from 'uuid';\n\nimport { MenuBase } from './MenuBase';\nimport { MenuDivider } from './MenuDivider';\nimport { MenuItem, MenuItemLink } from './MenuItem';\nimport { MenuItemList } from './MenuItemList';\nimport { MenuSearch } from './MenuSearch';\nimport {\n chainEventHandlers,\n createItemId,\n getNodeForIndex,\n handleKeyboardInteractions,\n} from './utils';\n\ntype ControlledMenuProps<T> = {\n children: React.ReactNode;\n onSelect?: (item: T) => void;\n /**\n * Menus items are rendered using react-virtual for\n * additional rendering performance.\n */\n enableVirtualization?: boolean;\n /**\n * Class name to be applied to all MenuItem and MenuItemLink components\n * in the menu.\n */\n menuItemClassName?: string;\n /**\n * Sets the width of the menu. This is especially useful when using virtual items\n * since the width cannot be automatically set by the widest element.\n */\n size?: MenuSize;\n /**\n * Sets the number out of elements rendered outside of the view window\n * when using virtualization\n */\n overscan?: number;\n /**\n * Sets the height for each menu item when using virtualization.\n *\n */\n itemHeight?: number;\n};\n\ntype MenuProps<T extends number | string> = ControlledMenuProps<T>;\n\nconst Menu = <T extends number | string>(props: MenuProps<T>) => {\n const {\n children,\n menuItemClassName,\n onSelect,\n enableVirtualization,\n itemHeight,\n size,\n overscan = 1,\n } = props;\n\n const focusManager = useFocusManager();\n\n const handleArrowDown = useCallback(() => {\n focusManager.focusNext({ wrap: true });\n }, [focusManager]);\n\n const handleArrowUp = useCallback(() => {\n focusManager.focusPrevious({ wrap: true });\n }, [focusManager]);\n\n const reduceItems = useMemo(() => {\n const childrenProps = Children.toArray(children);\n if (enableVirtualization) {\n // the virtualized menu has its own handlers and props\n let searchElem = null;\n let elements: ReactElement[] = [];\n (childrenProps as ReactElement[]).forEach((child: ReactElement) => {\n switch (child.type) {\n case MenuSearch:\n searchElem = child;\n break;\n case MenuItem:\n case MenuItemLink:\n case MenuDivider:\n elements = elements.concat(child);\n break;\n default:\n break;\n }\n });\n return { items: elements, searchElement: searchElem };\n }\n\n return (childrenProps as ReactElement[]).reduce(\n (\n { items, searchElement }: { items: ReactElement[]; searchElement: null | ReactElement },\n child\n ) => {\n switch (child.type) {\n case MenuSearch:\n return {\n items,\n searchElement: cloneElement(child, {\n onKeyDown: (e: KeyboardEvent) =>\n handleKeyboardInteractions(e, {\n handleDown: handleArrowDown,\n handleUp: handleArrowUp,\n }),\n }),\n };\n case MenuItem:\n case MenuItemLink:\n return {\n items: items.concat(\n child.props.disabled\n ? cloneElement(child, {\n onClick: () => undefined,\n onKeyDown: () => undefined,\n tabIndex: -1,\n disabled: true,\n })\n : cloneElement(child, {\n className: cx(child.props.className, menuItemClassName),\n item: child.props.item ?? items.length,\n // set focus on the first menu item if there is no search input, and set in the tab order\n onClick: chainEventHandlers(child.props.onClick, () => {\n onSelect?.(child.props.item ?? items.length);\n }),\n onKeyDown: (e: KeyboardEvent) =>\n handleKeyboardInteractions(e, {\n handleDown: handleArrowDown,\n handleUp: handleArrowUp,\n }),\n })\n ),\n searchElement,\n };\n case MenuDivider:\n return { items: items.concat(child), searchElement };\n default:\n return { items, searchElement };\n }\n },\n { items: [], searchElement: null }\n );\n }, [children, enableVirtualization, menuItemClassName, handleArrowDown, handleArrowUp, onSelect]);\n\n if (enableVirtualization) {\n return (\n <MenuBase isVirtual size={size}>\n <ItemVirtualizer<T>\n items={Children.toArray(reduceItems.items) as ReactElement[]}\n searchElement={reduceItems.searchElement}\n overscan={overscan}\n menuItemClassName={menuItemClassName}\n onSelect={onSelect}\n itemHeight={itemHeight}\n focusManager={focusManager}\n />\n </MenuBase>\n );\n }\n\n return (\n <MenuBase size={size}>\n {reduceItems.searchElement}\n <MenuItemList role=\"presentation\">{reduceItems.items}</MenuItemList>\n </MenuBase>\n );\n};\n\ntype ItemVirtualizerProps<T> = Omit<ControlledMenuProps<T>, 'children'> & {\n items: ReactElement[] | null;\n searchElement?: React.ReactElement | null;\n focusManager: FocusManager;\n};\n\nconst ItemVirtualizer = <T extends number | string>(props: ItemVirtualizerProps<T>) => {\n const {\n overscan,\n searchElement,\n itemHeight = 33,\n menuItemClassName,\n items: items,\n focusManager,\n onSelect,\n } = props;\n\n const menuId = useRef(`menu-ctrl-${v4()}`);\n\n const focusedItemIndex = useRef<number | null>(null);\n const parentRef = useRef<HTMLDivElement | null>(null);\n const searchRef = useRef<HTMLInputElement>();\n\n const [nextFocusValue, setNextFocusValue] = useState<number | null>(null);\n\n const hasSearch = !!searchElement;\n\n const lastVirtualItemIndex = items ? items.length - 1 : 0;\n\n const rowVirtualizer = useVirtual({\n size: items !== null ? items.length : 0,\n parentRef,\n estimateSize: useCallback(() => itemHeight, [itemHeight]),\n overscan,\n });\n\n const focusSearchBar = useCallback(() => {\n rowVirtualizer.scrollToIndex(0);\n searchRef.current?.focus?.();\n }, [rowVirtualizer]);\n\n /**\n * Scrolls to the menu item with the index provided and\n * then manually focuses it using a side effect in useEffect\n */\n const focusMenuItem = useCallback(\n (index: number) => {\n rowVirtualizer.scrollToIndex(index);\n setNextFocusValue(index);\n },\n [rowVirtualizer]\n );\n\n const handleKeyboardFocusInteraction = useCallback(\n (direction: 'next' | 'previous') => {\n if (focusedItemIndex.current === null || focusedItemIndex.current === undefined) {\n return;\n }\n const nextIndex =\n direction === 'next' ? focusedItemIndex.current + 1 : focusedItemIndex.current - 1;\n const shouldWrap =\n (direction === 'next' && focusedItemIndex.current === lastVirtualItemIndex) ||\n (direction === 'previous' && focusedItemIndex.current === 0);\n if (shouldWrap) {\n // we are at the end of the list so we will\n // scroll back to the beginning of the list\n if (hasSearch) {\n focusSearchBar();\n } else {\n // if at end, wrap to beginning, else focus last item\n focusMenuItem(direction === 'next' ? 0 : lastVirtualItemIndex);\n }\n return;\n }\n switch (direction) {\n case 'next':\n rowVirtualizer.scrollToIndex(nextIndex);\n focusManager.focusNext();\n break;\n case 'previous':\n rowVirtualizer.scrollToIndex(nextIndex);\n focusManager.focusPrevious();\n break;\n default:\n break;\n }\n },\n [focusManager, focusMenuItem, focusSearchBar, hasSearch, lastVirtualItemIndex, rowVirtualizer]\n );\n\n const getItemProps = useCallback(\n (itemElem: ReactElement, index: number) => {\n const childProps = itemElem.props as MenuItemProps<T>;\n switch (itemElem.type) {\n case MenuItem:\n case MenuItemLink:\n return {\n className: cx(childProps.className, menuItemClassName),\n // set focus on the first menu item if there is no search input, and set in the tab order\n onKeyDown: childProps.disabled\n ? () => undefined\n : (e: KeyboardEvent) =>\n handleKeyboardFocusKeydown(e, {\n handleFocusBackward: handleKeyboardFocusInteraction,\n handleFocusForward: handleKeyboardFocusInteraction,\n }),\n onFocus: chainEventHandlers(childProps.onFocus, () => {\n focusedItemIndex.current = index;\n }),\n id: createItemId(index, menuId.current),\n onBlur: chainEventHandlers(childProps.onBlur, () => {\n focusedItemIndex.current = null;\n }),\n onClick: childProps.disabled\n ? () => undefined\n : chainEventHandlers(childProps.onClick, () => {\n onSelect?.(childProps.item as T);\n }),\n } as MenuItemProps<T>;\n default:\n return {};\n }\n },\n [handleKeyboardFocusInteraction, menuItemClassName, onSelect]\n );\n\n useEffect(() => {\n if (nextFocusValue !== null) {\n requestAnimationFrame(() => {\n const element = getNodeForIndex(nextFocusValue, menuId.current);\n element?.focus();\n });\n setNextFocusValue(null);\n }\n }, [nextFocusValue]);\n\n /**\n * Calls handleFocusForward when the user is attempting to focus forward using\n * tab or arrow keys. Calls handleFocusBackward when the users wants to move backward.\n */\n const handleKeyboardFocusKeydown = (\n e: KeyboardEvent,\n callbacks: Record<\n 'handleFocusForward' | 'handleFocusBackward',\n (direction: 'next' | 'previous') => void\n >\n ) => {\n const keyOps = ['Tab', 'ArrowUp', 'ArrowDown'];\n if (keyOps.includes(e.key)) {\n e.preventDefault();\n e.stopPropagation();\n if ((e.key === 'Tab' && e.shiftKey) || e.key === 'ArrowUp') {\n callbacks.handleFocusBackward?.('previous');\n } else if (e.key === 'ArrowDown' || e.key === 'Tab') {\n callbacks.handleFocusForward?.('next');\n }\n }\n };\n\n const renderSearch = useMemo(\n () =>\n searchElement\n ? cloneElement(searchElement, {\n onKeyDown: (e: KeyboardEvent) =>\n handleKeyboardFocusKeydown(e, {\n handleFocusBackward: () => focusMenuItem(lastVirtualItemIndex),\n handleFocusForward: () => focusMenuItem(0),\n }),\n ref: searchRef,\n })\n : null,\n [searchElement, lastVirtualItemIndex, focusMenuItem]\n );\n\n const renderItems = useMemo(\n () =>\n rowVirtualizer.virtualItems.map((virtualRow) => {\n if (!items) {\n return null;\n }\n const elem = items[virtualRow.index];\n return (\n <div\n key={virtualRow.index}\n ref={\n elem.type !== MenuItem || elem.type !== MenuItemLink\n ? virtualRow.measureRef\n : undefined\n }\n role=\"presentation\"\n className={cx('VirtualMenu-item')}\n style={{\n transform: `translateY(${virtualRow.start}px)`,\n }}\n >\n {cloneElement(elem, getItemProps(elem, virtualRow.index))}\n </div>\n );\n }),\n [rowVirtualizer.virtualItems, items, getItemProps]\n );\n\n return (\n <>\n {renderSearch}\n <MenuItemList ref={parentRef} role=\"presentation\">\n <div\n role=\"presentation\"\n className=\"VirtualMenu-item-list\"\n style={{\n height: `${rowVirtualizer.totalSize}px`,\n }}\n >\n {renderItems}\n </div>\n </MenuItemList>\n </>\n );\n};\n\nexport { Menu, ItemVirtualizer };\nexport type { MenuProps, ItemVirtualizerProps };\n", "import type { EventHandler, KeyboardEvent, SyntheticEvent } from 'react';\n\nconst createItemId = (index: number, id: string) => `${id}-item-${index}`;\n\nconst getNodeForIndex = (index: number | null, menuId: string) =>\n index === null ? index : document.getElementById(createItemId(index, menuId));\n\nconst handleKeyboardInteractions = (\n event: React.KeyboardEvent,\n keyHandlers: Partial<\n Record<'handleUp' | 'handleDown' | 'handleEnter', (e: KeyboardEvent) => void>\n >\n) => {\n const ops = {\n ArrowUp: keyHandlers.handleUp,\n ArrowDown: keyHandlers.handleDown,\n Enter: keyHandlers.handleEnter,\n } as Record<string, (e: KeyboardEvent) => void | undefined>;\n\n if (ops[event.key]) {\n event.preventDefault();\n ops[event.key]?.call(globalThis, event);\n }\n};\n\nconst chainEventHandlers =\n (...handlers: Array<EventHandler<SyntheticEvent> | undefined>) =>\n (event: SyntheticEvent) => {\n handlers.forEach((h) => typeof h === 'function' && h(event));\n };\n\nexport { createItemId, getNodeForIndex, handleKeyboardInteractions, chainEventHandlers };\n", "enum MenuSize {\n SMALL = 'sm',\n MEDIUM = 'md',\n LARGE = 'lg',\n EXTRA_LARGE = 'xl',\n}\n\nexport { MenuSize };\n"],
|
5
|
+
"mappings": "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",
|
6
6
|
"names": []
|
7
7
|
}
|
package/dist/index.js
CHANGED
@@ -183,13 +183,11 @@ MenuSearch.displayName = "MenuSearch";
|
|
183
183
|
// src/Menu.tsx
|
184
184
|
var import_focus2 = require("@react-aria/focus");
|
185
185
|
var import_clsx3 = __toESM(require("clsx"));
|
186
|
-
var import_lodash_es2 = require("lodash-es");
|
187
186
|
var import_react4 = require("react");
|
188
187
|
var import_react_virtual = require("react-virtual");
|
189
188
|
var import_uuid = require("uuid");
|
190
189
|
|
191
190
|
// src/utils.ts
|
192
|
-
var import_lodash_es = require("lodash-es");
|
193
191
|
var createItemId = (index, id) => `${id}-item-${index}`;
|
194
192
|
var getNodeForIndex = (index, menuId) => index === null ? index : document.getElementById(createItemId(index, menuId));
|
195
193
|
var handleKeyboardInteractions = (event, keyHandlers) => {
|
@@ -204,7 +202,7 @@ var handleKeyboardInteractions = (event, keyHandlers) => {
|
|
204
202
|
}
|
205
203
|
};
|
206
204
|
var chainEventHandlers = (...handlers) => (event) => {
|
207
|
-
handlers.forEach((h) =>
|
205
|
+
handlers.forEach((h) => typeof h === "function" && h(event));
|
208
206
|
};
|
209
207
|
|
210
208
|
// src/Menu.tsx
|
@@ -262,8 +260,8 @@ var Menu = (props) => {
|
|
262
260
|
case MenuItemLink:
|
263
261
|
return {
|
264
262
|
items: items.concat(child.props.disabled ? (0, import_react4.cloneElement)(child, {
|
265
|
-
onClick:
|
266
|
-
onKeyDown:
|
263
|
+
onClick: () => void 0,
|
264
|
+
onKeyDown: () => void 0,
|
267
265
|
tabIndex: -1,
|
268
266
|
disabled: true
|
269
267
|
}) : (0, import_react4.cloneElement)(child, {
|
@@ -338,7 +336,7 @@ var ItemVirtualizer = (props) => {
|
|
338
336
|
setNextFocusValue(index);
|
339
337
|
}, [rowVirtualizer]);
|
340
338
|
const handleKeyboardFocusInteraction = (0, import_react4.useCallback)((direction) => {
|
341
|
-
if (
|
339
|
+
if (focusedItemIndex.current === null || focusedItemIndex.current === void 0) {
|
342
340
|
return;
|
343
341
|
}
|
344
342
|
const nextIndex = direction === "next" ? focusedItemIndex.current + 1 : focusedItemIndex.current - 1;
|
@@ -371,7 +369,7 @@ var ItemVirtualizer = (props) => {
|
|
371
369
|
case MenuItemLink:
|
372
370
|
return {
|
373
371
|
className: (0, import_clsx3.default)(childProps.className, menuItemClassName),
|
374
|
-
onKeyDown: childProps.disabled ?
|
372
|
+
onKeyDown: childProps.disabled ? () => void 0 : (e) => handleKeyboardFocusKeydown(e, {
|
375
373
|
handleFocusBackward: handleKeyboardFocusInteraction,
|
376
374
|
handleFocusForward: handleKeyboardFocusInteraction
|
377
375
|
}),
|
@@ -382,7 +380,7 @@ var ItemVirtualizer = (props) => {
|
|
382
380
|
onBlur: chainEventHandlers(childProps.onBlur, () => {
|
383
381
|
focusedItemIndex.current = null;
|
384
382
|
}),
|
385
|
-
onClick: childProps.disabled ?
|
383
|
+
onClick: childProps.disabled ? () => void 0 : chainEventHandlers(childProps.onClick, () => {
|
386
384
|
onSelect?.(childProps.item);
|
387
385
|
})
|
388
386
|
};
|
package/dist/index.js.map
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"version": 3,
|
3
3
|
"sources": ["../src/index.ts", "../../../scripts/react-shim.js", "../src/MenuBase.tsx", "../src/MenuDivider.tsx", "../src/MenuItem.tsx", "../src/MenuItemList.tsx", "../src/MenuSearch.tsx", "../src/Menu.tsx", "../src/utils.ts", "../src/types.ts"],
|
4
|
-
"sourcesContent": ["export type { MenuBaseProps } from './MenuBase';\nexport type { MenuDividerProps } from './MenuDivider';\nexport type { MenuItemProps, MenuItemLinkProps } from './MenuItem';\nexport type { MenuItemListProps } from './MenuItemList';\nexport type { MenuSearchProps } from './MenuSearch';\nexport type { MenuProps } from './Menu';\nexport { MenuBase } from './MenuBase';\nexport { MenuDivider } from './MenuDivider';\nexport { MenuItem, MenuItemLink } from './MenuItem';\nexport { MenuItemList } from './MenuItemList';\nexport { MenuSearch } from './MenuSearch';\nexport { Menu } from './Menu';\nexport { MenuSize } from './types';\n", "import * as React from 'react';\nexport { React };\n", "import type { MenuSize } from './types';\n\nimport cx from 'clsx';\nimport { forwardRef } from 'react';\n\nimport './styles/Menu.css';\n\ntype MenuBaseProps = React.ComponentPropsWithRef<'div'> & {\n isVirtual?: boolean;\n size?: MenuSize;\n};\n\nconst MenuBase = forwardRef<HTMLDivElement, MenuBaseProps>(\n ({ children, size, isVirtual, ...props }, ref) => {\n const classes = cx('Menu', {\n 'Menu--isVirtual': isVirtual,\n [`MenuSize--${size}`]: size,\n });\n\n return (\n <div {...props} role=\"menu\" className={classes} ref={ref}>\n {children}\n </div>\n );\n }\n);\n\nMenuBase.displayName = 'MenuBase';\n\nexport { MenuBase };\nexport type { MenuBaseProps };\n", "import type { SeparatorProps } from '@react-aria/separator';\n\nimport { useSeparator } from '@react-aria/separator';\n\nimport './styles/Menu.css';\n\ntype MenuDividerProps = SeparatorProps & {\n innerRef?: React.RefObject<HTMLDivElement>;\n};\n\nconst MenuDivider = ({ elementType = 'div', orientation, innerRef }: MenuDividerProps) => {\n const { separatorProps } = useSeparator({\n orientation,\n elementType,\n });\n\n return <div {...separatorProps} ref={innerRef} className=\"Menu-divider\" />;\n};\n\nexport { MenuDivider };\nexport type { MenuDividerProps };\n", "import type { Icon } from '@launchpad-ui/icons';\nimport type { PopoverPlacement } from '@launchpad-ui/popover';\n\nimport { IconSize } from '@launchpad-ui/icons';\nimport { Tooltip } from '@launchpad-ui/tooltip';\nimport { Slot } from '@radix-ui/react-slot';\nimport { FocusRing } from '@react-aria/focus';\nimport cx from 'clsx';\nimport { Link } from 'react-router-dom';\n\nimport './styles/Menu.css';\n\n// Merge two types and get rid of overlapping definitions\ntype Merge<T, U> = Omit<T, keyof U> & U;\n\ntype PropsWithComponent<P, T extends React.ElementType> = P & { component?: T };\n\ntype PolymorphicPropsWithRef<P, T extends React.ElementType> = Merge<\n T extends keyof JSX.IntrinsicElements\n ? React.PropsWithRef<JSX.IntrinsicElements[T]>\n : React.ComponentPropsWithRef<T>,\n PropsWithComponent<P, T>\n>;\n\ntype MenuItemOwnProps = {\n isHighlighted?: boolean;\n icon?: typeof Icon | null;\n disabled?: boolean;\n nested?: boolean;\n groupHeader?: boolean;\n tooltip?: string | React.ReactElement;\n tooltipOptions?: typeof Tooltip;\n tooltipPlacement?: PopoverPlacement;\n asChild?: boolean;\n};\n\nconst defaultElement = 'button';\n\ntype MenuItemProps<\n P,\n T extends React.ElementType = typeof defaultElement\n> = PolymorphicPropsWithRef<\n | (MenuItemOwnProps & {\n item: P; // Infer the type if it is included\n })\n | (MenuItemOwnProps & {\n item?: undefined;\n }),\n T\n>;\n\nconst MenuItem = <P, T extends React.ElementType = typeof defaultElement>({\n ...props\n}: MenuItemProps<P, T>) => {\n const {\n // TODO: remove component prop once we migrate over to asChild format\n component,\n children,\n isHighlighted,\n icon: Icon,\n nested,\n groupHeader,\n item,\n disabled,\n className,\n tooltip,\n role = 'menuitem',\n tooltipPlacement,\n onKeyDown,\n tooltipOptions,\n asChild,\n ...rest\n } = props;\n\n const Component: React.ElementType = component || (asChild ? Slot : defaultElement);\n\n const renderedItem = (\n <FocusRing focusRingClass=\"has-focus\">\n <Component\n {...rest}\n disabled={disabled}\n aria-disabled={disabled ? disabled : undefined}\n className={cx(\n 'Menu-item',\n className,\n { 'is-highlighted': isHighlighted },\n { 'Menu-item--nested': nested },\n { 'Menu-item--header': groupHeader }\n )}\n role={role}\n onKeyDown={onKeyDown}\n >\n {asChild ? (\n children\n ) : (\n <>\n {Icon && (\n <span className=\"Menu-item-icon\">\n <Icon size={IconSize.SMALL} />\n </span>\n )}\n {children}\n </>\n )}\n </Component>\n </FocusRing>\n );\n\n if (tooltip) {\n return (\n <Tooltip\n content={tooltip}\n rootElementStyle={{ display: 'block' }}\n allowBoundaryElementOverflow\n placement={tooltipPlacement ? tooltipPlacement : 'bottom'}\n {...(tooltipOptions || {})}\n >\n {renderedItem}\n </Tooltip>\n );\n }\n\n return renderedItem;\n};\n\ntype MenuItemLinkOwnProps = {\n disabled?: boolean;\n useHistory?: boolean;\n newTab?: boolean;\n};\n\ntype MenuItemLinkProps<P, T extends React.ElementType = typeof Link> =\n | Merge<Omit<MenuItemProps<P, T>, 'component' | 'item'>, MenuItemLinkOwnProps> &\n (\n | {\n item?: undefined;\n }\n | {\n item: P;\n }\n );\n\n// By default, this is a Link component whenever useHistory is\n// explicitly not false\n// TODO: deprecate this component\nconst MenuItemLink = <P, T extends React.ElementType = typeof Link>({\n to,\n disabled = false,\n useHistory = true,\n newTab = false,\n children,\n ...props\n}: MenuItemLinkProps<P, T>) => {\n const finalProps = {\n ...props,\n disabled,\n component: useHistory ? Link : ('a' as const),\n [useHistory ? 'to' : 'href']: disabled ? '' : to,\n rel: newTab ? 'noopener noreferrer' : undefined,\n target: newTab ? '_blank' : undefined,\n };\n\n // Ideally if this item is disabled, it should be a button rather\n // than a link https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/anchor-is-valid.md\n\n return <MenuItem {...finalProps}>{children}</MenuItem>;\n};\n\nexport { MenuItem, MenuItemLink };\nexport type { MenuItemProps, MenuItemLinkProps };\n", "import { forwardRef } from 'react';\n\nimport './styles/Menu.css';\n\ntype MenuItemListProps = Omit<React.ComponentPropsWithRef<'div'>, 'className'>;\n\nconst MenuItemList = forwardRef<HTMLDivElement, MenuItemListProps>(({ children, ...rest }, ref) => (\n <div {...rest} ref={ref} data-test-id=\"menu-item-list\" className=\"Menu-item-list\">\n {children}\n </div>\n));\n\nMenuItemList.displayName = 'MenuItemList';\n\nexport { MenuItemList };\nexport type { MenuItemListProps };\n", "import type { ChangeEvent } from 'react';\n\nimport { forwardRef } from 'react';\n\nimport './styles/Menu.css';\n\ntype MenuSearchProps = {\n ariaLabel?: string;\n value?: string;\n placeholder?: string;\n onChange?(event: ChangeEvent<HTMLInputElement>): void;\n};\n\nconst MenuSearch = forwardRef<HTMLInputElement, MenuSearchProps>((props, ref) => {\n const { ariaLabel, placeholder, ...finalProps } = props;\n\n return (\n <div className=\"Menu-search\">\n <input\n {...finalProps}\n ref={ref}\n className=\"Menu-search-input FormInput FormInput--tiny\"\n type=\"search\"\n autoComplete=\"off\"\n placeholder={placeholder}\n aria-label={ariaLabel || 'Search'}\n />\n <div\n className=\"Menu-search-hidden-placeholder Menu-search-input FormInput FormInput--tiny\"\n aria-hidden=\"true\"\n >\n {placeholder}\n </div>\n </div>\n );\n});\n\nMenuSearch.displayName = 'MenuSearch';\n\nexport { MenuSearch };\nexport type { MenuSearchProps };\n", "import type { MenuItemProps } from './MenuItem';\nimport type { MenuSize } from './types';\nimport type { FocusManager } from '@react-aria/focus';\nimport type { KeyboardEvent, ReactElement } from 'react';\n\nimport { useFocusManager } from '@react-aria/focus';\nimport cx from 'clsx';\nimport { isNil, noop } from 'lodash-es';\nimport { Children, cloneElement, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useVirtual } from 'react-virtual';\nimport { v4 } from 'uuid';\n\nimport { MenuBase } from './MenuBase';\nimport { MenuDivider } from './MenuDivider';\nimport { MenuItem, MenuItemLink } from './MenuItem';\nimport { MenuItemList } from './MenuItemList';\nimport { MenuSearch } from './MenuSearch';\nimport {\n chainEventHandlers,\n createItemId,\n getNodeForIndex,\n handleKeyboardInteractions,\n} from './utils';\n\ntype ControlledMenuProps<T> = {\n children: React.ReactNode;\n onSelect?: (item: T) => void;\n /**\n * Menus items are rendered using react-virtual for\n * additional rendering performance.\n */\n enableVirtualization?: boolean;\n /**\n * Class name to be applied to all MenuItem and MenuItemLink components\n * in the menu.\n */\n menuItemClassName?: string;\n /**\n * Sets the width of the menu. This is especially useful when using virtual items\n * since the width cannot be automatically set by the widest element.\n */\n size?: MenuSize;\n /**\n * Sets the number out of elements rendered outside of the view window\n * when using virtualization\n */\n overscan?: number;\n /**\n * Sets the height for each menu item when using virtualization.\n *\n */\n itemHeight?: number;\n};\n\ntype MenuProps<T extends number | string> = ControlledMenuProps<T>;\n\nconst Menu = <T extends number | string>(props: MenuProps<T>) => {\n const {\n children,\n menuItemClassName,\n onSelect,\n enableVirtualization,\n itemHeight,\n size,\n overscan = 1,\n } = props;\n\n const focusManager = useFocusManager();\n\n const handleArrowDown = useCallback(() => {\n focusManager.focusNext({ wrap: true });\n }, [focusManager]);\n\n const handleArrowUp = useCallback(() => {\n focusManager.focusPrevious({ wrap: true });\n }, [focusManager]);\n\n const reduceItems = useMemo(() => {\n const childrenProps = Children.toArray(children);\n if (enableVirtualization) {\n // the virtualized menu has its own handlers and props\n let searchElem = null;\n let elements: ReactElement[] = [];\n (childrenProps as ReactElement[]).forEach((child: ReactElement) => {\n switch (child.type) {\n case MenuSearch:\n searchElem = child;\n break;\n case MenuItem:\n case MenuItemLink:\n case MenuDivider:\n elements = elements.concat(child);\n break;\n default:\n break;\n }\n });\n return { items: elements, searchElement: searchElem };\n }\n\n return (childrenProps as ReactElement[]).reduce(\n (\n { items, searchElement }: { items: ReactElement[]; searchElement: null | ReactElement },\n child\n ) => {\n switch (child.type) {\n case MenuSearch:\n return {\n items,\n searchElement: cloneElement(child, {\n onKeyDown: (e: KeyboardEvent) =>\n handleKeyboardInteractions(e, {\n handleDown: handleArrowDown,\n handleUp: handleArrowUp,\n }),\n }),\n };\n case MenuItem:\n case MenuItemLink:\n return {\n items: items.concat(\n child.props.disabled\n ? cloneElement(child, {\n onClick: noop,\n onKeyDown: noop,\n tabIndex: -1,\n disabled: true,\n })\n : cloneElement(child, {\n className: cx(child.props.className, menuItemClassName),\n item: child.props.item ?? items.length,\n // set focus on the first menu item if there is no search input, and set in the tab order\n onClick: chainEventHandlers(child.props.onClick, () => {\n onSelect?.(child.props.item ?? items.length);\n }),\n onKeyDown: (e: KeyboardEvent) =>\n handleKeyboardInteractions(e, {\n handleDown: handleArrowDown,\n handleUp: handleArrowUp,\n }),\n })\n ),\n searchElement,\n };\n case MenuDivider:\n return { items: items.concat(child), searchElement };\n default:\n return { items, searchElement };\n }\n },\n { items: [], searchElement: null }\n );\n }, [children, enableVirtualization, menuItemClassName, handleArrowDown, handleArrowUp, onSelect]);\n\n if (enableVirtualization) {\n return (\n <MenuBase isVirtual size={size}>\n <ItemVirtualizer<T>\n items={Children.toArray(reduceItems.items) as ReactElement[]}\n searchElement={reduceItems.searchElement}\n overscan={overscan}\n menuItemClassName={menuItemClassName}\n onSelect={onSelect}\n itemHeight={itemHeight}\n focusManager={focusManager}\n />\n </MenuBase>\n );\n }\n\n return (\n <MenuBase size={size}>\n {reduceItems.searchElement}\n <MenuItemList role=\"presentation\">{reduceItems.items}</MenuItemList>\n </MenuBase>\n );\n};\n\ntype ItemVirtualizerProps<T> = Omit<ControlledMenuProps<T>, 'children'> & {\n items: ReactElement[] | null;\n searchElement?: React.ReactElement | null;\n focusManager: FocusManager;\n};\n\nconst ItemVirtualizer = <T extends number | string>(props: ItemVirtualizerProps<T>) => {\n const {\n overscan,\n searchElement,\n itemHeight = 33,\n menuItemClassName,\n items: items,\n focusManager,\n onSelect,\n } = props;\n\n const menuId = useRef(`menu-ctrl-${v4()}`);\n\n const focusedItemIndex = useRef<number | null>(null);\n const parentRef = useRef<HTMLDivElement | null>(null);\n const searchRef = useRef<HTMLInputElement>();\n\n const [nextFocusValue, setNextFocusValue] = useState<number | null>(null);\n\n const hasSearch = !!searchElement;\n\n const lastVirtualItemIndex = items ? items.length - 1 : 0;\n\n const rowVirtualizer = useVirtual({\n size: items !== null ? items.length : 0,\n parentRef,\n estimateSize: useCallback(() => itemHeight, [itemHeight]),\n overscan,\n });\n\n const focusSearchBar = useCallback(() => {\n rowVirtualizer.scrollToIndex(0);\n searchRef.current?.focus?.();\n }, [rowVirtualizer]);\n\n /**\n * Scrolls to the menu item with the index provided and\n * then manually focuses it using a side effect in useEffect\n */\n const focusMenuItem = useCallback(\n (index: number) => {\n rowVirtualizer.scrollToIndex(index);\n setNextFocusValue(index);\n },\n [rowVirtualizer]\n );\n\n const handleKeyboardFocusInteraction = useCallback(\n (direction: 'next' | 'previous') => {\n if (isNil(focusedItemIndex.current)) {\n return;\n }\n const nextIndex =\n direction === 'next' ? focusedItemIndex.current + 1 : focusedItemIndex.current - 1;\n const shouldWrap =\n (direction === 'next' && focusedItemIndex.current === lastVirtualItemIndex) ||\n (direction === 'previous' && focusedItemIndex.current === 0);\n if (shouldWrap) {\n // we are at the end of the list so we will\n // scroll back to the beginning of the list\n if (hasSearch) {\n focusSearchBar();\n } else {\n // if at end, wrap to beginning, else focus last item\n focusMenuItem(direction === 'next' ? 0 : lastVirtualItemIndex);\n }\n return;\n }\n switch (direction) {\n case 'next':\n rowVirtualizer.scrollToIndex(nextIndex);\n focusManager.focusNext();\n break;\n case 'previous':\n rowVirtualizer.scrollToIndex(nextIndex);\n focusManager.focusPrevious();\n break;\n default:\n break;\n }\n },\n [focusManager, focusMenuItem, focusSearchBar, hasSearch, lastVirtualItemIndex, rowVirtualizer]\n );\n\n const getItemProps = useCallback(\n (itemElem: ReactElement, index: number) => {\n const childProps = itemElem.props as MenuItemProps<T>;\n switch (itemElem.type) {\n case MenuItem:\n case MenuItemLink:\n return {\n className: cx(childProps.className, menuItemClassName),\n // set focus on the first menu item if there is no search input, and set in the tab order\n onKeyDown: childProps.disabled\n ? noop\n : (e: KeyboardEvent) =>\n handleKeyboardFocusKeydown(e, {\n handleFocusBackward: handleKeyboardFocusInteraction,\n handleFocusForward: handleKeyboardFocusInteraction,\n }),\n onFocus: chainEventHandlers(childProps.onFocus, () => {\n focusedItemIndex.current = index;\n }),\n id: createItemId(index, menuId.current),\n onBlur: chainEventHandlers(childProps.onBlur, () => {\n focusedItemIndex.current = null;\n }),\n onClick: childProps.disabled\n ? noop\n : chainEventHandlers(childProps.onClick, () => {\n onSelect?.(childProps.item as T);\n }),\n } as MenuItemProps<T>;\n default:\n return {};\n }\n },\n [handleKeyboardFocusInteraction, menuItemClassName, onSelect]\n );\n\n useEffect(() => {\n if (nextFocusValue !== null) {\n requestAnimationFrame(() => {\n const element = getNodeForIndex(nextFocusValue, menuId.current);\n element?.focus();\n });\n setNextFocusValue(null);\n }\n }, [nextFocusValue]);\n\n /**\n * Calls handleFocusForward when the user is attempting to focus forward using\n * tab or arrow keys. Calls handleFocusBackward when the users wants to move backward.\n */\n const handleKeyboardFocusKeydown = (\n e: KeyboardEvent,\n callbacks: Record<\n 'handleFocusForward' | 'handleFocusBackward',\n (direction: 'next' | 'previous') => void\n >\n ) => {\n const keyOps = ['Tab', 'ArrowUp', 'ArrowDown'];\n if (keyOps.includes(e.key)) {\n e.preventDefault();\n e.stopPropagation();\n if ((e.key === 'Tab' && e.shiftKey) || e.key === 'ArrowUp') {\n callbacks.handleFocusBackward?.('previous');\n } else if (e.key === 'ArrowDown' || e.key === 'Tab') {\n callbacks.handleFocusForward?.('next');\n }\n }\n };\n\n const renderSearch = useMemo(\n () =>\n searchElement\n ? cloneElement(searchElement, {\n onKeyDown: (e: KeyboardEvent) =>\n handleKeyboardFocusKeydown(e, {\n handleFocusBackward: () => focusMenuItem(lastVirtualItemIndex),\n handleFocusForward: () => focusMenuItem(0),\n }),\n ref: searchRef,\n })\n : null,\n [searchElement, lastVirtualItemIndex, focusMenuItem]\n );\n\n const renderItems = useMemo(\n () =>\n rowVirtualizer.virtualItems.map((virtualRow) => {\n if (!items) {\n return null;\n }\n const elem = items[virtualRow.index];\n return (\n <div\n key={virtualRow.index}\n ref={\n elem.type !== MenuItem || elem.type !== MenuItemLink\n ? virtualRow.measureRef\n : undefined\n }\n role=\"presentation\"\n className={cx('VirtualMenu-item')}\n style={{\n transform: `translateY(${virtualRow.start}px)`,\n }}\n >\n {cloneElement(elem, getItemProps(elem, virtualRow.index))}\n </div>\n );\n }),\n [rowVirtualizer.virtualItems, items, getItemProps]\n );\n\n return (\n <>\n {renderSearch}\n <MenuItemList ref={parentRef} role=\"presentation\">\n <div\n role=\"presentation\"\n className=\"VirtualMenu-item-list\"\n style={{\n height: `${rowVirtualizer.totalSize}px`,\n }}\n >\n {renderItems}\n </div>\n </MenuItemList>\n </>\n );\n};\n\nexport { Menu, ItemVirtualizer };\nexport type { MenuProps, ItemVirtualizerProps };\n", "import type { KeyboardEvent } from 'react';\n\nimport { isFunction } from 'lodash-es';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyFunction = (...args: any[]) => any;\n\nconst createItemId = (index: number, id: string) => `${id}-item-${index}`;\n\nconst getNodeForIndex = (index: number | null, menuId: string) =>\n index === null ? index : document.getElementById(createItemId(index, menuId));\n\nconst handleKeyboardInteractions = (\n event: React.KeyboardEvent,\n keyHandlers: Partial<\n Record<'handleUp' | 'handleDown' | 'handleEnter', (e: KeyboardEvent) => void>\n >\n) => {\n const ops = {\n ArrowUp: keyHandlers.handleUp,\n ArrowDown: keyHandlers.handleDown,\n Enter: keyHandlers.handleEnter,\n } as Record<string, (e: KeyboardEvent) => void | undefined>;\n\n if (ops[event.key]) {\n event.preventDefault();\n ops[event.key]?.call(globalThis, event);\n }\n};\n\nconst chainEventHandlers =\n (...handlers: Array<AnyFunction | undefined>) =>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (event: any) => {\n handlers.forEach((h) => isFunction(h) && h(event));\n };\n\nexport { createItemId, getNodeForIndex, handleKeyboardInteractions, chainEventHandlers };\n", "enum MenuSize {\n SMALL = 'sm',\n MEDIUM = 'md',\n LARGE = 'lg',\n EXTRA_LARGE = 'xl',\n}\n\nexport { MenuSize };\n"],
|
5
|
-
"mappings": "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
|
4
|
+
"sourcesContent": ["export type { MenuBaseProps } from './MenuBase';\nexport type { MenuDividerProps } from './MenuDivider';\nexport type { MenuItemProps, MenuItemLinkProps } from './MenuItem';\nexport type { MenuItemListProps } from './MenuItemList';\nexport type { MenuSearchProps } from './MenuSearch';\nexport type { MenuProps } from './Menu';\n/* c8 ignore start */\nexport { MenuBase } from './MenuBase';\n/* c8 ignore stop */\nexport { MenuDivider } from './MenuDivider';\nexport { MenuItem, MenuItemLink } from './MenuItem';\n/* c8 ignore start */\nexport { MenuItemList } from './MenuItemList';\n/* c8 ignore stop */\nexport { MenuSearch } from './MenuSearch';\nexport { Menu } from './Menu';\nexport { MenuSize } from './types';\n", "import * as React from 'react';\nexport { React };\n", "import type { MenuSize } from './types';\n\nimport cx from 'clsx';\nimport { forwardRef } from 'react';\n\nimport './styles/Menu.css';\n\ntype MenuBaseProps = React.ComponentPropsWithRef<'div'> & {\n isVirtual?: boolean;\n size?: MenuSize;\n};\n\nconst MenuBase = forwardRef<HTMLDivElement, MenuBaseProps>(\n ({ children, size, isVirtual, ...props }, ref) => {\n const classes = cx('Menu', {\n 'Menu--isVirtual': isVirtual,\n [`MenuSize--${size}`]: size,\n });\n\n return (\n <div {...props} role=\"menu\" className={classes} ref={ref}>\n {children}\n </div>\n );\n }\n);\n\nMenuBase.displayName = 'MenuBase';\n\nexport { MenuBase };\nexport type { MenuBaseProps };\n", "import type { SeparatorProps } from '@react-aria/separator';\n\nimport { useSeparator } from '@react-aria/separator';\n\nimport './styles/Menu.css';\n\ntype MenuDividerProps = SeparatorProps & {\n innerRef?: React.RefObject<HTMLDivElement>;\n};\n\nconst MenuDivider = ({ elementType = 'div', orientation, innerRef }: MenuDividerProps) => {\n const { separatorProps } = useSeparator({\n orientation,\n elementType,\n });\n\n return <div {...separatorProps} ref={innerRef} className=\"Menu-divider\" />;\n};\n\nexport { MenuDivider };\nexport type { MenuDividerProps };\n", "import type { Icon } from '@launchpad-ui/icons';\nimport type { PopoverPlacement } from '@launchpad-ui/popover';\n\nimport { IconSize } from '@launchpad-ui/icons';\nimport { Tooltip } from '@launchpad-ui/tooltip';\nimport { Slot } from '@radix-ui/react-slot';\nimport { FocusRing } from '@react-aria/focus';\nimport cx from 'clsx';\nimport { Link } from 'react-router-dom';\n\nimport './styles/Menu.css';\n\n// Merge two types and get rid of overlapping definitions\ntype Merge<T, U> = Omit<T, keyof U> & U;\n\ntype PropsWithComponent<P, T extends React.ElementType> = P & { component?: T };\n\ntype PolymorphicPropsWithRef<P, T extends React.ElementType> = Merge<\n T extends keyof JSX.IntrinsicElements\n ? React.PropsWithRef<JSX.IntrinsicElements[T]>\n : React.ComponentPropsWithRef<T>,\n PropsWithComponent<P, T>\n>;\n\ntype MenuItemOwnProps = {\n isHighlighted?: boolean;\n icon?: typeof Icon | null;\n disabled?: boolean;\n nested?: boolean;\n groupHeader?: boolean;\n tooltip?: string | React.ReactElement;\n tooltipOptions?: typeof Tooltip;\n tooltipPlacement?: PopoverPlacement;\n asChild?: boolean;\n};\n\nconst defaultElement = 'button';\n\ntype MenuItemProps<\n P,\n T extends React.ElementType = typeof defaultElement\n> = PolymorphicPropsWithRef<\n | (MenuItemOwnProps & {\n item: P; // Infer the type if it is included\n })\n | (MenuItemOwnProps & {\n item?: undefined;\n }),\n T\n>;\n\nconst MenuItem = <P, T extends React.ElementType = typeof defaultElement>({\n ...props\n}: MenuItemProps<P, T>) => {\n const {\n // TODO: remove component prop once we migrate over to asChild format\n component,\n children,\n isHighlighted,\n icon: Icon,\n nested,\n groupHeader,\n item,\n disabled,\n className,\n tooltip,\n role = 'menuitem',\n tooltipPlacement,\n onKeyDown,\n tooltipOptions,\n asChild,\n ...rest\n } = props;\n\n const Component: React.ElementType = component || (asChild ? Slot : defaultElement);\n\n const renderedItem = (\n <FocusRing focusRingClass=\"has-focus\">\n <Component\n {...rest}\n disabled={disabled}\n aria-disabled={disabled ? disabled : undefined}\n className={cx(\n 'Menu-item',\n className,\n { 'is-highlighted': isHighlighted },\n { 'Menu-item--nested': nested },\n { 'Menu-item--header': groupHeader }\n )}\n role={role}\n onKeyDown={onKeyDown}\n >\n {asChild ? (\n children\n ) : (\n <>\n {Icon && (\n <span className=\"Menu-item-icon\">\n <Icon size={IconSize.SMALL} />\n </span>\n )}\n {children}\n </>\n )}\n </Component>\n </FocusRing>\n );\n\n if (tooltip) {\n return (\n <Tooltip\n content={tooltip}\n rootElementStyle={{ display: 'block' }}\n allowBoundaryElementOverflow\n placement={tooltipPlacement ? tooltipPlacement : 'bottom'}\n {...(tooltipOptions || {})}\n >\n {renderedItem}\n </Tooltip>\n );\n }\n\n return renderedItem;\n};\n\ntype MenuItemLinkOwnProps = {\n disabled?: boolean;\n useHistory?: boolean;\n newTab?: boolean;\n};\n\ntype MenuItemLinkProps<P, T extends React.ElementType = typeof Link> =\n | Merge<Omit<MenuItemProps<P, T>, 'component' | 'item'>, MenuItemLinkOwnProps> &\n (\n | {\n item?: undefined;\n }\n | {\n item: P;\n }\n );\n\n// By default, this is a Link component whenever useHistory is\n// explicitly not false\n// TODO: deprecate this component\nconst MenuItemLink = <P, T extends React.ElementType = typeof Link>({\n to,\n disabled = false,\n useHistory = true,\n newTab = false,\n children,\n ...props\n}: MenuItemLinkProps<P, T>) => {\n const finalProps = {\n ...props,\n disabled,\n component: useHistory ? Link : ('a' as const),\n [useHistory ? 'to' : 'href']: disabled ? '' : to,\n rel: newTab ? 'noopener noreferrer' : undefined,\n target: newTab ? '_blank' : undefined,\n };\n\n // Ideally if this item is disabled, it should be a button rather\n // than a link https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/anchor-is-valid.md\n\n return <MenuItem {...finalProps}>{children}</MenuItem>;\n};\n\nexport { MenuItem, MenuItemLink };\nexport type { MenuItemProps, MenuItemLinkProps };\n", "import { forwardRef } from 'react';\n\nimport './styles/Menu.css';\n\ntype MenuItemListProps = Omit<React.ComponentPropsWithRef<'div'>, 'className'>;\n\nconst MenuItemList = forwardRef<HTMLDivElement, MenuItemListProps>(({ children, ...rest }, ref) => (\n <div {...rest} ref={ref} data-test-id=\"menu-item-list\" className=\"Menu-item-list\">\n {children}\n </div>\n));\n\nMenuItemList.displayName = 'MenuItemList';\n\nexport { MenuItemList };\nexport type { MenuItemListProps };\n", "import type { ChangeEvent } from 'react';\n\nimport { forwardRef } from 'react';\n\nimport './styles/Menu.css';\n\ntype MenuSearchProps = {\n ariaLabel?: string;\n value?: string;\n placeholder?: string;\n onChange?(event: ChangeEvent<HTMLInputElement>): void;\n};\n\nconst MenuSearch = forwardRef<HTMLInputElement, MenuSearchProps>((props, ref) => {\n const { ariaLabel, placeholder, ...finalProps } = props;\n\n return (\n <div className=\"Menu-search\">\n <input\n {...finalProps}\n ref={ref}\n className=\"Menu-search-input FormInput FormInput--tiny\"\n type=\"search\"\n autoComplete=\"off\"\n placeholder={placeholder}\n aria-label={ariaLabel || 'Search'}\n />\n <div\n className=\"Menu-search-hidden-placeholder Menu-search-input FormInput FormInput--tiny\"\n aria-hidden=\"true\"\n >\n {placeholder}\n </div>\n </div>\n );\n});\n\nMenuSearch.displayName = 'MenuSearch';\n\nexport { MenuSearch };\nexport type { MenuSearchProps };\n", "import type { MenuItemProps } from './MenuItem';\nimport type { MenuSize } from './types';\nimport type { FocusManager } from '@react-aria/focus';\nimport type { KeyboardEvent, ReactElement } from 'react';\n\nimport { useFocusManager } from '@react-aria/focus';\nimport cx from 'clsx';\nimport { Children, cloneElement, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useVirtual } from 'react-virtual';\nimport { v4 } from 'uuid';\n\nimport { MenuBase } from './MenuBase';\nimport { MenuDivider } from './MenuDivider';\nimport { MenuItem, MenuItemLink } from './MenuItem';\nimport { MenuItemList } from './MenuItemList';\nimport { MenuSearch } from './MenuSearch';\nimport {\n chainEventHandlers,\n createItemId,\n getNodeForIndex,\n handleKeyboardInteractions,\n} from './utils';\n\ntype ControlledMenuProps<T> = {\n children: React.ReactNode;\n onSelect?: (item: T) => void;\n /**\n * Menus items are rendered using react-virtual for\n * additional rendering performance.\n */\n enableVirtualization?: boolean;\n /**\n * Class name to be applied to all MenuItem and MenuItemLink components\n * in the menu.\n */\n menuItemClassName?: string;\n /**\n * Sets the width of the menu. This is especially useful when using virtual items\n * since the width cannot be automatically set by the widest element.\n */\n size?: MenuSize;\n /**\n * Sets the number out of elements rendered outside of the view window\n * when using virtualization\n */\n overscan?: number;\n /**\n * Sets the height for each menu item when using virtualization.\n *\n */\n itemHeight?: number;\n};\n\ntype MenuProps<T extends number | string> = ControlledMenuProps<T>;\n\nconst Menu = <T extends number | string>(props: MenuProps<T>) => {\n const {\n children,\n menuItemClassName,\n onSelect,\n enableVirtualization,\n itemHeight,\n size,\n overscan = 1,\n } = props;\n\n const focusManager = useFocusManager();\n\n const handleArrowDown = useCallback(() => {\n focusManager.focusNext({ wrap: true });\n }, [focusManager]);\n\n const handleArrowUp = useCallback(() => {\n focusManager.focusPrevious({ wrap: true });\n }, [focusManager]);\n\n const reduceItems = useMemo(() => {\n const childrenProps = Children.toArray(children);\n if (enableVirtualization) {\n // the virtualized menu has its own handlers and props\n let searchElem = null;\n let elements: ReactElement[] = [];\n (childrenProps as ReactElement[]).forEach((child: ReactElement) => {\n switch (child.type) {\n case MenuSearch:\n searchElem = child;\n break;\n case MenuItem:\n case MenuItemLink:\n case MenuDivider:\n elements = elements.concat(child);\n break;\n default:\n break;\n }\n });\n return { items: elements, searchElement: searchElem };\n }\n\n return (childrenProps as ReactElement[]).reduce(\n (\n { items, searchElement }: { items: ReactElement[]; searchElement: null | ReactElement },\n child\n ) => {\n switch (child.type) {\n case MenuSearch:\n return {\n items,\n searchElement: cloneElement(child, {\n onKeyDown: (e: KeyboardEvent) =>\n handleKeyboardInteractions(e, {\n handleDown: handleArrowDown,\n handleUp: handleArrowUp,\n }),\n }),\n };\n case MenuItem:\n case MenuItemLink:\n return {\n items: items.concat(\n child.props.disabled\n ? cloneElement(child, {\n onClick: () => undefined,\n onKeyDown: () => undefined,\n tabIndex: -1,\n disabled: true,\n })\n : cloneElement(child, {\n className: cx(child.props.className, menuItemClassName),\n item: child.props.item ?? items.length,\n // set focus on the first menu item if there is no search input, and set in the tab order\n onClick: chainEventHandlers(child.props.onClick, () => {\n onSelect?.(child.props.item ?? items.length);\n }),\n onKeyDown: (e: KeyboardEvent) =>\n handleKeyboardInteractions(e, {\n handleDown: handleArrowDown,\n handleUp: handleArrowUp,\n }),\n })\n ),\n searchElement,\n };\n case MenuDivider:\n return { items: items.concat(child), searchElement };\n default:\n return { items, searchElement };\n }\n },\n { items: [], searchElement: null }\n );\n }, [children, enableVirtualization, menuItemClassName, handleArrowDown, handleArrowUp, onSelect]);\n\n if (enableVirtualization) {\n return (\n <MenuBase isVirtual size={size}>\n <ItemVirtualizer<T>\n items={Children.toArray(reduceItems.items) as ReactElement[]}\n searchElement={reduceItems.searchElement}\n overscan={overscan}\n menuItemClassName={menuItemClassName}\n onSelect={onSelect}\n itemHeight={itemHeight}\n focusManager={focusManager}\n />\n </MenuBase>\n );\n }\n\n return (\n <MenuBase size={size}>\n {reduceItems.searchElement}\n <MenuItemList role=\"presentation\">{reduceItems.items}</MenuItemList>\n </MenuBase>\n );\n};\n\ntype ItemVirtualizerProps<T> = Omit<ControlledMenuProps<T>, 'children'> & {\n items: ReactElement[] | null;\n searchElement?: React.ReactElement | null;\n focusManager: FocusManager;\n};\n\nconst ItemVirtualizer = <T extends number | string>(props: ItemVirtualizerProps<T>) => {\n const {\n overscan,\n searchElement,\n itemHeight = 33,\n menuItemClassName,\n items: items,\n focusManager,\n onSelect,\n } = props;\n\n const menuId = useRef(`menu-ctrl-${v4()}`);\n\n const focusedItemIndex = useRef<number | null>(null);\n const parentRef = useRef<HTMLDivElement | null>(null);\n const searchRef = useRef<HTMLInputElement>();\n\n const [nextFocusValue, setNextFocusValue] = useState<number | null>(null);\n\n const hasSearch = !!searchElement;\n\n const lastVirtualItemIndex = items ? items.length - 1 : 0;\n\n const rowVirtualizer = useVirtual({\n size: items !== null ? items.length : 0,\n parentRef,\n estimateSize: useCallback(() => itemHeight, [itemHeight]),\n overscan,\n });\n\n const focusSearchBar = useCallback(() => {\n rowVirtualizer.scrollToIndex(0);\n searchRef.current?.focus?.();\n }, [rowVirtualizer]);\n\n /**\n * Scrolls to the menu item with the index provided and\n * then manually focuses it using a side effect in useEffect\n */\n const focusMenuItem = useCallback(\n (index: number) => {\n rowVirtualizer.scrollToIndex(index);\n setNextFocusValue(index);\n },\n [rowVirtualizer]\n );\n\n const handleKeyboardFocusInteraction = useCallback(\n (direction: 'next' | 'previous') => {\n if (focusedItemIndex.current === null || focusedItemIndex.current === undefined) {\n return;\n }\n const nextIndex =\n direction === 'next' ? focusedItemIndex.current + 1 : focusedItemIndex.current - 1;\n const shouldWrap =\n (direction === 'next' && focusedItemIndex.current === lastVirtualItemIndex) ||\n (direction === 'previous' && focusedItemIndex.current === 0);\n if (shouldWrap) {\n // we are at the end of the list so we will\n // scroll back to the beginning of the list\n if (hasSearch) {\n focusSearchBar();\n } else {\n // if at end, wrap to beginning, else focus last item\n focusMenuItem(direction === 'next' ? 0 : lastVirtualItemIndex);\n }\n return;\n }\n switch (direction) {\n case 'next':\n rowVirtualizer.scrollToIndex(nextIndex);\n focusManager.focusNext();\n break;\n case 'previous':\n rowVirtualizer.scrollToIndex(nextIndex);\n focusManager.focusPrevious();\n break;\n default:\n break;\n }\n },\n [focusManager, focusMenuItem, focusSearchBar, hasSearch, lastVirtualItemIndex, rowVirtualizer]\n );\n\n const getItemProps = useCallback(\n (itemElem: ReactElement, index: number) => {\n const childProps = itemElem.props as MenuItemProps<T>;\n switch (itemElem.type) {\n case MenuItem:\n case MenuItemLink:\n return {\n className: cx(childProps.className, menuItemClassName),\n // set focus on the first menu item if there is no search input, and set in the tab order\n onKeyDown: childProps.disabled\n ? () => undefined\n : (e: KeyboardEvent) =>\n handleKeyboardFocusKeydown(e, {\n handleFocusBackward: handleKeyboardFocusInteraction,\n handleFocusForward: handleKeyboardFocusInteraction,\n }),\n onFocus: chainEventHandlers(childProps.onFocus, () => {\n focusedItemIndex.current = index;\n }),\n id: createItemId(index, menuId.current),\n onBlur: chainEventHandlers(childProps.onBlur, () => {\n focusedItemIndex.current = null;\n }),\n onClick: childProps.disabled\n ? () => undefined\n : chainEventHandlers(childProps.onClick, () => {\n onSelect?.(childProps.item as T);\n }),\n } as MenuItemProps<T>;\n default:\n return {};\n }\n },\n [handleKeyboardFocusInteraction, menuItemClassName, onSelect]\n );\n\n useEffect(() => {\n if (nextFocusValue !== null) {\n requestAnimationFrame(() => {\n const element = getNodeForIndex(nextFocusValue, menuId.current);\n element?.focus();\n });\n setNextFocusValue(null);\n }\n }, [nextFocusValue]);\n\n /**\n * Calls handleFocusForward when the user is attempting to focus forward using\n * tab or arrow keys. Calls handleFocusBackward when the users wants to move backward.\n */\n const handleKeyboardFocusKeydown = (\n e: KeyboardEvent,\n callbacks: Record<\n 'handleFocusForward' | 'handleFocusBackward',\n (direction: 'next' | 'previous') => void\n >\n ) => {\n const keyOps = ['Tab', 'ArrowUp', 'ArrowDown'];\n if (keyOps.includes(e.key)) {\n e.preventDefault();\n e.stopPropagation();\n if ((e.key === 'Tab' && e.shiftKey) || e.key === 'ArrowUp') {\n callbacks.handleFocusBackward?.('previous');\n } else if (e.key === 'ArrowDown' || e.key === 'Tab') {\n callbacks.handleFocusForward?.('next');\n }\n }\n };\n\n const renderSearch = useMemo(\n () =>\n searchElement\n ? cloneElement(searchElement, {\n onKeyDown: (e: KeyboardEvent) =>\n handleKeyboardFocusKeydown(e, {\n handleFocusBackward: () => focusMenuItem(lastVirtualItemIndex),\n handleFocusForward: () => focusMenuItem(0),\n }),\n ref: searchRef,\n })\n : null,\n [searchElement, lastVirtualItemIndex, focusMenuItem]\n );\n\n const renderItems = useMemo(\n () =>\n rowVirtualizer.virtualItems.map((virtualRow) => {\n if (!items) {\n return null;\n }\n const elem = items[virtualRow.index];\n return (\n <div\n key={virtualRow.index}\n ref={\n elem.type !== MenuItem || elem.type !== MenuItemLink\n ? virtualRow.measureRef\n : undefined\n }\n role=\"presentation\"\n className={cx('VirtualMenu-item')}\n style={{\n transform: `translateY(${virtualRow.start}px)`,\n }}\n >\n {cloneElement(elem, getItemProps(elem, virtualRow.index))}\n </div>\n );\n }),\n [rowVirtualizer.virtualItems, items, getItemProps]\n );\n\n return (\n <>\n {renderSearch}\n <MenuItemList ref={parentRef} role=\"presentation\">\n <div\n role=\"presentation\"\n className=\"VirtualMenu-item-list\"\n style={{\n height: `${rowVirtualizer.totalSize}px`,\n }}\n >\n {renderItems}\n </div>\n </MenuItemList>\n </>\n );\n};\n\nexport { Menu, ItemVirtualizer };\nexport type { MenuProps, ItemVirtualizerProps };\n", "import type { EventHandler, KeyboardEvent, SyntheticEvent } from 'react';\n\nconst createItemId = (index: number, id: string) => `${id}-item-${index}`;\n\nconst getNodeForIndex = (index: number | null, menuId: string) =>\n index === null ? index : document.getElementById(createItemId(index, menuId));\n\nconst handleKeyboardInteractions = (\n event: React.KeyboardEvent,\n keyHandlers: Partial<\n Record<'handleUp' | 'handleDown' | 'handleEnter', (e: KeyboardEvent) => void>\n >\n) => {\n const ops = {\n ArrowUp: keyHandlers.handleUp,\n ArrowDown: keyHandlers.handleDown,\n Enter: keyHandlers.handleEnter,\n } as Record<string, (e: KeyboardEvent) => void | undefined>;\n\n if (ops[event.key]) {\n event.preventDefault();\n ops[event.key]?.call(globalThis, event);\n }\n};\n\nconst chainEventHandlers =\n (...handlers: Array<EventHandler<SyntheticEvent> | undefined>) =>\n (event: SyntheticEvent) => {\n handlers.forEach((h) => typeof h === 'function' && h(event));\n };\n\nexport { createItemId, getNodeForIndex, handleKeyboardInteractions, chainEventHandlers };\n", "enum MenuSize {\n SMALL = 'sm',\n MEDIUM = 'md',\n LARGE = 'lg',\n EXTRA_LARGE = 'xl',\n}\n\nexport { MenuSize };\n"],
|
5
|
+
"mappings": "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",
|
6
6
|
"names": []
|
7
7
|
}
|
package/dist/utils.d.ts
CHANGED
@@ -1,8 +1,7 @@
|
|
1
|
-
import type { KeyboardEvent } from 'react';
|
2
|
-
declare type AnyFunction = (...args: any[]) => any;
|
1
|
+
import type { EventHandler, KeyboardEvent, SyntheticEvent } from 'react';
|
3
2
|
declare const createItemId: (index: number, id: string) => string;
|
4
3
|
declare const getNodeForIndex: (index: number | null, menuId: string) => HTMLElement | null;
|
5
4
|
declare const handleKeyboardInteractions: (event: React.KeyboardEvent, keyHandlers: Partial<Record<"handleUp" | "handleDown" | "handleEnter", (e: KeyboardEvent) => void>>) => void;
|
6
|
-
declare const chainEventHandlers: (...handlers: Array<
|
5
|
+
declare const chainEventHandlers: (...handlers: Array<EventHandler<SyntheticEvent> | undefined>) => (event: SyntheticEvent) => void;
|
7
6
|
export { createItemId, getNodeForIndex, handleKeyboardInteractions, chainEventHandlers };
|
8
7
|
//# sourceMappingURL=utils.d.ts.map
|
package/dist/utils.d.ts.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAEzE,QAAA,MAAM,YAAY,UAAW,MAAM,MAAM,MAAM,WAA0B,CAAC;AAE1E,QAAA,MAAM,eAAe,UAAW,MAAM,GAAG,IAAI,UAAU,MAAM,uBACkB,CAAC;AAEhF,QAAA,MAAM,0BAA0B,UACvB,mBAAmB,6EAE8B,aAAa,KAAK,IAAI,WAa/E,CAAC;AAEF,QAAA,MAAM,kBAAkB,gBACR,MAAM,aAAa,cAAc,CAAC,GAAG,SAAS,CAAC,aACrD,cAAc,SAErB,CAAC;AAEJ,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,0BAA0B,EAAE,kBAAkB,EAAE,CAAC"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@launchpad-ui/menu",
|
3
|
-
"version": "0.3.
|
3
|
+
"version": "0.3.5",
|
4
4
|
"status": "beta",
|
5
5
|
"publishConfig": {
|
6
6
|
"access": "public"
|
@@ -27,14 +27,13 @@
|
|
27
27
|
"source": "src/index.ts",
|
28
28
|
"dependencies": {
|
29
29
|
"@launchpad-ui/icons": "~0.2.3",
|
30
|
-
"@launchpad-ui/popover": "~0.5.
|
30
|
+
"@launchpad-ui/popover": "~0.5.5",
|
31
31
|
"@launchpad-ui/tokens": "~0.1.5",
|
32
|
-
"@launchpad-ui/tooltip": "~0.3.
|
32
|
+
"@launchpad-ui/tooltip": "~0.3.7",
|
33
33
|
"@radix-ui/react-slot": "^1.0.0",
|
34
34
|
"@react-aria/focus": "^3.7.0",
|
35
35
|
"@react-aria/separator": "^3.2.0",
|
36
36
|
"clsx": "^1.2.0",
|
37
|
-
"lodash-es": "^4.17.21",
|
38
37
|
"react-router-dom": "^6.3.0",
|
39
38
|
"react-virtual": "^2.10.4",
|
40
39
|
"uuid": "^8.3.2"
|
@@ -44,7 +43,6 @@
|
|
44
43
|
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
45
44
|
},
|
46
45
|
"devDependencies": {
|
47
|
-
"@types/lodash-es": "^4.17.6",
|
48
46
|
"@types/uuid": "^8.3.4",
|
49
47
|
"react": "^18.2.0",
|
50
48
|
"react-dom": "^18.2.0"
|