@launchpad-ui/menu 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/dist/Menu.d.ts +42 -0
- package/dist/Menu.d.ts.map +1 -0
- package/dist/MenuBase.d.ts +7 -0
- package/dist/MenuBase.d.ts.map +1 -0
- package/dist/MenuDivider.d.ts +10 -0
- package/dist/MenuDivider.d.ts.map +1 -0
- package/dist/MenuItem.d.ts +47 -0
- package/dist/MenuItem.d.ts.map +1 -0
- package/dist/MenuItemList.d.ts +7 -0
- package/dist/MenuItemList.d.ts.map +1 -0
- package/dist/MenuSearch.d.ts +12 -0
- package/dist/MenuSearch.d.ts.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.es.js +418 -0
- package/dist/index.es.js.map +7 -0
- package/dist/index.js +453 -0
- package/dist/index.js.map +7 -0
- package/dist/styles.css +2 -0
- package/dist/styles.css.map +1 -0
- package/dist/utils.d.ts +9 -0
- package/dist/utils.d.ts.map +1 -0
- package/package.json +58 -0
@@ -0,0 +1,7 @@
|
|
1
|
+
{
|
2
|
+
"version": 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"],
|
4
|
+
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import cx from 'clsx';\nimport { forwardRef } from 'react';\n\nimport './styles.css';\n\ntype MenuBaseProps = React.ComponentPropsWithRef<'div'>;\n\n// This is the pure presentational component that contains menu items\nconst MenuBase = forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ children, ...props }, ref) => {\n const className = cx('Menu', props.className);\n return (\n <div {...props} className={className} ref={ref}>\n {children}\n </div>\n );\n }\n);\n\nMenuBase.displayName = 'MenuBase';\n\nexport { MenuBase };\nexport type { MenuBaseProps };\n", "import { SeparatorProps, useSeparator } from '@react-aria/separator';\n\nimport './styles.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 { PopoverPlacement } from '@launchpad-ui/popover';\n\nimport { Icon, IconSize } from '@launchpad-ui/icons';\nimport { Tooltip } from '@launchpad-ui/tooltip';\nimport { FocusRing } from '@react-aria/focus';\nimport cx from 'clsx';\nimport { Link } from 'react-router-dom';\n\nimport './styles.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 innerRef?: React.RefObject<HTMLDivElement>;\n tooltip?: string | React.ReactElement;\n tooltipOptions?: typeof Tooltip;\n tooltipPlacement?: PopoverPlacement;\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 component,\n children,\n isHighlighted,\n icon: Icon,\n nested,\n groupHeader,\n item,\n disabled,\n className,\n innerRef,\n tooltip,\n role = 'menuitem',\n tooltipPlacement,\n onKeyDown,\n tooltipOptions,\n ...rest\n } = props;\n\n const Component: React.ElementType = component || defaultElement;\n\n const renderedItem = (\n <FocusRing focusRingClass=\"has-focus\">\n <Component\n {...rest}\n ref={innerRef}\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 { 'u-fw-medium': groupHeader }\n )}\n role={role}\n onKeyDown={onKeyDown}\n >\n {Icon && (\n <span className=\"Menu-item-icon\">\n <Icon size={IconSize.SMALL} />\n </span>\n )}\n {children}\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\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.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.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 { KeyboardEvent, ReactElement } from 'react';\n\nimport { FocusManager, 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, MenuItemProps } 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 menuWidth?: 'tiny' | 'small' | 'med' | 'large' | 'xLarge';\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 menuWidth,\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 const menuClassName = cx(\n { 'Menu--isVirtual': enableVirtualization },\n { [`MenuSize--${menuWidth}`]: menuWidth }\n );\n\n if (enableVirtualization) {\n return (\n <MenuBase role=\"menu\" className={menuClassName}>\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 role=\"menu\" className={menuClassName}>\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 normalizeIndex = (index: undefined | null | number, delta: number, count: number) => {\n if (index === undefined || index === null) {\n if (delta < 0) {\n return count - 1;\n } else {\n return 0;\n }\n }\n\n let normalized = index + delta;\n if (normalized > count - 1) {\n normalized = 0;\n } else if (normalized < 0) {\n normalized = count - 1;\n }\n return normalized;\n};\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(this, 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 {\n createItemId,\n getNodeForIndex,\n normalizeIndex,\n handleKeyboardInteractions,\n chainEventHandlers,\n};\n"],
|
5
|
+
"mappings": "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",
|
6
|
+
"names": []
|
7
|
+
}
|
package/dist/index.js
ADDED
@@ -0,0 +1,453 @@
|
|
1
|
+
var __create = Object.create;
|
2
|
+
var __defProp = Object.defineProperty;
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
7
|
+
var __export = (target, all) => {
|
8
|
+
for (var name in all)
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
10
|
+
};
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
13
|
+
for (let key of __getOwnPropNames(from))
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
16
|
+
}
|
17
|
+
return to;
|
18
|
+
};
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod));
|
20
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
21
|
+
|
22
|
+
// src/index.ts
|
23
|
+
var src_exports = {};
|
24
|
+
__export(src_exports, {
|
25
|
+
Menu: () => Menu,
|
26
|
+
MenuBase: () => MenuBase,
|
27
|
+
MenuDivider: () => MenuDivider,
|
28
|
+
MenuItem: () => MenuItem,
|
29
|
+
MenuItemLink: () => MenuItemLink,
|
30
|
+
MenuItemList: () => MenuItemList,
|
31
|
+
MenuSearch: () => MenuSearch
|
32
|
+
});
|
33
|
+
module.exports = __toCommonJS(src_exports);
|
34
|
+
|
35
|
+
// ../../scripts/react-shim.js
|
36
|
+
var React = __toESM(require("react"));
|
37
|
+
|
38
|
+
// src/MenuBase.tsx
|
39
|
+
var import_clsx = __toESM(require("clsx"));
|
40
|
+
var import_react = require("react");
|
41
|
+
var import_styles = require("./styles.css");
|
42
|
+
var MenuBase = (0, import_react.forwardRef)(({ children, ...props }, ref) => {
|
43
|
+
const className = (0, import_clsx.default)("Menu", props.className);
|
44
|
+
return /* @__PURE__ */ React.createElement("div", {
|
45
|
+
...props,
|
46
|
+
className,
|
47
|
+
ref
|
48
|
+
}, children);
|
49
|
+
});
|
50
|
+
MenuBase.displayName = "MenuBase";
|
51
|
+
|
52
|
+
// src/MenuDivider.tsx
|
53
|
+
var import_separator = require("@react-aria/separator");
|
54
|
+
var import_styles2 = require("./styles.css");
|
55
|
+
var MenuDivider = ({ elementType = "div", orientation, innerRef }) => {
|
56
|
+
const { separatorProps } = (0, import_separator.useSeparator)({
|
57
|
+
orientation,
|
58
|
+
elementType
|
59
|
+
});
|
60
|
+
return /* @__PURE__ */ React.createElement("div", {
|
61
|
+
...separatorProps,
|
62
|
+
ref: innerRef,
|
63
|
+
className: "Menu-divider"
|
64
|
+
});
|
65
|
+
};
|
66
|
+
|
67
|
+
// src/MenuItem.tsx
|
68
|
+
var import_icons = require("@launchpad-ui/icons");
|
69
|
+
var import_tooltip = require("@launchpad-ui/tooltip");
|
70
|
+
var import_focus = require("@react-aria/focus");
|
71
|
+
var import_clsx2 = __toESM(require("clsx"));
|
72
|
+
var import_react_router_dom = require("react-router-dom");
|
73
|
+
var import_styles3 = require("./styles.css");
|
74
|
+
var defaultElement = "button";
|
75
|
+
var MenuItem = ({
|
76
|
+
...props
|
77
|
+
}) => {
|
78
|
+
const {
|
79
|
+
component,
|
80
|
+
children,
|
81
|
+
isHighlighted,
|
82
|
+
icon: Icon2,
|
83
|
+
nested,
|
84
|
+
groupHeader,
|
85
|
+
item,
|
86
|
+
disabled,
|
87
|
+
className,
|
88
|
+
innerRef,
|
89
|
+
tooltip,
|
90
|
+
role = "menuitem",
|
91
|
+
tooltipPlacement,
|
92
|
+
onKeyDown,
|
93
|
+
tooltipOptions,
|
94
|
+
...rest
|
95
|
+
} = props;
|
96
|
+
const Component = component || defaultElement;
|
97
|
+
const renderedItem = /* @__PURE__ */ React.createElement(import_focus.FocusRing, {
|
98
|
+
focusRingClass: "has-focus"
|
99
|
+
}, /* @__PURE__ */ React.createElement(Component, {
|
100
|
+
...rest,
|
101
|
+
ref: innerRef,
|
102
|
+
disabled,
|
103
|
+
"aria-disabled": disabled ? disabled : void 0,
|
104
|
+
className: (0, import_clsx2.default)("Menu-item", className, { "is-highlighted": isHighlighted }, { "Menu-item--nested": nested }, { "u-fw-medium": groupHeader }),
|
105
|
+
role,
|
106
|
+
onKeyDown
|
107
|
+
}, Icon2 && /* @__PURE__ */ React.createElement("span", {
|
108
|
+
className: "Menu-item-icon"
|
109
|
+
}, /* @__PURE__ */ React.createElement(Icon2, {
|
110
|
+
size: import_icons.IconSize.SMALL
|
111
|
+
})), children));
|
112
|
+
if (tooltip) {
|
113
|
+
return /* @__PURE__ */ React.createElement(import_tooltip.Tooltip, {
|
114
|
+
content: tooltip,
|
115
|
+
rootElementStyle: { display: "block" },
|
116
|
+
allowBoundaryElementOverflow: true,
|
117
|
+
placement: tooltipPlacement ? tooltipPlacement : "bottom",
|
118
|
+
...tooltipOptions || {}
|
119
|
+
}, renderedItem);
|
120
|
+
}
|
121
|
+
return renderedItem;
|
122
|
+
};
|
123
|
+
var MenuItemLink = ({
|
124
|
+
to,
|
125
|
+
disabled = false,
|
126
|
+
useHistory = true,
|
127
|
+
newTab = false,
|
128
|
+
children,
|
129
|
+
...props
|
130
|
+
}) => {
|
131
|
+
const finalProps = {
|
132
|
+
...props,
|
133
|
+
disabled,
|
134
|
+
component: useHistory ? import_react_router_dom.Link : "a",
|
135
|
+
[useHistory ? "to" : "href"]: disabled ? "" : to,
|
136
|
+
rel: newTab ? "noopener noreferrer" : void 0,
|
137
|
+
target: newTab ? "_blank" : void 0
|
138
|
+
};
|
139
|
+
return /* @__PURE__ */ React.createElement(MenuItem, {
|
140
|
+
...finalProps
|
141
|
+
}, children);
|
142
|
+
};
|
143
|
+
|
144
|
+
// src/MenuItemList.tsx
|
145
|
+
var import_react2 = require("react");
|
146
|
+
var import_styles4 = require("./styles.css");
|
147
|
+
var MenuItemList = (0, import_react2.forwardRef)(({ children, ...rest }, ref) => /* @__PURE__ */ React.createElement("div", {
|
148
|
+
...rest,
|
149
|
+
ref,
|
150
|
+
"data-test-id": "menu-item-list",
|
151
|
+
className: "Menu-item-list"
|
152
|
+
}, children));
|
153
|
+
MenuItemList.displayName = "MenuItemList";
|
154
|
+
|
155
|
+
// src/MenuSearch.tsx
|
156
|
+
var import_react3 = require("react");
|
157
|
+
var import_styles5 = require("./styles.css");
|
158
|
+
var MenuSearch = (0, import_react3.forwardRef)((props, ref) => {
|
159
|
+
const { ariaLabel, placeholder, ...finalProps } = props;
|
160
|
+
return /* @__PURE__ */ React.createElement("div", {
|
161
|
+
className: "Menu-search"
|
162
|
+
}, /* @__PURE__ */ React.createElement("input", {
|
163
|
+
...finalProps,
|
164
|
+
ref,
|
165
|
+
className: "Menu-search-input FormInput FormInput--tiny",
|
166
|
+
type: "search",
|
167
|
+
autoComplete: "off",
|
168
|
+
placeholder,
|
169
|
+
"aria-label": ariaLabel || "Search"
|
170
|
+
}), /* @__PURE__ */ React.createElement("div", {
|
171
|
+
className: "Menu-search-hidden-placeholder Menu-search-input FormInput FormInput--tiny",
|
172
|
+
"aria-hidden": "true"
|
173
|
+
}, placeholder));
|
174
|
+
});
|
175
|
+
MenuSearch.displayName = "MenuSearch";
|
176
|
+
|
177
|
+
// src/Menu.tsx
|
178
|
+
var import_focus2 = require("@react-aria/focus");
|
179
|
+
var import_clsx3 = __toESM(require("clsx"));
|
180
|
+
var import_lodash_es2 = require("lodash-es");
|
181
|
+
var import_react4 = require("react");
|
182
|
+
var import_react_virtual = require("react-virtual");
|
183
|
+
var import_uuid = require("uuid");
|
184
|
+
|
185
|
+
// src/utils.ts
|
186
|
+
var import_lodash_es = require("lodash-es");
|
187
|
+
var createItemId = (index, id) => `${id}-item-${index}`;
|
188
|
+
var getNodeForIndex = (index, menuId) => index === null ? index : document.getElementById(createItemId(index, menuId));
|
189
|
+
var handleKeyboardInteractions = (event, keyHandlers) => {
|
190
|
+
const ops = {
|
191
|
+
ArrowUp: keyHandlers.handleUp,
|
192
|
+
ArrowDown: keyHandlers.handleDown,
|
193
|
+
Enter: keyHandlers.handleEnter
|
194
|
+
};
|
195
|
+
if (ops[event.key]) {
|
196
|
+
event.preventDefault();
|
197
|
+
ops[event.key]?.call(void 0, event);
|
198
|
+
}
|
199
|
+
};
|
200
|
+
var chainEventHandlers = (...handlers) => (event) => {
|
201
|
+
handlers.forEach((h) => (0, import_lodash_es.isFunction)(h) && h(event));
|
202
|
+
};
|
203
|
+
|
204
|
+
// src/Menu.tsx
|
205
|
+
var Menu = (props) => {
|
206
|
+
const {
|
207
|
+
children,
|
208
|
+
menuItemClassName,
|
209
|
+
onSelect,
|
210
|
+
enableVirtualization,
|
211
|
+
itemHeight,
|
212
|
+
menuWidth,
|
213
|
+
overscan = 1
|
214
|
+
} = props;
|
215
|
+
const focusManager = (0, import_focus2.useFocusManager)();
|
216
|
+
const handleArrowDown = (0, import_react4.useCallback)(() => {
|
217
|
+
focusManager.focusNext({ wrap: true });
|
218
|
+
}, [focusManager]);
|
219
|
+
const handleArrowUp = (0, import_react4.useCallback)(() => {
|
220
|
+
focusManager.focusPrevious({ wrap: true });
|
221
|
+
}, [focusManager]);
|
222
|
+
const reduceItems = (0, import_react4.useMemo)(() => {
|
223
|
+
const childrenProps = import_react4.Children.toArray(children);
|
224
|
+
if (enableVirtualization) {
|
225
|
+
let searchElem = null;
|
226
|
+
let elements = [];
|
227
|
+
childrenProps.forEach((child) => {
|
228
|
+
switch (child.type) {
|
229
|
+
case MenuSearch:
|
230
|
+
searchElem = child;
|
231
|
+
break;
|
232
|
+
case MenuItem:
|
233
|
+
case MenuItemLink:
|
234
|
+
case MenuDivider:
|
235
|
+
elements = elements.concat(child);
|
236
|
+
break;
|
237
|
+
default:
|
238
|
+
break;
|
239
|
+
}
|
240
|
+
});
|
241
|
+
return { items: elements, searchElement: searchElem };
|
242
|
+
}
|
243
|
+
return childrenProps.reduce(({ items, searchElement }, child) => {
|
244
|
+
switch (child.type) {
|
245
|
+
case MenuSearch:
|
246
|
+
return {
|
247
|
+
items,
|
248
|
+
searchElement: (0, import_react4.cloneElement)(child, {
|
249
|
+
onKeyDown: (e) => handleKeyboardInteractions(e, {
|
250
|
+
handleDown: handleArrowDown,
|
251
|
+
handleUp: handleArrowUp
|
252
|
+
})
|
253
|
+
})
|
254
|
+
};
|
255
|
+
case MenuItem:
|
256
|
+
case MenuItemLink:
|
257
|
+
return {
|
258
|
+
items: items.concat(child.props.disabled ? (0, import_react4.cloneElement)(child, {
|
259
|
+
onClick: import_lodash_es2.noop,
|
260
|
+
onKeyDown: import_lodash_es2.noop,
|
261
|
+
tabIndex: -1,
|
262
|
+
disabled: true
|
263
|
+
}) : (0, import_react4.cloneElement)(child, {
|
264
|
+
className: (0, import_clsx3.default)(child.props.className, menuItemClassName),
|
265
|
+
item: child.props.item ?? items.length,
|
266
|
+
onClick: chainEventHandlers(child.props.onClick, () => {
|
267
|
+
onSelect?.(child.props.item ?? items.length);
|
268
|
+
}),
|
269
|
+
onKeyDown: (e) => handleKeyboardInteractions(e, {
|
270
|
+
handleDown: handleArrowDown,
|
271
|
+
handleUp: handleArrowUp
|
272
|
+
})
|
273
|
+
})),
|
274
|
+
searchElement
|
275
|
+
};
|
276
|
+
case MenuDivider:
|
277
|
+
return { items: items.concat(child), searchElement };
|
278
|
+
default:
|
279
|
+
return { items, searchElement };
|
280
|
+
}
|
281
|
+
}, { items: [], searchElement: null });
|
282
|
+
}, [children, enableVirtualization, menuItemClassName, handleArrowDown, handleArrowUp, onSelect]);
|
283
|
+
const menuClassName = (0, import_clsx3.default)({ "Menu--isVirtual": enableVirtualization }, { [`MenuSize--${menuWidth}`]: menuWidth });
|
284
|
+
if (enableVirtualization) {
|
285
|
+
return /* @__PURE__ */ React.createElement(MenuBase, {
|
286
|
+
role: "menu",
|
287
|
+
className: menuClassName
|
288
|
+
}, /* @__PURE__ */ React.createElement(ItemVirtualizer, {
|
289
|
+
items: import_react4.Children.toArray(reduceItems.items),
|
290
|
+
searchElement: reduceItems.searchElement,
|
291
|
+
overscan,
|
292
|
+
menuItemClassName,
|
293
|
+
onSelect,
|
294
|
+
itemHeight,
|
295
|
+
focusManager
|
296
|
+
}));
|
297
|
+
}
|
298
|
+
return /* @__PURE__ */ React.createElement(MenuBase, {
|
299
|
+
role: "menu",
|
300
|
+
className: menuClassName
|
301
|
+
}, reduceItems.searchElement, /* @__PURE__ */ React.createElement(MenuItemList, {
|
302
|
+
role: "presentation"
|
303
|
+
}, reduceItems.items));
|
304
|
+
};
|
305
|
+
var ItemVirtualizer = (props) => {
|
306
|
+
const {
|
307
|
+
overscan,
|
308
|
+
searchElement,
|
309
|
+
itemHeight = 33,
|
310
|
+
menuItemClassName,
|
311
|
+
items,
|
312
|
+
focusManager,
|
313
|
+
onSelect
|
314
|
+
} = props;
|
315
|
+
const menuId = (0, import_react4.useRef)(`menu-ctrl-${(0, import_uuid.v4)()}`);
|
316
|
+
const focusedItemIndex = (0, import_react4.useRef)(null);
|
317
|
+
const parentRef = (0, import_react4.useRef)(null);
|
318
|
+
const searchRef = (0, import_react4.useRef)();
|
319
|
+
const [nextFocusValue, setNextFocusValue] = (0, import_react4.useState)(null);
|
320
|
+
const hasSearch = !!searchElement;
|
321
|
+
const lastVirtualItemIndex = items ? items.length - 1 : 0;
|
322
|
+
const rowVirtualizer = (0, import_react_virtual.useVirtual)({
|
323
|
+
size: items !== null ? items.length : 0,
|
324
|
+
parentRef,
|
325
|
+
estimateSize: (0, import_react4.useCallback)(() => itemHeight, [itemHeight]),
|
326
|
+
overscan
|
327
|
+
});
|
328
|
+
const focusSearchBar = (0, import_react4.useCallback)(() => {
|
329
|
+
rowVirtualizer.scrollToIndex(0);
|
330
|
+
searchRef.current?.focus?.();
|
331
|
+
}, [rowVirtualizer]);
|
332
|
+
const focusMenuItem = (0, import_react4.useCallback)((index) => {
|
333
|
+
rowVirtualizer.scrollToIndex(index);
|
334
|
+
setNextFocusValue(index);
|
335
|
+
}, [rowVirtualizer]);
|
336
|
+
const handleKeyboardFocusInteraction = (0, import_react4.useCallback)((direction) => {
|
337
|
+
if ((0, import_lodash_es2.isNil)(focusedItemIndex.current)) {
|
338
|
+
return;
|
339
|
+
}
|
340
|
+
const nextIndex = direction === "next" ? focusedItemIndex.current + 1 : focusedItemIndex.current - 1;
|
341
|
+
const shouldWrap = direction === "next" && focusedItemIndex.current === lastVirtualItemIndex || direction === "previous" && focusedItemIndex.current === 0;
|
342
|
+
if (shouldWrap) {
|
343
|
+
if (hasSearch) {
|
344
|
+
focusSearchBar();
|
345
|
+
} else {
|
346
|
+
focusMenuItem(direction === "next" ? 0 : lastVirtualItemIndex);
|
347
|
+
}
|
348
|
+
return;
|
349
|
+
}
|
350
|
+
switch (direction) {
|
351
|
+
case "next":
|
352
|
+
rowVirtualizer.scrollToIndex(nextIndex);
|
353
|
+
focusManager.focusNext();
|
354
|
+
break;
|
355
|
+
case "previous":
|
356
|
+
rowVirtualizer.scrollToIndex(nextIndex);
|
357
|
+
focusManager.focusPrevious();
|
358
|
+
break;
|
359
|
+
default:
|
360
|
+
break;
|
361
|
+
}
|
362
|
+
}, [focusManager, focusMenuItem, focusSearchBar, hasSearch, lastVirtualItemIndex, rowVirtualizer]);
|
363
|
+
const getItemProps = (0, import_react4.useCallback)((itemElem, index) => {
|
364
|
+
const childProps = itemElem.props;
|
365
|
+
switch (itemElem.type) {
|
366
|
+
case MenuItem:
|
367
|
+
case MenuItemLink:
|
368
|
+
return {
|
369
|
+
className: (0, import_clsx3.default)(childProps.className, menuItemClassName),
|
370
|
+
onKeyDown: childProps.disabled ? import_lodash_es2.noop : (e) => handleKeyboardFocusKeydown(e, {
|
371
|
+
handleFocusBackward: handleKeyboardFocusInteraction,
|
372
|
+
handleFocusForward: handleKeyboardFocusInteraction
|
373
|
+
}),
|
374
|
+
onFocus: chainEventHandlers(childProps.onFocus, () => {
|
375
|
+
focusedItemIndex.current = index;
|
376
|
+
}),
|
377
|
+
id: createItemId(index, menuId.current),
|
378
|
+
onBlur: chainEventHandlers(childProps.onBlur, () => {
|
379
|
+
focusedItemIndex.current = null;
|
380
|
+
}),
|
381
|
+
onClick: childProps.disabled ? import_lodash_es2.noop : chainEventHandlers(childProps.onClick, () => {
|
382
|
+
onSelect?.(childProps.item);
|
383
|
+
})
|
384
|
+
};
|
385
|
+
default:
|
386
|
+
return {};
|
387
|
+
}
|
388
|
+
}, [handleKeyboardFocusInteraction, menuItemClassName, onSelect]);
|
389
|
+
(0, import_react4.useEffect)(() => {
|
390
|
+
if (nextFocusValue !== null) {
|
391
|
+
requestAnimationFrame(() => {
|
392
|
+
const element = getNodeForIndex(nextFocusValue, menuId.current);
|
393
|
+
element?.focus();
|
394
|
+
});
|
395
|
+
setNextFocusValue(null);
|
396
|
+
}
|
397
|
+
}, [nextFocusValue]);
|
398
|
+
const handleKeyboardFocusKeydown = (e, callbacks) => {
|
399
|
+
const keyOps = ["Tab", "ArrowUp", "ArrowDown"];
|
400
|
+
if (keyOps.includes(e.key)) {
|
401
|
+
e.preventDefault();
|
402
|
+
e.stopPropagation();
|
403
|
+
if (e.key === "Tab" && e.shiftKey || e.key === "ArrowUp") {
|
404
|
+
callbacks.handleFocusBackward?.("previous");
|
405
|
+
} else if (e.key === "ArrowDown" || e.key === "Tab") {
|
406
|
+
callbacks.handleFocusForward?.("next");
|
407
|
+
}
|
408
|
+
}
|
409
|
+
};
|
410
|
+
const renderSearch = (0, import_react4.useMemo)(() => searchElement ? (0, import_react4.cloneElement)(searchElement, {
|
411
|
+
onKeyDown: (e) => handleKeyboardFocusKeydown(e, {
|
412
|
+
handleFocusBackward: () => focusMenuItem(lastVirtualItemIndex),
|
413
|
+
handleFocusForward: () => focusMenuItem(0)
|
414
|
+
}),
|
415
|
+
ref: searchRef
|
416
|
+
}) : null, [searchElement, lastVirtualItemIndex, focusMenuItem]);
|
417
|
+
const renderItems = (0, import_react4.useMemo)(() => rowVirtualizer.virtualItems.map((virtualRow) => {
|
418
|
+
if (!items) {
|
419
|
+
return null;
|
420
|
+
}
|
421
|
+
const elem = items[virtualRow.index];
|
422
|
+
return /* @__PURE__ */ React.createElement("div", {
|
423
|
+
key: virtualRow.index,
|
424
|
+
ref: elem.type !== MenuItem || elem.type !== MenuItemLink ? virtualRow.measureRef : void 0,
|
425
|
+
role: "presentation",
|
426
|
+
className: (0, import_clsx3.default)("VirtualMenu-item"),
|
427
|
+
style: {
|
428
|
+
transform: `translateY(${virtualRow.start}px)`
|
429
|
+
}
|
430
|
+
}, (0, import_react4.cloneElement)(elem, getItemProps(elem, virtualRow.index)));
|
431
|
+
}), [rowVirtualizer.virtualItems, items, getItemProps]);
|
432
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, renderSearch, /* @__PURE__ */ React.createElement(MenuItemList, {
|
433
|
+
ref: parentRef,
|
434
|
+
role: "presentation"
|
435
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
436
|
+
role: "presentation",
|
437
|
+
className: "VirtualMenu-item-list",
|
438
|
+
style: {
|
439
|
+
height: `${rowVirtualizer.totalSize}px`
|
440
|
+
}
|
441
|
+
}, renderItems)));
|
442
|
+
};
|
443
|
+
// Annotate the CommonJS export names for ESM import in node:
|
444
|
+
0 && (module.exports = {
|
445
|
+
Menu,
|
446
|
+
MenuBase,
|
447
|
+
MenuDivider,
|
448
|
+
MenuItem,
|
449
|
+
MenuItemLink,
|
450
|
+
MenuItemList,
|
451
|
+
MenuSearch
|
452
|
+
});
|
453
|
+
//# sourceMappingURL=index.js.map
|
@@ -0,0 +1,7 @@
|
|
1
|
+
{
|
2
|
+
"version": 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"],
|
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';\n", "import * as React from 'react';\nexport { React };\n", "import cx from 'clsx';\nimport { forwardRef } from 'react';\n\nimport './styles.css';\n\ntype MenuBaseProps = React.ComponentPropsWithRef<'div'>;\n\n// This is the pure presentational component that contains menu items\nconst MenuBase = forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ children, ...props }, ref) => {\n const className = cx('Menu', props.className);\n return (\n <div {...props} className={className} ref={ref}>\n {children}\n </div>\n );\n }\n);\n\nMenuBase.displayName = 'MenuBase';\n\nexport { MenuBase };\nexport type { MenuBaseProps };\n", "import { SeparatorProps, useSeparator } from '@react-aria/separator';\n\nimport './styles.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 { PopoverPlacement } from '@launchpad-ui/popover';\n\nimport { Icon, IconSize } from '@launchpad-ui/icons';\nimport { Tooltip } from '@launchpad-ui/tooltip';\nimport { FocusRing } from '@react-aria/focus';\nimport cx from 'clsx';\nimport { Link } from 'react-router-dom';\n\nimport './styles.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 innerRef?: React.RefObject<HTMLDivElement>;\n tooltip?: string | React.ReactElement;\n tooltipOptions?: typeof Tooltip;\n tooltipPlacement?: PopoverPlacement;\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 component,\n children,\n isHighlighted,\n icon: Icon,\n nested,\n groupHeader,\n item,\n disabled,\n className,\n innerRef,\n tooltip,\n role = 'menuitem',\n tooltipPlacement,\n onKeyDown,\n tooltipOptions,\n ...rest\n } = props;\n\n const Component: React.ElementType = component || defaultElement;\n\n const renderedItem = (\n <FocusRing focusRingClass=\"has-focus\">\n <Component\n {...rest}\n ref={innerRef}\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 { 'u-fw-medium': groupHeader }\n )}\n role={role}\n onKeyDown={onKeyDown}\n >\n {Icon && (\n <span className=\"Menu-item-icon\">\n <Icon size={IconSize.SMALL} />\n </span>\n )}\n {children}\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\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.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.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 { KeyboardEvent, ReactElement } from 'react';\n\nimport { FocusManager, 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, MenuItemProps } 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 menuWidth?: 'tiny' | 'small' | 'med' | 'large' | 'xLarge';\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 menuWidth,\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 const menuClassName = cx(\n { 'Menu--isVirtual': enableVirtualization },\n { [`MenuSize--${menuWidth}`]: menuWidth }\n );\n\n if (enableVirtualization) {\n return (\n <MenuBase role=\"menu\" className={menuClassName}>\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 role=\"menu\" className={menuClassName}>\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 normalizeIndex = (index: undefined | null | number, delta: number, count: number) => {\n if (index === undefined || index === null) {\n if (delta < 0) {\n return count - 1;\n } else {\n return 0;\n }\n }\n\n let normalized = index + delta;\n if (normalized > count - 1) {\n normalized = 0;\n } else if (normalized < 0) {\n normalized = count - 1;\n }\n return normalized;\n};\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(this, 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 {\n createItemId,\n getNodeForIndex,\n normalizeIndex,\n handleKeyboardInteractions,\n chainEventHandlers,\n};\n"],
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,YAAuB;;;ACAvB,kBAAe;AACf,mBAA2B;AAE3B,oBAAO;AAKP,IAAM,WAAW,6BACf,CAAC,EAAE,aAAa,SAAS,QAAQ;AAC/B,QAAM,YAAY,yBAAG,QAAQ,MAAM,SAAS;AAC5C,SACE,oCAAC;AAAA,IAAK,GAAG;AAAA,IAAO;AAAA,IAAsB;AAAA,KACnC,QACH;AAEJ,CACF;AAEA,SAAS,cAAc;;;ACnBvB,uBAA6C;AAE7C,qBAAO;AAMP,IAAM,cAAc,CAAC,EAAE,cAAc,OAAO,aAAa,eAAiC;AACxF,QAAM,EAAE,mBAAmB,mCAAa;AAAA,IACtC;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAO,oCAAC;AAAA,IAAK,GAAG;AAAA,IAAgB,KAAK;AAAA,IAAU,WAAU;AAAA,GAAe;AAC1E;;;ACbA,mBAA+B;AAC/B,qBAAwB;AACxB,mBAA0B;AAC1B,mBAAe;AACf,8BAAqB;AAErB,qBAAO;AA0BP,IAAM,iBAAiB;AAevB,IAAM,WAAW,CAAyD;AAAA,KACrE;AAAA,MACsB;AACzB,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,OACG;AAAA,MACD;AAEJ,QAAM,YAA+B,aAAa;AAElD,QAAM,eACJ,oCAAC;AAAA,IAAU,gBAAe;AAAA,KACxB,oCAAC;AAAA,IACE,GAAG;AAAA,IACJ,KAAK;AAAA,IACL;AAAA,IACA,iBAAe,WAAW,WAAW;AAAA,IACrC,WAAW,0BACT,aACA,WACA,EAAE,kBAAkB,cAAc,GAClC,EAAE,qBAAqB,OAAO,GAC9B,EAAE,eAAe,YAAY,CAC/B;AAAA,IACA;AAAA,IACA;AAAA,KAEC,SACC,oCAAC;AAAA,IAAK,WAAU;AAAA,KACd,oCAAC;AAAA,IAAK,MAAM,sBAAS;AAAA,GAAO,CAC9B,GAED,QACH,CACF;AAGF,MAAI,SAAS;AACX,WACE,oCAAC;AAAA,MACC,SAAS;AAAA,MACT,kBAAkB,EAAE,SAAS,QAAQ;AAAA,MACrC,8BAA4B;AAAA,MAC5B,WAAW,mBAAmB,mBAAmB;AAAA,MAChD,GAAI,kBAAkB,CAAC;AAAA,OAEvB,YACH;AAAA,EAEJ;AAEA,SAAO;AACT;AAqBA,IAAM,eAAe,CAA+C;AAAA,EAClE;AAAA,EACA,WAAW;AAAA,EACX,aAAa;AAAA,EACb,SAAS;AAAA,EACT;AAAA,KACG;AAAA,MAC0B;AAC7B,QAAM,aAAa;AAAA,IACjB,GAAG;AAAA,IACH;AAAA,IACA,WAAW,aAAa,+BAAQ;AAAA,IAChC,CAAC,aAAa,OAAO,SAAS,WAAW,KAAK;AAAA,IAC9C,KAAK,SAAS,wBAAwB;AAAA,IACtC,QAAQ,SAAS,WAAW;AAAA,EAC9B;AAKA,SAAO,oCAAC;AAAA,IAAU,GAAG;AAAA,KAAa,QAAS;AAC7C;;;AC7JA,oBAA2B;AAE3B,qBAAO;AAIP,IAAM,eAAe,8BAA8C,CAAC,EAAE,aAAa,QAAQ,QACzF,oCAAC;AAAA,EAAK,GAAG;AAAA,EAAM;AAAA,EAAU,gBAAa;AAAA,EAAiB,WAAU;AAAA,GAC9D,QACH,CACD;AAED,aAAa,cAAc;;;ACV3B,oBAA2B;AAE3B,qBAAO;AASP,IAAM,aAAa,8BAA8C,CAAC,OAAO,QAAQ;AAC/E,QAAM,EAAE,WAAW,gBAAgB,eAAe;AAElD,SACE,oCAAC;AAAA,IAAI,WAAU;AAAA,KACb,oCAAC;AAAA,IACE,GAAG;AAAA,IACJ;AAAA,IACA,WAAU;AAAA,IACV,MAAK;AAAA,IACL,cAAa;AAAA,IACb;AAAA,IACA,cAAY,aAAa;AAAA,GAC3B,GACA,oCAAC;AAAA,IACC,WAAU;AAAA,IACV,eAAY;AAAA,KAEX,WACH,CACF;AAEJ,CAAC;AAED,WAAW,cAAc;;;ACnCzB,oBAA8C;AAC9C,mBAAe;AACf,wBAA4B;AAC5B,oBAA0F;AAC1F,2BAA2B;AAC3B,kBAAmB;;;ACLnB,uBAA2B;AAK3B,IAAM,eAAe,CAAC,OAAe,OAAe,GAAG,WAAW;AAElE,IAAM,kBAAkB,CAAC,OAAsB,WAC7C,UAAU,OAAO,QAAQ,SAAS,eAAe,aAAa,OAAO,MAAM,CAAC;AAoB9E,IAAM,6BAA6B,CACjC,OACA,gBAGG;AACH,QAAM,MAAM;AAAA,IACV,SAAS,YAAY;AAAA,IACrB,WAAW,YAAY;AAAA,IACvB,OAAO,YAAY;AAAA,EACrB;AAEA,MAAI,IAAI,MAAM,MAAM;AAClB,UAAM,eAAe;AACrB,QAAI,MAAM,MAAM,KAAK,QAAM,KAAK;AAAA,EAClC;AACF;AAEA,IAAM,qBACJ,IAAI,aAEJ,CAAC,UAAe;AACd,WAAS,QAAQ,CAAC,MAAM,iCAAW,CAAC,KAAK,EAAE,KAAK,CAAC;AACnD;;;ADAF,IAAM,OAAO,CAA4B,UAAwB;AAC/D,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,MACT;AAEJ,QAAM,eAAe,mCAAgB;AAErC,QAAM,kBAAkB,+BAAY,MAAM;AACxC,iBAAa,UAAU,EAAE,MAAM,KAAK,CAAC;AAAA,EACvC,GAAG,CAAC,YAAY,CAAC;AAEjB,QAAM,gBAAgB,+BAAY,MAAM;AACtC,iBAAa,cAAc,EAAE,MAAM,KAAK,CAAC;AAAA,EAC3C,GAAG,CAAC,YAAY,CAAC;AAEjB,QAAM,cAAc,2BAAQ,MAAM;AAChC,UAAM,gBAAgB,uBAAS,QAAQ,QAAQ;AAC/C,QAAI,sBAAsB;AAExB,UAAI,aAAa;AACjB,UAAI,WAA2B,CAAC;AAChC,MAAC,cAAiC,QAAQ,CAAC,UAAwB;AACjE,gBAAQ,MAAM;AAAA,eACP;AACH,yBAAa;AACb;AAAA,eACG;AAAA,eACA;AAAA,eACA;AACH,uBAAW,SAAS,OAAO,KAAK;AAChC;AAAA;AAEA;AAAA;AAAA,MAEN,CAAC;AACD,aAAO,EAAE,OAAO,UAAU,eAAe,WAAW;AAAA,IACtD;AAEA,WAAQ,cAAiC,OACvC,CACE,EAAE,OAAO,iBACT,UACG;AACH,cAAQ,MAAM;AAAA,aACP;AACH,iBAAO;AAAA,YACL;AAAA,YACA,eAAe,gCAAa,OAAO;AAAA,cACjC,WAAW,CAAC,MACV,2BAA2B,GAAG;AAAA,gBAC5B,YAAY;AAAA,gBACZ,UAAU;AAAA,cACZ,CAAC;AAAA,YACL,CAAC;AAAA,UACH;AAAA,aACG;AAAA,aACA;AACH,iBAAO;AAAA,YACL,OAAO,MAAM,OACX,MAAM,MAAM,WACR,gCAAa,OAAO;AAAA,cAClB,SAAS;AAAA,cACT,WAAW;AAAA,cACX,UAAU;AAAA,cACV,UAAU;AAAA,YACZ,CAAC,IACD,gCAAa,OAAO;AAAA,cAClB,WAAW,0BAAG,MAAM,MAAM,WAAW,iBAAiB;AAAA,cACtD,MAAM,MAAM,MAAM,QAAQ,MAAM;AAAA,cAEhC,SAAS,mBAAmB,MAAM,MAAM,SAAS,MAAM;AACrD,2BAAW,MAAM,MAAM,QAAQ,MAAM,MAAM;AAAA,cAC7C,CAAC;AAAA,cACD,WAAW,CAAC,MACV,2BAA2B,GAAG;AAAA,gBAC5B,YAAY;AAAA,gBACZ,UAAU;AAAA,cACZ,CAAC;AAAA,YACL,CAAC,CACP;AAAA,YACA;AAAA,UACF;AAAA,aACG;AACH,iBAAO,EAAE,OAAO,MAAM,OAAO,KAAK,GAAG,cAAc;AAAA;AAEnD,iBAAO,EAAE,OAAO,cAAc;AAAA;AAAA,IAEpC,GACA,EAAE,OAAO,CAAC,GAAG,eAAe,KAAK,CACnC;AAAA,EACF,GAAG,CAAC,UAAU,sBAAsB,mBAAmB,iBAAiB,eAAe,QAAQ,CAAC;AAEhG,QAAM,gBAAgB,0BACpB,EAAE,mBAAmB,qBAAqB,GAC1C,EAAE,CAAC,aAAa,cAAc,UAAU,CAC1C;AAEA,MAAI,sBAAsB;AACxB,WACE,oCAAC;AAAA,MAAS,MAAK;AAAA,MAAO,WAAW;AAAA,OAC/B,oCAAC;AAAA,MACC,OAAO,uBAAS,QAAQ,YAAY,KAAK;AAAA,MACzC,eAAe,YAAY;AAAA,MAC3B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,KACF,CACF;AAAA,EAEJ;AAEA,SACE,oCAAC;AAAA,IAAS,MAAK;AAAA,IAAO,WAAW;AAAA,KAC9B,YAAY,eACb,oCAAC;AAAA,IAAa,MAAK;AAAA,KAAgB,YAAY,KAAM,CACvD;AAEJ;AAQA,IAAM,kBAAkB,CAA4B,UAAmC;AACrF,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,MACE;AAEJ,QAAM,SAAS,0BAAO,aAAa,oBAAG,GAAG;AAEzC,QAAM,mBAAmB,0BAAsB,IAAI;AACnD,QAAM,YAAY,0BAA8B,IAAI;AACpD,QAAM,YAAY,0BAAyB;AAE3C,QAAM,CAAC,gBAAgB,qBAAqB,4BAAwB,IAAI;AAExE,QAAM,YAAY,CAAC,CAAC;AAEpB,QAAM,uBAAuB,QAAQ,MAAM,SAAS,IAAI;AAExD,QAAM,iBAAiB,qCAAW;AAAA,IAChC,MAAM,UAAU,OAAO,MAAM,SAAS;AAAA,IACtC;AAAA,IACA,cAAc,+BAAY,MAAM,YAAY,CAAC,UAAU,CAAC;AAAA,IACxD;AAAA,EACF,CAAC;AAED,QAAM,iBAAiB,+BAAY,MAAM;AACvC,mBAAe,cAAc,CAAC;AAC9B,cAAU,SAAS,QAAQ;AAAA,EAC7B,GAAG,CAAC,cAAc,CAAC;AAMnB,QAAM,gBAAgB,+BACpB,CAAC,UAAkB;AACjB,mBAAe,cAAc,KAAK;AAClC,sBAAkB,KAAK;AAAA,EACzB,GACA,CAAC,cAAc,CACjB;AAEA,QAAM,iCAAiC,+BACrC,CAAC,cAAmC;AAClC,QAAI,6BAAM,iBAAiB,OAAO,GAAG;AACnC;AAAA,IACF;AACA,UAAM,YACJ,cAAc,SAAS,iBAAiB,UAAU,IAAI,iBAAiB,UAAU;AACnF,UAAM,aACH,cAAc,UAAU,iBAAiB,YAAY,wBACrD,cAAc,cAAc,iBAAiB,YAAY;AAC5D,QAAI,YAAY;AAGd,UAAI,WAAW;AACb,uBAAe;AAAA,MACjB,OAAO;AAEL,sBAAc,cAAc,SAAS,IAAI,oBAAoB;AAAA,MAC/D;AACA;AAAA,IACF;AACA,YAAQ;AAAA,WACD;AACH,uBAAe,cAAc,SAAS;AACtC,qBAAa,UAAU;AACvB;AAAA,WACG;AACH,uBAAe,cAAc,SAAS;AACtC,qBAAa,cAAc;AAC3B;AAAA;AAEA;AAAA;AAAA,EAEN,GACA,CAAC,cAAc,eAAe,gBAAgB,WAAW,sBAAsB,cAAc,CAC/F;AAEA,QAAM,eAAe,+BACnB,CAAC,UAAwB,UAAkB;AACzC,UAAM,aAAa,SAAS;AAC5B,YAAQ,SAAS;AAAA,WACV;AAAA,WACA;AACH,eAAO;AAAA,UACL,WAAW,0BAAG,WAAW,WAAW,iBAAiB;AAAA,UAErD,WAAW,WAAW,WAClB,yBACA,CAAC,MACC,2BAA2B,GAAG;AAAA,YAC5B,qBAAqB;AAAA,YACrB,oBAAoB;AAAA,UACtB,CAAC;AAAA,UACP,SAAS,mBAAmB,WAAW,SAAS,MAAM;AACpD,6BAAiB,UAAU;AAAA,UAC7B,CAAC;AAAA,UACD,IAAI,aAAa,OAAO,OAAO,OAAO;AAAA,UACtC,QAAQ,mBAAmB,WAAW,QAAQ,MAAM;AAClD,6BAAiB,UAAU;AAAA,UAC7B,CAAC;AAAA,UACD,SAAS,WAAW,WAChB,yBACA,mBAAmB,WAAW,SAAS,MAAM;AAC3C,uBAAW,WAAW,IAAS;AAAA,UACjC,CAAC;AAAA,QACP;AAAA;AAEA,eAAO,CAAC;AAAA;AAAA,EAEd,GACA,CAAC,gCAAgC,mBAAmB,QAAQ,CAC9D;AAEA,+BAAU,MAAM;AACd,QAAI,mBAAmB,MAAM;AAC3B,4BAAsB,MAAM;AAC1B,cAAM,UAAU,gBAAgB,gBAAgB,OAAO,OAAO;AAC9D,iBAAS,MAAM;AAAA,MACjB,CAAC;AACD,wBAAkB,IAAI;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,cAAc,CAAC;AAMnB,QAAM,6BAA6B,CACjC,GACA,cAIG;AACH,UAAM,SAAS,CAAC,OAAO,WAAW,WAAW;AAC7C,QAAI,OAAO,SAAS,EAAE,GAAG,GAAG;AAC1B,QAAE,eAAe;AACjB,QAAE,gBAAgB;AAClB,UAAK,EAAE,QAAQ,SAAS,EAAE,YAAa,EAAE,QAAQ,WAAW;AAC1D,kBAAU,sBAAsB,UAAU;AAAA,MAC5C,WAAW,EAAE,QAAQ,eAAe,EAAE,QAAQ,OAAO;AACnD,kBAAU,qBAAqB,MAAM;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAEA,QAAM,eAAe,2BACnB,MACE,gBACI,gCAAa,eAAe;AAAA,IAC1B,WAAW,CAAC,MACV,2BAA2B,GAAG;AAAA,MAC5B,qBAAqB,MAAM,cAAc,oBAAoB;AAAA,MAC7D,oBAAoB,MAAM,cAAc,CAAC;AAAA,IAC3C,CAAC;AAAA,IACH,KAAK;AAAA,EACP,CAAC,IACD,MACN,CAAC,eAAe,sBAAsB,aAAa,CACrD;AAEA,QAAM,cAAc,2BAClB,MACE,eAAe,aAAa,IAAI,CAAC,eAAe;AAC9C,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,IACT;AACA,UAAM,OAAO,MAAM,WAAW;AAC9B,WACE,oCAAC;AAAA,MACC,KAAK,WAAW;AAAA,MAChB,KACE,KAAK,SAAS,YAAY,KAAK,SAAS,eACpC,WAAW,aACX;AAAA,MAEN,MAAK;AAAA,MACL,WAAW,0BAAG,kBAAkB;AAAA,MAChC,OAAO;AAAA,QACL,WAAW,cAAc,WAAW;AAAA,MACtC;AAAA,OAEC,gCAAa,MAAM,aAAa,MAAM,WAAW,KAAK,CAAC,CAC1D;AAAA,EAEJ,CAAC,GACH,CAAC,eAAe,cAAc,OAAO,YAAY,CACnD;AAEA,SACE,0DACG,cACD,oCAAC;AAAA,IAAa,KAAK;AAAA,IAAW,MAAK;AAAA,KACjC,oCAAC;AAAA,IACC,MAAK;AAAA,IACL,WAAU;AAAA,IACV,OAAO;AAAA,MACL,QAAQ,GAAG,eAAe;AAAA,IAC5B;AAAA,KAEC,WACH,CACF,CACF;AAEJ;",
|
6
|
+
"names": []
|
7
|
+
}
|
package/dist/styles.css
ADDED
@@ -0,0 +1,2 @@
|
|
1
|
+
.Menu:focus{outline:none}:is(.Menu [hidden]:first-child+.Menu .Menu-item-list,.Menu .Menu-item-list:first-child)>.Menu-item:first-child,:is(.Menu [hidden]:first-child+.Menu .Menu-item-list,.Menu .Menu-item-list:first-child)>.VirtualMenu-item-list .VirtualMenu-item:first-child .Menu-item{border-top-left-radius:var(--border-radius);border-top-right-radius:var(--border-radius)}.Menu-item-list{min-width:12rem;max-height:55vh;overflow:auto}.Menu-item-list>.Menu-item:last-child,.Menu-item-list>.VirtualMenu-item-list .VirtualMenu-item:last-child .Menu-item{border-bottom-left-radius:var(--border-radius);border-bottom-right-radius:var(--border-radius)}.Menu-item-list:first-child{border-top-left-radius:var(--border-radius);border-top-right-radius:var(--border-radius)}.Menu-item-list:last-child{border-bottom-left-radius:var(--border-radius);border-bottom-right-radius:var(--border-radius)}.Menu-item{color:var(--color-black-300);background:var(--color-white);cursor:pointer;text-align:left;text-overflow:ellipsis;white-space:nowrap;-webkit-user-select:none;user-select:none;font-size:1.3rem;line-height:inherit;width:100%;border-width:0;outline:none;padding:.6rem 2.5rem;text-decoration:none;display:block;position:relative;overflow:hidden}.Menu .Menu-item:not([disabled],[aria-disabled]):hover:not(:active,.has-focus){background-color:var(--color-gray-100);box-shadow:inset 0 0 0 1px var(--color-gray-600)}.Menu .Menu-item:not([disabled],[aria-disabled]).has-focus{background-color:var(--color-gray-100);box-shadow:inset 0 0 0 2px var(--color-blue-500)}.Menu .Menu-item:not([disabled],[aria-disabled]):active{box-shadow:none;background-color:var(--color-blue-200);color:var(--color-blue-600);text-decoration:none}.Menu a.Menu-item:focus:not(:hover,.has-focus){box-shadow:none;text-decoration:none}.Menu a.Menu-item:active[disabled],.Menu a.Menu-item:active[aria-disabled]{color:var(--color-gray-800);text-decoration:none}.Menu-item--nested{padding-left:4rem}.Menu-item .Gravatar{margin-right:.5rem}.Menu-item.is-highlighted{background-color:var(--color-gray-100);box-shadow:inset 0 0 0 1px var(--color-gray-600)}.Menu-item.is-highlighted:active{background-color:var(--color-blue-200);color:var(--color-blue-600);box-shadow:none}.Menu-item[aria-disabled],.Menu-item[disabled]{color:var(--color-gray-800);cursor:default}.Menu-item-icon{position:absolute;top:50%;left:.5rem;transform:translateY(-50%)}.Menu-divider{border-top:1px solid var(--color-gray-200)}.Menu-search{border-bottom:1px solid var(--color-gray-200);padding:1rem;font-size:1.3rem}.Menu-search:first-child{border-top-left-radius:var(--border-radius);border-top-right-radius:var(--border-radius)}.Menu-clear.Button{color:var(--color-system-red-600);font-size:1.3rem;font-weight:var(--font-weight-medium);width:100%;border-bottom:1px solid var(--color-gray-200);padding:1rem;text-decoration:none}.Menu-clear.Button:active,.Menu-clear.Button:focus,.Menu-clear.Button:hover{box-shadow:unset;color:var(--color-system-red-600);border-bottom-color:var(--color-gray-200);background-color:var(--color-gray-100);outline:none}.Popover-content .Menu-search{width:100%}.Popover-content .Menu-search .Menu-search-hidden-placeholder{height:0;visibility:hidden;border:none;padding-top:0;padding-bottom:0}.Menu--isVirtual{flex-direction:column;align-items:stretch;display:flex}.MenuSize--xLarge{width:32rem}.MenuSize--large{width:24rem}.MenuSize--med{width:16rem}.MenuSize--small{width:12rem}.VirtualMenu-item-list{width:100%;position:relative}.VirtualMenu-item{width:100%;position:absolute;top:0;left:0}
|
2
|
+
/*# sourceMappingURL=styles.css.map */
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"mappings":"AAEE,yBAME,gWAYJ,8DAME,oNAWF,qHAKA,0HAKA,+VAuBI,uKAKA,mJAKA,gKAUA,oFAMA,4HAQJ,qCAIA,wCAIA,kHAIE,oHAOF,0FAMA,gFAOA,yDAIA,yFAMA,kHAKA,uMAUA,6NAUA,yCAIE,oIASF,wEAMA,8BAIA,6BAIA,2BAIA,6BAIA,oDAKA","sources":["src/styles.css"],"sourcesContent":["/* stylelint-disable no-descending-specificity */\n.Menu {\n &:focus {\n outline: none;\n }\n\n & [hidden]:first-child + & .Menu-item-list,\n & .Menu-item-list:first-child {\n & > .Menu-item:first-child {\n border-top-left-radius: var(--border-radius);\n border-top-right-radius: var(--border-radius);\n }\n\n & > .VirtualMenu-item-list .VirtualMenu-item:first-child .Menu-item {\n border-top-left-radius: var(--border-radius);\n border-top-right-radius: var(--border-radius);\n }\n }\n}\n\n.Menu-item-list {\n min-width: 12rem;\n overflow: auto;\n max-height: 55vh;\n\n /* use the child selector due to MenuItems being nested in divs for virtualization */\n & > .Menu-item:last-child {\n border-bottom-left-radius: var(--border-radius);\n border-bottom-right-radius: var(--border-radius);\n }\n\n & > .VirtualMenu-item-list .VirtualMenu-item:last-child .Menu-item {\n border-bottom-left-radius: var(--border-radius);\n border-bottom-right-radius: var(--border-radius);\n }\n}\n\n.Menu-item-list:first-child {\n border-top-left-radius: var(--border-radius);\n border-top-right-radius: var(--border-radius);\n}\n\n.Menu-item-list:last-child {\n border-bottom-left-radius: var(--border-radius);\n border-bottom-right-radius: var(--border-radius);\n}\n\n.Menu-item {\n display: block;\n position: relative;\n color: var(--color-black-300);\n background: var(--color-white);\n text-decoration: none;\n cursor: pointer;\n outline: none;\n padding: 0.6rem 2.5rem;\n text-align: left;\n font-size: 1.3rem;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n user-select: none;\n line-height: inherit;\n border-width: 0;\n width: 100%;\n}\n\n/* stylelint-disable-next-line no-duplicate-selectors */\n.Menu {\n & .Menu-item:not([disabled], [aria-disabled]) {\n &:hover:not(:active, .has-focus) {\n background-color: var(--color-gray-100);\n box-shadow: inset 0 0 0 1px var(--color-gray-600);\n }\n\n &.has-focus {\n background-color: var(--color-gray-100);\n box-shadow: inset 0 0 0 2px var(--color-blue-500);\n }\n\n &:active {\n text-decoration: none;\n box-shadow: none;\n background-color: var(--color-blue-200);\n color: var(--color-blue-600);\n }\n }\n\n /* Override our link styles for MenuItemLink component */\n & a.Menu-item {\n &:focus:not(:hover, .has-focus) {\n text-decoration: none;\n box-shadow: none;\n }\n\n /* Ensures that links that are disabled don't show active styles */\n &:active[disabled],\n &:active[aria-disabled] {\n text-decoration: none;\n color: var(--color-gray-800);\n }\n }\n}\n\n.Menu-item--nested {\n padding-left: 4rem;\n}\n\n.Menu-item .Gravatar {\n margin-right: 0.5rem;\n}\n\n.Menu-item.is-highlighted {\n background-color: var(--color-gray-100);\n box-shadow: inset 0 0 0 1px var(--color-gray-600);\n\n &:active {\n background-color: var(--color-blue-200);\n color: var(--color-blue-600);\n box-shadow: none;\n }\n}\n\n.Menu-item[aria-disabled],\n.Menu-item[disabled] {\n color: var(--color-gray-800);\n cursor: default;\n}\n\n.Menu-item-icon {\n position: absolute;\n left: 0.5rem;\n top: 50%;\n transform: translateY(-50%);\n}\n\n.Menu-divider {\n border-top: 1px solid var(--color-gray-200);\n}\n\n.Menu-search {\n padding: 1rem;\n font-size: 1.3rem;\n border-bottom: 1px solid var(--color-gray-200);\n}\n\n.Menu-search:first-child {\n border-top-left-radius: var(--border-radius);\n border-top-right-radius: var(--border-radius);\n}\n\n.Menu-clear.Button {\n text-decoration: none;\n color: var(--color-system-red-600);\n font-size: 1.3rem;\n font-weight: var(--font-weight-medium);\n padding: 1rem;\n width: 100%;\n border-bottom: 1px solid var(--color-gray-200);\n}\n\n.Menu-clear.Button:active,\n.Menu-clear.Button:focus,\n.Menu-clear.Button:hover {\n outline: none;\n box-shadow: unset;\n color: var(--color-system-red-600);\n border-bottom-color: var(--color-gray-200);\n background-color: var(--color-gray-100);\n}\n\n.Popover-content .Menu-search {\n width: 100%;\n\n /* Removing anything that could give it some height */\n & .Menu-search-hidden-placeholder {\n padding-top: 0;\n padding-bottom: 0;\n height: 0;\n border: none;\n visibility: hidden;\n }\n}\n\n.Menu--isVirtual {\n display: flex;\n align-items: stretch;\n flex-direction: column;\n}\n\n.MenuSize--xLarge {\n width: 32rem;\n}\n\n.MenuSize--large {\n width: 24rem;\n}\n\n.MenuSize--med {\n width: 16rem;\n}\n\n.MenuSize--small {\n width: 12rem;\n}\n\n.VirtualMenu-item-list {\n width: 100%;\n position: relative;\n}\n\n.VirtualMenu-item {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n}\n"],"names":[]}
|
package/dist/utils.d.ts
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
import type { KeyboardEvent } from 'react';
|
2
|
+
declare type AnyFunction = (...args: any[]) => any;
|
3
|
+
declare const createItemId: (index: number, id: string) => string;
|
4
|
+
declare const getNodeForIndex: (index: number | null, menuId: string) => HTMLElement | null;
|
5
|
+
declare const normalizeIndex: (index: undefined | null | number, delta: number, count: number) => number;
|
6
|
+
declare const handleKeyboardInteractions: (event: React.KeyboardEvent, keyHandlers: Partial<Record<"handleUp" | "handleDown" | "handleEnter", (e: KeyboardEvent) => void>>) => void;
|
7
|
+
declare const chainEventHandlers: (...handlers: Array<AnyFunction | undefined>) => (event: any) => void;
|
8
|
+
export { createItemId, getNodeForIndex, normalizeIndex, handleKeyboardInteractions, chainEventHandlers, };
|
9
|
+
//# sourceMappingURL=utils.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAK3C,aAAK,WAAW,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC;AAE3C,QAAA,MAAM,YAAY,UAAW,MAAM,MAAM,MAAM,WAA0B,CAAC;AAE1E,QAAA,MAAM,eAAe,UAAW,MAAM,GAAG,IAAI,UAAU,MAAM,uBACkB,CAAC;AAEhF,QAAA,MAAM,cAAc,UAAW,SAAS,GAAG,IAAI,GAAG,MAAM,SAAS,MAAM,SAAS,MAAM,WAgBrF,CAAC;AAEF,QAAA,MAAM,0BAA0B,UACvB,mBAAmB,6EAE8B,aAAa,KAAK,IAAI,WAa/E,CAAC;AAEF,QAAA,MAAM,kBAAkB,gBACR,MAAM,WAAW,GAAG,SAAS,CAAC,aAEpC,GAAG,SAEV,CAAC;AAEJ,OAAO,EACL,YAAY,EACZ,eAAe,EACf,cAAc,EACd,0BAA0B,EAC1B,kBAAkB,GACnB,CAAC"}
|