@vuu-ui/vuu-popups 0.9.3 → 0.10.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/cjs/menu/context-menu-provider.js.map +1 -1
- package/cjs/menu/use-cascade.js +10 -8
- package/cjs/menu/use-cascade.js.map +1 -1
- package/cjs/menu/use-keyboard-navigation.js.map +1 -1
- package/cjs/menu/useContextMenu.js.map +1 -1
- package/cjs/popup-menu/usePopupMenu.js.map +1 -1
- package/esm/menu/context-menu-provider.js.map +1 -1
- package/esm/menu/use-cascade.js +10 -8
- package/esm/menu/use-cascade.js.map +1 -1
- package/esm/menu/use-keyboard-navigation.js.map +1 -1
- package/esm/menu/useContextMenu.js.map +1 -1
- package/esm/popup-menu/usePopupMenu.js.map +1 -1
- package/package.json +8 -8
- package/types/tooltip/useTooltip.d.ts +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-menu-provider.js","sources":["../../src/menu/context-menu-provider.tsx"],"sourcesContent":["import type {\n ContextMenuContextType,\n MenuActionHandler,\n MenuBuilder,\n} from \"@vuu-ui/vuu-data-types\";\nimport { createContext, ReactNode, useCallback, useMemo } from \"react\";\n\nexport const ContextMenuContext = createContext<ContextMenuContextType | null>(\n null,\n);\n\nexport interface ContextMenuConfiguration {\n menuActionHandler?: MenuActionHandler;\n menuBuilder: MenuBuilder;\n}\n\nexport interface ContextMenuProviderProps extends ContextMenuConfiguration {\n children: ReactNode;\n label?: string;\n}\n\ninterface ProviderProps extends ContextMenuProviderProps {\n context: ContextMenuContextType | null;\n}\n\nconst Provider = ({\n children,\n context,\n menuActionHandler,\n menuBuilder,\n}: ProviderProps) => {\n const menuBuilders = useMemo(() => {\n if (context?.menuBuilders && menuBuilder) {\n return context.menuBuilders.concat(menuBuilder);\n } else if (menuBuilder) {\n return [menuBuilder];\n } else {\n return context?.menuBuilders || [];\n }\n }, [context, menuBuilder]);\n\n const handleMenuAction = useCallback(\n (reason) => {\n if (menuActionHandler?.(reason)) {\n return true;\n }\n\n if (context?.menuActionHandler?.(reason)) {\n return true;\n }\n },\n [context, menuActionHandler],\n );\n\n return (\n <ContextMenuContext.Provider\n value={{\n menuActionHandler: handleMenuAction,\n menuBuilders,\n }}\n >\n {children}\n </ContextMenuContext.Provider>\n );\n};\n\n// Need an option for local menu to override higher-level menu, rather than extend\nexport const ContextMenuProvider = ({\n children,\n label,\n menuActionHandler,\n menuBuilder,\n}: ContextMenuProviderProps) => {\n return (\n <ContextMenuContext.Consumer>\n {(parentContext) => (\n <Provider\n context={parentContext}\n label={label}\n menuActionHandler={menuActionHandler}\n menuBuilder={menuBuilder}\n >\n {children}\n </Provider>\n )}\n </ContextMenuContext.Consumer>\n );\n};\n"],"names":["createContext","useMemo","useCallback","jsx"],"mappings":";;;;;AAOO,MAAM,kBAAqB,GAAAA,mBAAA;AAAA,EAChC;AACF;AAgBA,MAAM,WAAW,CAAC;AAAA,EAChB,QAAA;AAAA,EACA,OAAA;AAAA,EACA,iBAAA;AAAA,EACA;AACF,CAAqB,KAAA;AACnB,EAAM,MAAA,YAAA,GAAeC,cAAQ,MAAM;AACjC,IAAI,IAAA,OAAA,EAAS,gBAAgB,WAAa,EAAA;AACxC,MAAO,OAAA,OAAA,CAAQ,YAAa,CAAA,MAAA,CAAO,WAAW,CAAA;AAAA,eACrC,WAAa,EAAA;AACtB,MAAA,OAAO,CAAC,WAAW,CAAA;AAAA,KACd,MAAA;AACL,MAAO,OAAA,OAAA,EAAS,gBAAgB,EAAC;AAAA;AACnC,GACC,EAAA,CAAC,OAAS,EAAA,WAAW,CAAC,CAAA;AAEzB,EAAA,MAAM,gBAAmB,GAAAC,iBAAA;AAAA,IACvB,CAAC,MAAW,KAAA;AACV,MAAI,IAAA,iBAAA,GAAoB,MAAM,CAAG,EAAA;AAC/B,QAAO,OAAA,IAAA;AAAA;AAGT,MAAI,IAAA,OAAA,EAAS,iBAAoB,GAAA,MAAM,CAAG,EAAA;AACxC,QAAO,OAAA,IAAA;AAAA;AACT,KACF;AAAA,IACA,CAAC,SAAS,iBAAiB;AAAA,GAC7B;AAEA,EACE,uBAAAC,cAAA;AAAA,IAAC,kBAAmB,CAAA,QAAA;AAAA,IAAnB;AAAA,MACC,KAAO,EAAA;AAAA,QACL,iBAAmB,EAAA,gBAAA;AAAA,QACnB;AAAA,OACF;AAAA,MAEC;AAAA;AAAA,GACH;AAEJ,CAAA;AAGO,MAAM,sBAAsB,CAAC;AAAA,EAClC,QAAA;AAAA,EACA,KAAA;AAAA,EACA,iBAAA;AAAA,EACA;AACF,CAAgC,KAAA;AAC9B,EAAA,uBACGA,cAAA,CAAA,kBAAA,CAAmB,QAAnB,EAAA,EACE,WAAC,aACA,qBAAAA,cAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,OAAS,EAAA,aAAA;AAAA,MACT,KAAA;AAAA,MACA,iBAAA;AAAA,MACA,WAAA;AAAA,MAEC;AAAA;AAAA,GAGP,EAAA,CAAA;AAEJ;;;;;"}
|
|
1
|
+
{"version":3,"file":"context-menu-provider.js","sources":["../../src/menu/context-menu-provider.tsx"],"sourcesContent":["import type {\n ContextMenuContextType,\n MenuActionHandler,\n MenuBuilder,\n} from \"@vuu-ui/vuu-data-types\";\nimport { createContext, ReactNode, useCallback, useMemo } from \"react\";\n\nexport const ContextMenuContext = createContext<ContextMenuContextType | null>(\n null,\n);\n\nexport interface ContextMenuConfiguration {\n menuActionHandler?: MenuActionHandler;\n menuBuilder: MenuBuilder;\n}\n\nexport interface ContextMenuProviderProps extends ContextMenuConfiguration {\n children: ReactNode;\n label?: string;\n}\n\ninterface ProviderProps extends ContextMenuProviderProps {\n context: ContextMenuContextType | null;\n}\n\nconst Provider = ({\n children,\n context,\n menuActionHandler,\n menuBuilder,\n}: ProviderProps) => {\n const menuBuilders = useMemo(() => {\n if (context?.menuBuilders && menuBuilder) {\n return context.menuBuilders.concat(menuBuilder);\n } else if (menuBuilder) {\n return [menuBuilder];\n } else {\n return context?.menuBuilders || [];\n }\n }, [context, menuBuilder]);\n\n const handleMenuAction = useCallback<MenuActionHandler>(\n (reason) => {\n if (menuActionHandler?.(reason)) {\n return true;\n }\n\n if (context?.menuActionHandler?.(reason)) {\n return true;\n }\n },\n [context, menuActionHandler],\n );\n\n return (\n <ContextMenuContext.Provider\n value={{\n menuActionHandler: handleMenuAction,\n menuBuilders,\n }}\n >\n {children}\n </ContextMenuContext.Provider>\n );\n};\n\n// Need an option for local menu to override higher-level menu, rather than extend\nexport const ContextMenuProvider = ({\n children,\n label,\n menuActionHandler,\n menuBuilder,\n}: ContextMenuProviderProps) => {\n return (\n <ContextMenuContext.Consumer>\n {(parentContext) => (\n <Provider\n context={parentContext}\n label={label}\n menuActionHandler={menuActionHandler}\n menuBuilder={menuBuilder}\n >\n {children}\n </Provider>\n )}\n </ContextMenuContext.Consumer>\n );\n};\n"],"names":["createContext","useMemo","useCallback","jsx"],"mappings":";;;;;AAOO,MAAM,kBAAqB,GAAAA,mBAAA;AAAA,EAChC;AACF;AAgBA,MAAM,WAAW,CAAC;AAAA,EAChB,QAAA;AAAA,EACA,OAAA;AAAA,EACA,iBAAA;AAAA,EACA;AACF,CAAqB,KAAA;AACnB,EAAM,MAAA,YAAA,GAAeC,cAAQ,MAAM;AACjC,IAAI,IAAA,OAAA,EAAS,gBAAgB,WAAa,EAAA;AACxC,MAAO,OAAA,OAAA,CAAQ,YAAa,CAAA,MAAA,CAAO,WAAW,CAAA;AAAA,eACrC,WAAa,EAAA;AACtB,MAAA,OAAO,CAAC,WAAW,CAAA;AAAA,KACd,MAAA;AACL,MAAO,OAAA,OAAA,EAAS,gBAAgB,EAAC;AAAA;AACnC,GACC,EAAA,CAAC,OAAS,EAAA,WAAW,CAAC,CAAA;AAEzB,EAAA,MAAM,gBAAmB,GAAAC,iBAAA;AAAA,IACvB,CAAC,MAAW,KAAA;AACV,MAAI,IAAA,iBAAA,GAAoB,MAAM,CAAG,EAAA;AAC/B,QAAO,OAAA,IAAA;AAAA;AAGT,MAAI,IAAA,OAAA,EAAS,iBAAoB,GAAA,MAAM,CAAG,EAAA;AACxC,QAAO,OAAA,IAAA;AAAA;AACT,KACF;AAAA,IACA,CAAC,SAAS,iBAAiB;AAAA,GAC7B;AAEA,EACE,uBAAAC,cAAA;AAAA,IAAC,kBAAmB,CAAA,QAAA;AAAA,IAAnB;AAAA,MACC,KAAO,EAAA;AAAA,QACL,iBAAmB,EAAA,gBAAA;AAAA,QACnB;AAAA,OACF;AAAA,MAEC;AAAA;AAAA,GACH;AAEJ,CAAA;AAGO,MAAM,sBAAsB,CAAC;AAAA,EAClC,QAAA;AAAA,EACA,KAAA;AAAA,EACA,iBAAA;AAAA,EACA;AACF,CAAgC,KAAA;AAC9B,EAAA,uBACGA,cAAA,CAAA,kBAAA,CAAmB,QAAnB,EAAA,EACE,WAAC,aACA,qBAAAA,cAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,OAAS,EAAA,aAAA;AAAA,MACT,KAAA;AAAA,MACA,iBAAA;AAAA,MACA,WAAA;AAAA,MAEC;AAAA;AAAA,GAGP,EAAA,CAAA;AAEJ;;;;;"}
|
package/cjs/menu/use-cascade.js
CHANGED
|
@@ -88,14 +88,16 @@ const useCascade = ({
|
|
|
88
88
|
setOpenMenus([{ id: rootId, left: posX, top: posY }]);
|
|
89
89
|
} else {
|
|
90
90
|
menuState.current[hostMenuId] = "popup-open";
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
91
|
+
if (itemId) {
|
|
92
|
+
const el = document.getElementById(itemId);
|
|
93
|
+
if (el !== null) {
|
|
94
|
+
const { left, top } = getPosition(el, openMenus.current);
|
|
95
|
+
setOpenMenus(
|
|
96
|
+
openMenus.current.concat({ id: targetMenuId, left, top })
|
|
97
|
+
);
|
|
98
|
+
} else {
|
|
99
|
+
throw Error(`openMenu no menuItem ${itemId}`);
|
|
100
|
+
}
|
|
99
101
|
}
|
|
100
102
|
}
|
|
101
103
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-cascade.js","sources":["../../src/menu/use-cascade.ts"],"sourcesContent":["import {\n MouseEvent,\n SyntheticEvent,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport { closestListItem } from \"./list-dom-utils\";\nimport { MenuItemProps, MenuOpenHandler } from \"./MenuList\";\n// import {mousePosition} from './aim/utils';\n// import {aiming} from './aim/aim';\n\nconst nudge = (\n menus: RuntimeMenuDescriptor[],\n distance: number,\n pos: \"left\" | \"top\"\n) => {\n return menus.map((m, i) =>\n i === menus.length - 1\n ? {\n ...m,\n [pos]: m[pos] - distance,\n }\n : m\n );\n};\nconst nudgeLeft = (menus: RuntimeMenuDescriptor[], distance: number) =>\n nudge(menus, distance, \"left\");\nconst nudgeUp = (menus: RuntimeMenuDescriptor[], distance: number) =>\n nudge(menus, distance, \"top\");\n\nconst flipSides = (id: string, menus: RuntimeMenuDescriptor[]) => {\n const [parentMenu, menu] = menus.slice(-2);\n const el = document.getElementById(`${id}-${menu.id}`);\n if (el === null) {\n throw Error(`useCascade.flipSides element with id ${menu.id} not found`);\n }\n const { width } = el.getBoundingClientRect();\n return menus.map((m) =>\n m === menu\n ? {\n ...m,\n left: parentMenu.left - (width - 2),\n }\n : m\n );\n};\n\n// const closedNode = (el: HTMLElement) =>\n// el.ariaHasPopup === \"true\" && el.ariaExpanded !== \"true\";\nconst getPosition = (el: HTMLElement, openMenus: RuntimeMenuDescriptor[]) => {\n const [{ left, top: menuTop }] = openMenus.slice(-1);\n // const {top, right, bottom, left} = el.getBoundingClientRect();\n // this will not work for MenuList within window, we need the\n // const {offsetLeft: left, offsetTop: menuTop} = el.closest('.vuuMenuList');\n const { offsetWidth: width, offsetTop: top } = el;\n return { left: left + width, top: top + menuTop };\n};\n\nexport type RuntimeMenuDescriptor = {\n id: string;\n left: number;\n top: number;\n};\n\n/** menuitem-vuu-1-0 vuu-1 */\nexport const getHostMenuId = (id: string, rootId: string) => {\n const pos = id.lastIndexOf(\"-\");\n if (id.startsWith(\"menuitem\")) {\n return pos > -1 ? id.slice(9, pos) : rootId;\n } else {\n return pos > -1 ? id.slice(0, pos) : rootId;\n }\n};\n\nconst getTargetMenuId = (id: string) => id.slice(9);\n\nconst getMenuItemDetails = (\n { ariaExpanded, ariaHasPopup, id }: HTMLElement,\n rootId: string\n) => {\n if (id.startsWith(\"menuitem\")) {\n return {\n hostMenuId: getHostMenuId(id, rootId),\n targetMenuId: getTargetMenuId(id),\n menuItemId: id,\n isGroup: ariaHasPopup === \"true\",\n isOpen: ariaExpanded === \"true\",\n };\n } else {\n throw Error(`getMenuItemDetails #${id} is not a menuitem`);\n }\n};\n\nexport interface CascadeHookProps {\n id: string;\n onActivate: (menuId: string) => void;\n onMouseEnterItem: (evt: MouseEvent, itemId: string) => void;\n position: { x: number; y: number };\n}\n\nexport interface CascadeHooksResult {\n closeMenu: () => void;\n handleRender: () => void;\n listItemProps: Partial<MenuItemProps>;\n openMenu: MenuOpenHandler;\n openMenus: RuntimeMenuDescriptor[];\n}\n\ntype MenuStatus = \"no-popup\" | \"popup-open\" | \"pending-close\" | \"popup-pending\";\ntype MenuState = { [key: string]: MenuStatus };\n\nexport const useCascade = ({\n id: rootId,\n onActivate,\n onMouseEnterItem,\n position: { x: posX, y: posY },\n}: CascadeHookProps): CascadeHooksResult => {\n const [, forceRefresh] = useState({});\n const openMenus = useRef<RuntimeMenuDescriptor[]>([\n { id: rootId, left: posX, top: posY },\n ]);\n\n const menuIsOpen = useCallback(\n (menuId: string) =>\n openMenus.current.findIndex((menu) => menu.id === menuId) !== -1,\n []\n );\n\n const getOpenMenuStatus = useCallback((menuId: string) => {\n const state = menuState.current[menuId];\n if (state === undefined) {\n throw Error(`getOpenMenuState no entry for menu ${menuId}`);\n }\n return state;\n }, []);\n\n const setOpenMenus = useCallback((menus: RuntimeMenuDescriptor[]) => {\n openMenus.current = menus;\n forceRefresh({});\n }, []);\n\n const menuOpenPendingTimeout = useRef<number | undefined>();\n const menuClosePendingTimeout = useRef<number | undefined>();\n const menuState = useRef<MenuState>({ [rootId]: \"no-popup\" });\n // const prevLevel = useRef(0);\n\n // const prevAim = useRef({mousePos: null, distance: true});\n\n const openMenu = useCallback(\n (hostMenuId = rootId, targetMenuId: string, itemId = null) => {\n if (hostMenuId === rootId && itemId === null) {\n setOpenMenus([{ id: rootId, left: posX, top: posY }]);\n } else {\n menuState.current[hostMenuId] = \"popup-open\";\n const el = document.getElementById(itemId) as HTMLElement;\n if (el !== null) {\n const { left, top } = getPosition(el, openMenus.current);\n setOpenMenus(\n openMenus.current.concat({ id: targetMenuId, left, top })\n );\n } else {\n throw Error(`openMenu no menuItem ${itemId}`);\n }\n }\n },\n [rootId, posX, posY, setOpenMenus]\n );\n\n const closeMenu = useCallback(\n (menuId?: string) => {\n if (menuId === rootId) {\n setOpenMenus([]);\n } else {\n const menus = openMenus.current.slice();\n const lastMenu = menus.pop() as RuntimeMenuDescriptor;\n menuState.current[lastMenu.id] = \"no-popup\";\n const parentMenu = menus.at(-1);\n if (parentMenu) {\n menuState.current[parentMenu.id] = \"no-popup\";\n }\n setOpenMenus(menus);\n }\n },\n [rootId, setOpenMenus]\n );\n\n const closeMenus = useCallback(\n (menuItemId) => {\n const menus = openMenus.current.slice();\n const menuItemMenuId = menuItemId.slice(9);\n let { id: lastMenuId } = menus.at(-1) as RuntimeMenuDescriptor;\n while (menus.length > 1 && !menuItemMenuId.startsWith(lastMenuId)) {\n const parentMenuId = getHostMenuId(lastMenuId, rootId);\n menus.pop();\n menuState.current[lastMenuId] = \"no-popup\";\n menuState.current[parentMenuId] = \"no-popup\";\n ({ id: lastMenuId } = menus[menus.length - 1]);\n }\n if (menus.length < openMenus.current.length) {\n setOpenMenus(menus);\n }\n },\n [rootId, setOpenMenus]\n );\n\n const clearAnyScheduledOpenTasks = useCallback(() => {\n if (menuOpenPendingTimeout.current) {\n clearTimeout(menuOpenPendingTimeout.current);\n menuOpenPendingTimeout.current = undefined;\n }\n }, []);\n\n const scheduleOpen = useCallback(\n (\n hostMenuId: string,\n targetMenuId: string,\n menuItemId: string,\n delay = 300\n ) => {\n clearAnyScheduledOpenTasks();\n // do we need to set target state to pending-open ?s\n\n menuOpenPendingTimeout.current = window.setTimeout(() => {\n // console.log(\n // `scheduleOpen<timeout> opening menu ${targetMenuId} from menu ${hostMenuId} via menuitem ${menuItemId}`\n // );\n closeMenus(menuItemId);\n menuState.current[hostMenuId] = \"popup-open\";\n menuState.current[targetMenuId] = \"no-popup\";\n openMenu(hostMenuId, targetMenuId, menuItemId);\n }, delay);\n },\n [clearAnyScheduledOpenTasks, closeMenus, openMenu]\n );\n\n const scheduleClose = useCallback(\n (hostMenuId: string, openMenuId: string, itemId: string) => {\n // console.log(\n // `scheduleClose openMenuId ${openMenuId} from parent menu ${hostMenuId} itemId ${itemId}`\n // );\n menuState.current[openMenuId] = \"pending-close\";\n menuClosePendingTimeout.current = window.setTimeout(() => {\n // console.log(`call closeMenus from scheduleClose`);\n closeMenus(itemId);\n }, 400);\n },\n [closeMenus]\n );\n\n const handleRender = useCallback(() => {\n const { current: menus } = openMenus;\n const menu = menus.at(-1);\n const el = menu ? document.getElementById(menu.id) : undefined;\n if (el) {\n const { right, bottom } = el.getBoundingClientRect();\n const { clientHeight, clientWidth } = document.body;\n if (right > clientWidth) {\n const newMenus =\n menus.length > 1\n ? flipSides(rootId, menus)\n : nudgeLeft(menus, right - clientWidth);\n setOpenMenus(newMenus);\n } else if (bottom > clientHeight) {\n const newMenus = nudgeUp(menus, bottom - clientHeight);\n setOpenMenus(newMenus);\n }\n\n if (typeof el.tabIndex === \"number\") {\n el.focus();\n }\n }\n }, [rootId, setOpenMenus]);\n\n // TODO introduce a delay parameter that allows click to requeat an immediate render\n const triggerChildMenu = useCallback<MenuOpenHandler>(\n (menuItemEl, immediate = false) => {\n const { hostMenuId, targetMenuId, menuItemId, isGroup, isOpen } =\n getMenuItemDetails(menuItemEl, rootId);\n const {\n current: { [hostMenuId]: state },\n } = menuState;\n\n const delay = immediate ? 0 : undefined;\n\n // console.log(\n // `%ctriggerChildMenu\n // rootId ${rootId}\n // menuItem ${menuItemId}\n // host menu: ${hostMenuId}\n // target menu: ${targetMenuId}\n // item index: ${menuItemId}\n // state ${state}\n // isGroup ${isGroup} isOpen ${isOpen}\n // openMenus: ${JSON.stringify(openMenus.current)}\n // full state='${JSON.stringify(menuState.current)}`,\n // \"color: green; font-weight: bold;\"\n // );\n\n if (state === \"no-popup\" && isGroup) {\n menuState.current[hostMenuId] = \"popup-pending\";\n scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);\n } else if (state === \"popup-pending\" && !isGroup) {\n menuState.current[hostMenuId] = \"no-popup\";\n clearTimeout(menuOpenPendingTimeout.current);\n menuOpenPendingTimeout.current = undefined;\n } else if (state === \"popup-pending\" && isGroup) {\n clearTimeout(menuOpenPendingTimeout.current);\n scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);\n } else if (state === \"popup-open\") {\n if (menuIsOpen(targetMenuId)) {\n const menuStatus = getOpenMenuStatus(targetMenuId);\n // Close any child menus of the target menu. This can happen if we have\n // opened child menus, then moused out of the menu entirely, to re-enter\n // at a higher level\n closeMenus(menuItemId);\n\n switch (menuStatus) {\n case \"pending-close\":\n // cancel the close\n clearTimeout(menuClosePendingTimeout.current);\n menuClosePendingTimeout.current = undefined;\n menuState.current[targetMenuId] = \"no-popup\";\n clearAnyScheduledOpenTasks();\n break;\n default:\n }\n } else {\n // TODO review the below, suspectb it's over complicating things\n const [parentOfLastOpenedMenu, lastOpenedMenu] =\n openMenus.current.slice(-2);\n if (\n parentOfLastOpenedMenu.id === hostMenuId &&\n menuState.current[lastOpenedMenu.id] !== \"pending-close\" /*&&\n sameLevel*/\n ) {\n scheduleClose(hostMenuId, lastOpenedMenu.id, menuItemId);\n if (isGroup && !isOpen) {\n scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);\n }\n } else if (\n parentOfLastOpenedMenu.id === hostMenuId &&\n isGroup &&\n menuItemId !== lastOpenedMenu.id &&\n menuState.current[lastOpenedMenu.id] === \"pending-close\"\n ) {\n // if there is already an item queued for opening cancel it\n scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);\n } else if (isGroup) {\n // closeMenus(menuId, itemId);\n scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);\n } else if (\n !(\n (menuState.current[lastOpenedMenu.id] === \"pending-close\") /*&&\n sameLevel*/\n )\n ) {\n closeMenus(menuItemId);\n }\n }\n }\n\n if (state === \"pending-close\") {\n clearAnyScheduledOpenTasks();\n clearTimeout(menuClosePendingTimeout.current);\n menuClosePendingTimeout.current = undefined;\n menuState.current[hostMenuId] = \"popup-open\";\n }\n },\n [\n clearAnyScheduledOpenTasks,\n closeMenus,\n getOpenMenuStatus,\n menuIsOpen,\n rootId,\n scheduleClose,\n scheduleOpen,\n ]\n );\n\n const listItemProps: Partial<MenuItemProps> = useMemo(\n () => ({\n onMouseEnter: (evt: MouseEvent) => {\n const menuItemEl = closestListItem(evt.target as HTMLElement);\n triggerChildMenu(menuItemEl);\n onMouseEnterItem(evt, menuItemEl.id);\n },\n\n onClick: (evt: SyntheticEvent) => {\n const listItemEl = closestListItem(evt.target as HTMLElement);\n const { isGroup, menuItemId } = getMenuItemDetails(listItemEl, rootId);\n if (isGroup) {\n triggerChildMenu(listItemEl);\n } else {\n onActivate(menuItemId);\n }\n },\n }),\n [onActivate, onMouseEnterItem, rootId, triggerChildMenu]\n );\n\n return {\n closeMenu,\n handleRender,\n listItemProps,\n openMenu: triggerChildMenu,\n openMenus: openMenus.current,\n };\n};\n"],"names":["useState","useRef","useCallback","useMemo","closestListItem"],"mappings":";;;;;AAcA,MAAM,KAAQ,GAAA,CACZ,KACA,EAAA,QAAA,EACA,GACG,KAAA;AACH,EAAA,OAAO,KAAM,CAAA,GAAA;AAAA,IAAI,CAAC,CAAG,EAAA,CAAA,KACnB,CAAM,KAAA,KAAA,CAAM,SAAS,CACjB,GAAA;AAAA,MACE,GAAG,CAAA;AAAA,MACH,CAAC,GAAG,GAAG,CAAA,CAAE,GAAG,CAAI,GAAA;AAAA,KAElB,GAAA;AAAA,GACN;AACF,CAAA;AACA,MAAM,YAAY,CAAC,KAAA,EAAgC,aACjD,KAAM,CAAA,KAAA,EAAO,UAAU,MAAM,CAAA;AAC/B,MAAM,UAAU,CAAC,KAAA,EAAgC,aAC/C,KAAM,CAAA,KAAA,EAAO,UAAU,KAAK,CAAA;AAE9B,MAAM,SAAA,GAAY,CAAC,EAAA,EAAY,KAAmC,KAAA;AAChE,EAAA,MAAM,CAAC,UAAY,EAAA,IAAI,CAAI,GAAA,KAAA,CAAM,MAAM,CAAE,CAAA,CAAA;AACzC,EAAM,MAAA,EAAA,GAAK,SAAS,cAAe,CAAA,CAAA,EAAG,EAAE,CAAI,CAAA,EAAA,IAAA,CAAK,EAAE,CAAE,CAAA,CAAA;AACrD,EAAA,IAAI,OAAO,IAAM,EAAA;AACf,IAAA,MAAM,KAAM,CAAA,CAAA,qCAAA,EAAwC,IAAK,CAAA,EAAE,CAAY,UAAA,CAAA,CAAA;AAAA;AAEzE,EAAA,MAAM,EAAE,KAAA,EAAU,GAAA,EAAA,CAAG,qBAAsB,EAAA;AAC3C,EAAA,OAAO,KAAM,CAAA,GAAA;AAAA,IAAI,CAAC,CAChB,KAAA,CAAA,KAAM,IACF,GAAA;AAAA,MACE,GAAG,CAAA;AAAA,MACH,IAAA,EAAM,UAAW,CAAA,IAAA,IAAQ,KAAQ,GAAA,CAAA;AAAA,KAEnC,GAAA;AAAA,GACN;AACF,CAAA;AAIA,MAAM,WAAA,GAAc,CAAC,EAAA,EAAiB,SAAuC,KAAA;AAC3E,EAAM,MAAA,CAAC,EAAE,IAAM,EAAA,GAAA,EAAK,SAAS,CAAA,GAAI,SAAU,CAAA,KAAA,CAAM,CAAE,CAAA,CAAA;AAInD,EAAA,MAAM,EAAE,WAAA,EAAa,KAAO,EAAA,SAAA,EAAW,KAAQ,GAAA,EAAA;AAC/C,EAAA,OAAO,EAAE,IAAM,EAAA,IAAA,GAAO,KAAO,EAAA,GAAA,EAAK,MAAM,OAAQ,EAAA;AAClD,CAAA;AASa,MAAA,aAAA,GAAgB,CAAC,EAAA,EAAY,MAAmB,KAAA;AAC3D,EAAM,MAAA,GAAA,GAAM,EAAG,CAAA,WAAA,CAAY,GAAG,CAAA;AAC9B,EAAI,IAAA,EAAA,CAAG,UAAW,CAAA,UAAU,CAAG,EAAA;AAC7B,IAAA,OAAO,MAAM,CAAK,CAAA,GAAA,EAAA,CAAG,KAAM,CAAA,CAAA,EAAG,GAAG,CAAI,GAAA,MAAA;AAAA,GAChC,MAAA;AACL,IAAA,OAAO,MAAM,CAAK,CAAA,GAAA,EAAA,CAAG,KAAM,CAAA,CAAA,EAAG,GAAG,CAAI,GAAA,MAAA;AAAA;AAEzC;AAEA,MAAM,eAAkB,GAAA,CAAC,EAAe,KAAA,EAAA,CAAG,MAAM,CAAC,CAAA;AAElD,MAAM,qBAAqB,CACzB,EAAE,cAAc,YAAc,EAAA,EAAA,IAC9B,MACG,KAAA;AACH,EAAI,IAAA,EAAA,CAAG,UAAW,CAAA,UAAU,CAAG,EAAA;AAC7B,IAAO,OAAA;AAAA,MACL,UAAA,EAAY,aAAc,CAAA,EAAA,EAAI,MAAM,CAAA;AAAA,MACpC,YAAA,EAAc,gBAAgB,EAAE,CAAA;AAAA,MAChC,UAAY,EAAA,EAAA;AAAA,MACZ,SAAS,YAAiB,KAAA,MAAA;AAAA,MAC1B,QAAQ,YAAiB,KAAA;AAAA,KAC3B;AAAA,GACK,MAAA;AACL,IAAM,MAAA,KAAA,CAAM,CAAuB,oBAAA,EAAA,EAAE,CAAoB,kBAAA,CAAA,CAAA;AAAA;AAE7D,CAAA;AAoBO,MAAM,aAAa,CAAC;AAAA,EACzB,EAAI,EAAA,MAAA;AAAA,EACJ,UAAA;AAAA,EACA,gBAAA;AAAA,EACA,QAAU,EAAA,EAAE,CAAG,EAAA,IAAA,EAAM,GAAG,IAAK;AAC/B,CAA4C,KAAA;AAC1C,EAAA,MAAM,GAAG,YAAY,CAAI,GAAAA,cAAA,CAAS,EAAE,CAAA;AACpC,EAAA,MAAM,YAAYC,YAAgC,CAAA;AAAA,IAChD,EAAE,EAAI,EAAA,MAAA,EAAQ,IAAM,EAAA,IAAA,EAAM,KAAK,IAAK;AAAA,GACrC,CAAA;AAED,EAAA,MAAM,UAAa,GAAAC,iBAAA;AAAA,IACjB,CAAC,MACC,KAAA,SAAA,CAAU,OAAQ,CAAA,SAAA,CAAU,CAAC,IAAS,KAAA,IAAA,CAAK,EAAO,KAAA,MAAM,CAAM,KAAA,CAAA,CAAA;AAAA,IAChE;AAAC,GACH;AAEA,EAAM,MAAA,iBAAA,GAAoBA,iBAAY,CAAA,CAAC,MAAmB,KAAA;AACxD,IAAM,MAAA,KAAA,GAAQ,SAAU,CAAA,OAAA,CAAQ,MAAM,CAAA;AACtC,IAAA,IAAI,UAAU,KAAW,CAAA,EAAA;AACvB,MAAM,MAAA,KAAA,CAAM,CAAsC,mCAAA,EAAA,MAAM,CAAE,CAAA,CAAA;AAAA;AAE5D,IAAO,OAAA,KAAA;AAAA,GACT,EAAG,EAAE,CAAA;AAEL,EAAM,MAAA,YAAA,GAAeA,iBAAY,CAAA,CAAC,KAAmC,KAAA;AACnE,IAAA,SAAA,CAAU,OAAU,GAAA,KAAA;AACpB,IAAA,YAAA,CAAa,EAAE,CAAA;AAAA,GACjB,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,yBAAyBD,YAA2B,EAAA;AAC1D,EAAA,MAAM,0BAA0BA,YAA2B,EAAA;AAC3D,EAAA,MAAM,YAAYA,YAAkB,CAAA,EAAE,CAAC,MAAM,GAAG,YAAY,CAAA;AAK5D,EAAA,MAAM,QAAW,GAAAC,iBAAA;AAAA,IACf,CAAC,UAAA,GAAa,MAAQ,EAAA,YAAA,EAAsB,SAAS,IAAS,KAAA;AAC5D,MAAI,IAAA,UAAA,KAAe,MAAU,IAAA,MAAA,KAAW,IAAM,EAAA;AAC5C,QAAa,YAAA,CAAA,CAAC,EAAE,EAAI,EAAA,MAAA,EAAQ,MAAM,IAAM,EAAA,GAAA,EAAK,IAAK,EAAC,CAAC,CAAA;AAAA,OAC/C,MAAA;AACL,QAAU,SAAA,CAAA,OAAA,CAAQ,UAAU,CAAI,GAAA,YAAA;AAChC,QAAM,MAAA,EAAA,GAAK,QAAS,CAAA,cAAA,CAAe,MAAM,CAAA;AACzC,QAAA,IAAI,OAAO,IAAM,EAAA;AACf,UAAA,MAAM,EAAE,IAAM,EAAA,GAAA,KAAQ,WAAY,CAAA,EAAA,EAAI,UAAU,OAAO,CAAA;AACvD,UAAA,YAAA;AAAA,YACE,SAAA,CAAU,QAAQ,MAAO,CAAA,EAAE,IAAI,YAAc,EAAA,IAAA,EAAM,KAAK;AAAA,WAC1D;AAAA,SACK,MAAA;AACL,UAAM,MAAA,KAAA,CAAM,CAAwB,qBAAA,EAAA,MAAM,CAAE,CAAA,CAAA;AAAA;AAC9C;AACF,KACF;AAAA,IACA,CAAC,MAAA,EAAQ,IAAM,EAAA,IAAA,EAAM,YAAY;AAAA,GACnC;AAEA,EAAA,MAAM,SAAY,GAAAA,iBAAA;AAAA,IAChB,CAAC,MAAoB,KAAA;AACnB,MAAA,IAAI,WAAW,MAAQ,EAAA;AACrB,QAAA,YAAA,CAAa,EAAE,CAAA;AAAA,OACV,MAAA;AACL,QAAM,MAAA,KAAA,GAAQ,SAAU,CAAA,OAAA,CAAQ,KAAM,EAAA;AACtC,QAAM,MAAA,QAAA,GAAW,MAAM,GAAI,EAAA;AAC3B,QAAU,SAAA,CAAA,OAAA,CAAQ,QAAS,CAAA,EAAE,CAAI,GAAA,UAAA;AACjC,QAAM,MAAA,UAAA,GAAa,KAAM,CAAA,EAAA,CAAG,CAAE,CAAA,CAAA;AAC9B,QAAA,IAAI,UAAY,EAAA;AACd,UAAU,SAAA,CAAA,OAAA,CAAQ,UAAW,CAAA,EAAE,CAAI,GAAA,UAAA;AAAA;AAErC,QAAA,YAAA,CAAa,KAAK,CAAA;AAAA;AACpB,KACF;AAAA,IACA,CAAC,QAAQ,YAAY;AAAA,GACvB;AAEA,EAAA,MAAM,UAAa,GAAAA,iBAAA;AAAA,IACjB,CAAC,UAAe,KAAA;AACd,MAAM,MAAA,KAAA,GAAQ,SAAU,CAAA,OAAA,CAAQ,KAAM,EAAA;AACtC,MAAM,MAAA,cAAA,GAAiB,UAAW,CAAA,KAAA,CAAM,CAAC,CAAA;AACzC,MAAA,IAAI,EAAE,EAAI,EAAA,UAAA,EAAe,GAAA,KAAA,CAAM,GAAG,CAAE,CAAA,CAAA;AACpC,MAAA,OAAO,MAAM,MAAS,GAAA,CAAA,IAAK,CAAC,cAAe,CAAA,UAAA,CAAW,UAAU,CAAG,EAAA;AACjE,QAAM,MAAA,YAAA,GAAe,aAAc,CAAA,UAAA,EAAY,MAAM,CAAA;AACrD,QAAA,KAAA,CAAM,GAAI,EAAA;AACV,QAAU,SAAA,CAAA,OAAA,CAAQ,UAAU,CAAI,GAAA,UAAA;AAChC,QAAU,SAAA,CAAA,OAAA,CAAQ,YAAY,CAAI,GAAA,UAAA;AAClC,QAAA,CAAC,EAAE,EAAI,EAAA,UAAA,KAAe,KAAM,CAAA,KAAA,CAAM,SAAS,CAAC,CAAA;AAAA;AAE9C,MAAA,IAAI,KAAM,CAAA,MAAA,GAAS,SAAU,CAAA,OAAA,CAAQ,MAAQ,EAAA;AAC3C,QAAA,YAAA,CAAa,KAAK,CAAA;AAAA;AACpB,KACF;AAAA,IACA,CAAC,QAAQ,YAAY;AAAA,GACvB;AAEA,EAAM,MAAA,0BAAA,GAA6BA,kBAAY,MAAM;AACnD,IAAA,IAAI,uBAAuB,OAAS,EAAA;AAClC,MAAA,YAAA,CAAa,uBAAuB,OAAO,CAAA;AAC3C,MAAA,sBAAA,CAAuB,OAAU,GAAA,KAAA,CAAA;AAAA;AACnC,GACF,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,YAAe,GAAAA,iBAAA;AAAA,IACnB,CACE,UAAA,EACA,YACA,EAAA,UAAA,EACA,QAAQ,GACL,KAAA;AACH,MAA2B,0BAAA,EAAA;AAG3B,MAAuB,sBAAA,CAAA,OAAA,GAAU,MAAO,CAAA,UAAA,CAAW,MAAM;AAIvD,QAAA,UAAA,CAAW,UAAU,CAAA;AACrB,QAAU,SAAA,CAAA,OAAA,CAAQ,UAAU,CAAI,GAAA,YAAA;AAChC,QAAU,SAAA,CAAA,OAAA,CAAQ,YAAY,CAAI,GAAA,UAAA;AAClC,QAAS,QAAA,CAAA,UAAA,EAAY,cAAc,UAAU,CAAA;AAAA,SAC5C,KAAK,CAAA;AAAA,KACV;AAAA,IACA,CAAC,0BAA4B,EAAA,UAAA,EAAY,QAAQ;AAAA,GACnD;AAEA,EAAA,MAAM,aAAgB,GAAAA,iBAAA;AAAA,IACpB,CAAC,UAAoB,EAAA,UAAA,EAAoB,MAAmB,KAAA;AAI1D,MAAU,SAAA,CAAA,OAAA,CAAQ,UAAU,CAAI,GAAA,eAAA;AAChC,MAAwB,uBAAA,CAAA,OAAA,GAAU,MAAO,CAAA,UAAA,CAAW,MAAM;AAExD,QAAA,UAAA,CAAW,MAAM,CAAA;AAAA,SAChB,GAAG,CAAA;AAAA,KACR;AAAA,IACA,CAAC,UAAU;AAAA,GACb;AAEA,EAAM,MAAA,YAAA,GAAeA,kBAAY,MAAM;AACrC,IAAM,MAAA,EAAE,OAAS,EAAA,KAAA,EAAU,GAAA,SAAA;AAC3B,IAAM,MAAA,IAAA,GAAO,KAAM,CAAA,EAAA,CAAG,CAAE,CAAA,CAAA;AACxB,IAAA,MAAM,KAAK,IAAO,GAAA,QAAA,CAAS,cAAe,CAAA,IAAA,CAAK,EAAE,CAAI,GAAA,KAAA,CAAA;AACrD,IAAA,IAAI,EAAI,EAAA;AACN,MAAA,MAAM,EAAE,KAAA,EAAO,MAAO,EAAA,GAAI,GAAG,qBAAsB,EAAA;AACnD,MAAA,MAAM,EAAE,YAAA,EAAc,WAAY,EAAA,GAAI,QAAS,CAAA,IAAA;AAC/C,MAAA,IAAI,QAAQ,WAAa,EAAA;AACvB,QAAM,MAAA,QAAA,GACJ,KAAM,CAAA,MAAA,GAAS,CACX,GAAA,SAAA,CAAU,MAAQ,EAAA,KAAK,CACvB,GAAA,SAAA,CAAU,KAAO,EAAA,KAAA,GAAQ,WAAW,CAAA;AAC1C,QAAA,YAAA,CAAa,QAAQ,CAAA;AAAA,OACvB,MAAA,IAAW,SAAS,YAAc,EAAA;AAChC,QAAA,MAAM,QAAW,GAAA,OAAA,CAAQ,KAAO,EAAA,MAAA,GAAS,YAAY,CAAA;AACrD,QAAA,YAAA,CAAa,QAAQ,CAAA;AAAA;AAGvB,MAAI,IAAA,OAAO,EAAG,CAAA,QAAA,KAAa,QAAU,EAAA;AACnC,QAAA,EAAA,CAAG,KAAM,EAAA;AAAA;AACX;AACF,GACC,EAAA,CAAC,MAAQ,EAAA,YAAY,CAAC,CAAA;AAGzB,EAAA,MAAM,gBAAmB,GAAAA,iBAAA;AAAA,IACvB,CAAC,UAAY,EAAA,SAAA,GAAY,KAAU,KAAA;AACjC,MAAM,MAAA,EAAE,YAAY,YAAc,EAAA,UAAA,EAAY,SAAS,MAAO,EAAA,GAC5D,kBAAmB,CAAA,UAAA,EAAY,MAAM,CAAA;AACvC,MAAM,MAAA;AAAA,QACJ,OAAS,EAAA,EAAE,CAAC,UAAU,GAAG,KAAM;AAAA,OAC7B,GAAA,SAAA;AAEJ,MAAM,MAAA,KAAA,GAAQ,YAAY,CAAI,GAAA,KAAA,CAAA;AAgB9B,MAAI,IAAA,KAAA,KAAU,cAAc,OAAS,EAAA;AACnC,QAAU,SAAA,CAAA,OAAA,CAAQ,UAAU,CAAI,GAAA,eAAA;AAChC,QAAa,YAAA,CAAA,UAAA,EAAY,YAAc,EAAA,UAAA,EAAY,KAAK,CAAA;AAAA,OAC/C,MAAA,IAAA,KAAA,KAAU,eAAmB,IAAA,CAAC,OAAS,EAAA;AAChD,QAAU,SAAA,CAAA,OAAA,CAAQ,UAAU,CAAI,GAAA,UAAA;AAChC,QAAA,YAAA,CAAa,uBAAuB,OAAO,CAAA;AAC3C,QAAA,sBAAA,CAAuB,OAAU,GAAA,KAAA,CAAA;AAAA,OACnC,MAAA,IAAW,KAAU,KAAA,eAAA,IAAmB,OAAS,EAAA;AAC/C,QAAA,YAAA,CAAa,uBAAuB,OAAO,CAAA;AAC3C,QAAa,YAAA,CAAA,UAAA,EAAY,YAAc,EAAA,UAAA,EAAY,KAAK,CAAA;AAAA,OAC1D,MAAA,IAAW,UAAU,YAAc,EAAA;AACjC,QAAI,IAAA,UAAA,CAAW,YAAY,CAAG,EAAA;AAC5B,UAAM,MAAA,UAAA,GAAa,kBAAkB,YAAY,CAAA;AAIjD,UAAA,UAAA,CAAW,UAAU,CAAA;AAErB,UAAA,QAAQ,UAAY;AAAA,YAClB,KAAK,eAAA;AAEH,cAAA,YAAA,CAAa,wBAAwB,OAAO,CAAA;AAC5C,cAAA,uBAAA,CAAwB,OAAU,GAAA,KAAA,CAAA;AAClC,cAAU,SAAA,CAAA,OAAA,CAAQ,YAAY,CAAI,GAAA,UAAA;AAClC,cAA2B,0BAAA,EAAA;AAC3B,cAAA;AACF;AACF,SACK,MAAA;AAEL,UAAA,MAAM,CAAC,sBAAwB,EAAA,cAAc,IAC3C,SAAU,CAAA,OAAA,CAAQ,MAAM,CAAE,CAAA,CAAA;AAC5B,UACE,IAAA,sBAAA,CAAuB,OAAO,UAC9B,IAAA,SAAA,CAAU,QAAQ,cAAe,CAAA,EAAE,MAAM,eAEzC,EAAA;AACA,YAAc,aAAA,CAAA,UAAA,EAAY,cAAe,CAAA,EAAA,EAAI,UAAU,CAAA;AACvD,YAAI,IAAA,OAAA,IAAW,CAAC,MAAQ,EAAA;AACtB,cAAa,YAAA,CAAA,UAAA,EAAY,YAAc,EAAA,UAAA,EAAY,KAAK,CAAA;AAAA;AAC1D,WAEA,MAAA,IAAA,sBAAA,CAAuB,EAAO,KAAA,UAAA,IAC9B,OACA,IAAA,UAAA,KAAe,cAAe,CAAA,EAAA,IAC9B,SAAU,CAAA,OAAA,CAAQ,cAAe,CAAA,EAAE,MAAM,eACzC,EAAA;AAEA,YAAa,YAAA,CAAA,UAAA,EAAY,YAAc,EAAA,UAAA,EAAY,KAAK,CAAA;AAAA,qBAC/C,OAAS,EAAA;AAElB,YAAa,YAAA,CAAA,UAAA,EAAY,YAAc,EAAA,UAAA,EAAY,KAAK,CAAA;AAAA,qBAExD,EACG,SAAA,CAAU,QAAQ,cAAe,CAAA,EAAE,MAAM,eAG5C,CAAA,EAAA;AACA,YAAA,UAAA,CAAW,UAAU,CAAA;AAAA;AACvB;AACF;AAGF,MAAA,IAAI,UAAU,eAAiB,EAAA;AAC7B,QAA2B,0BAAA,EAAA;AAC3B,QAAA,YAAA,CAAa,wBAAwB,OAAO,CAAA;AAC5C,QAAA,uBAAA,CAAwB,OAAU,GAAA,KAAA,CAAA;AAClC,QAAU,SAAA,CAAA,OAAA,CAAQ,UAAU,CAAI,GAAA,YAAA;AAAA;AAClC,KACF;AAAA,IACA;AAAA,MACE,0BAAA;AAAA,MACA,UAAA;AAAA,MACA,iBAAA;AAAA,MACA,UAAA;AAAA,MACA,MAAA;AAAA,MACA,aAAA;AAAA,MACA;AAAA;AACF,GACF;AAEA,EAAA,MAAM,aAAwC,GAAAC,aAAA;AAAA,IAC5C,OAAO;AAAA,MACL,YAAA,EAAc,CAAC,GAAoB,KAAA;AACjC,QAAM,MAAA,UAAA,GAAaC,4BAAgB,CAAA,GAAA,CAAI,MAAqB,CAAA;AAC5D,QAAA,gBAAA,CAAiB,UAAU,CAAA;AAC3B,QAAiB,gBAAA,CAAA,GAAA,EAAK,WAAW,EAAE,CAAA;AAAA,OACrC;AAAA,MAEA,OAAA,EAAS,CAAC,GAAwB,KAAA;AAChC,QAAM,MAAA,UAAA,GAAaA,4BAAgB,CAAA,GAAA,CAAI,MAAqB,CAAA;AAC5D,QAAA,MAAM,EAAE,OAAS,EAAA,UAAA,EAAe,GAAA,kBAAA,CAAmB,YAAY,MAAM,CAAA;AACrE,QAAA,IAAI,OAAS,EAAA;AACX,UAAA,gBAAA,CAAiB,UAAU,CAAA;AAAA,SACtB,MAAA;AACL,UAAA,UAAA,CAAW,UAAU,CAAA;AAAA;AACvB;AACF,KACF,CAAA;AAAA,IACA,CAAC,UAAA,EAAY,gBAAkB,EAAA,MAAA,EAAQ,gBAAgB;AAAA,GACzD;AAEA,EAAO,OAAA;AAAA,IACL,SAAA;AAAA,IACA,YAAA;AAAA,IACA,aAAA;AAAA,IACA,QAAU,EAAA,gBAAA;AAAA,IACV,WAAW,SAAU,CAAA;AAAA,GACvB;AACF;;;;;"}
|
|
1
|
+
{"version":3,"file":"use-cascade.js","sources":["../../src/menu/use-cascade.ts"],"sourcesContent":["import {\n MouseEvent,\n SyntheticEvent,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport { closestListItem } from \"./list-dom-utils\";\nimport { MenuItemProps, MenuOpenHandler } from \"./MenuList\";\n// import {mousePosition} from './aim/utils';\n// import {aiming} from './aim/aim';\n\nconst nudge = (\n menus: RuntimeMenuDescriptor[],\n distance: number,\n pos: \"left\" | \"top\",\n) => {\n return menus.map((m, i) =>\n i === menus.length - 1\n ? {\n ...m,\n [pos]: m[pos] - distance,\n }\n : m,\n );\n};\nconst nudgeLeft = (menus: RuntimeMenuDescriptor[], distance: number) =>\n nudge(menus, distance, \"left\");\nconst nudgeUp = (menus: RuntimeMenuDescriptor[], distance: number) =>\n nudge(menus, distance, \"top\");\n\nconst flipSides = (id: string, menus: RuntimeMenuDescriptor[]) => {\n const [parentMenu, menu] = menus.slice(-2);\n const el = document.getElementById(`${id}-${menu.id}`);\n if (el === null) {\n throw Error(`useCascade.flipSides element with id ${menu.id} not found`);\n }\n const { width } = el.getBoundingClientRect();\n return menus.map((m) =>\n m === menu\n ? {\n ...m,\n left: parentMenu.left - (width - 2),\n }\n : m,\n );\n};\n\n// const closedNode = (el: HTMLElement) =>\n// el.ariaHasPopup === \"true\" && el.ariaExpanded !== \"true\";\nconst getPosition = (el: HTMLElement, openMenus: RuntimeMenuDescriptor[]) => {\n const [{ left, top: menuTop }] = openMenus.slice(-1);\n // const {top, right, bottom, left} = el.getBoundingClientRect();\n // this will not work for MenuList within window, we need the\n // const {offsetLeft: left, offsetTop: menuTop} = el.closest('.vuuMenuList');\n const { offsetWidth: width, offsetTop: top } = el;\n return { left: left + width, top: top + menuTop };\n};\n\nexport type RuntimeMenuDescriptor = {\n id: string;\n left: number;\n top: number;\n};\n\n/** menuitem-vuu-1-0 vuu-1 */\nexport const getHostMenuId = (id: string, rootId: string) => {\n const pos = id.lastIndexOf(\"-\");\n if (id.startsWith(\"menuitem\")) {\n return pos > -1 ? id.slice(9, pos) : rootId;\n } else {\n return pos > -1 ? id.slice(0, pos) : rootId;\n }\n};\n\nconst getTargetMenuId = (id: string) => id.slice(9);\n\nconst getMenuItemDetails = (\n { ariaExpanded, ariaHasPopup, id }: HTMLElement,\n rootId: string,\n) => {\n if (id.startsWith(\"menuitem\")) {\n return {\n hostMenuId: getHostMenuId(id, rootId),\n targetMenuId: getTargetMenuId(id),\n menuItemId: id,\n isGroup: ariaHasPopup === \"true\",\n isOpen: ariaExpanded === \"true\",\n };\n } else {\n throw Error(`getMenuItemDetails #${id} is not a menuitem`);\n }\n};\n\nexport interface CascadeHookProps {\n id: string;\n onActivate: (menuId: string) => void;\n onMouseEnterItem: (evt: MouseEvent, itemId: string) => void;\n position: { x: number; y: number };\n}\n\nexport interface CascadeHooksResult {\n closeMenu: () => void;\n handleRender: () => void;\n listItemProps: Partial<MenuItemProps>;\n openMenu: MenuOpenHandler;\n openMenus: RuntimeMenuDescriptor[];\n}\n\ntype MenuStatus = \"no-popup\" | \"popup-open\" | \"pending-close\" | \"popup-pending\";\ntype MenuState = { [key: string]: MenuStatus };\n\nexport const useCascade = ({\n id: rootId,\n onActivate,\n onMouseEnterItem,\n position: { x: posX, y: posY },\n}: CascadeHookProps): CascadeHooksResult => {\n const [, forceRefresh] = useState({});\n const openMenus = useRef<RuntimeMenuDescriptor[]>([\n { id: rootId, left: posX, top: posY },\n ]);\n\n const menuIsOpen = useCallback(\n (menuId: string) =>\n openMenus.current.findIndex((menu) => menu.id === menuId) !== -1,\n [],\n );\n\n const getOpenMenuStatus = useCallback((menuId: string) => {\n const state = menuState.current[menuId];\n if (state === undefined) {\n throw Error(`getOpenMenuState no entry for menu ${menuId}`);\n }\n return state;\n }, []);\n\n const setOpenMenus = useCallback((menus: RuntimeMenuDescriptor[]) => {\n openMenus.current = menus;\n forceRefresh({});\n }, []);\n\n const menuOpenPendingTimeout = useRef<number | undefined>();\n const menuClosePendingTimeout = useRef<number | undefined>();\n const menuState = useRef<MenuState>({ [rootId]: \"no-popup\" });\n // const prevLevel = useRef(0);\n\n // const prevAim = useRef({mousePos: null, distance: true});\n\n const openMenu = useCallback(\n (\n hostMenuId = rootId,\n targetMenuId: string,\n itemId: string | null = null,\n ) => {\n if (hostMenuId === rootId && itemId === null) {\n setOpenMenus([{ id: rootId, left: posX, top: posY }]);\n } else {\n menuState.current[hostMenuId] = \"popup-open\";\n if (itemId) {\n const el = document.getElementById(itemId) as HTMLElement;\n if (el !== null) {\n const { left, top } = getPosition(el, openMenus.current);\n setOpenMenus(\n openMenus.current.concat({ id: targetMenuId, left, top }),\n );\n } else {\n throw Error(`openMenu no menuItem ${itemId}`);\n }\n }\n }\n },\n [rootId, posX, posY, setOpenMenus],\n );\n\n const closeMenu = useCallback(\n (menuId?: string) => {\n if (menuId === rootId) {\n setOpenMenus([]);\n } else {\n const menus = openMenus.current.slice();\n const lastMenu = menus.pop() as RuntimeMenuDescriptor;\n menuState.current[lastMenu.id] = \"no-popup\";\n const parentMenu = menus.at(-1);\n if (parentMenu) {\n menuState.current[parentMenu.id] = \"no-popup\";\n }\n setOpenMenus(menus);\n }\n },\n [rootId, setOpenMenus],\n );\n\n const closeMenus = useCallback(\n (menuItemId: string) => {\n const menus = openMenus.current.slice();\n const menuItemMenuId = menuItemId.slice(9);\n let { id: lastMenuId } = menus.at(-1) as RuntimeMenuDescriptor;\n while (menus.length > 1 && !menuItemMenuId.startsWith(lastMenuId)) {\n const parentMenuId = getHostMenuId(lastMenuId, rootId);\n menus.pop();\n menuState.current[lastMenuId] = \"no-popup\";\n menuState.current[parentMenuId] = \"no-popup\";\n ({ id: lastMenuId } = menus[menus.length - 1]);\n }\n if (menus.length < openMenus.current.length) {\n setOpenMenus(menus);\n }\n },\n [rootId, setOpenMenus],\n );\n\n const clearAnyScheduledOpenTasks = useCallback(() => {\n if (menuOpenPendingTimeout.current) {\n clearTimeout(menuOpenPendingTimeout.current);\n menuOpenPendingTimeout.current = undefined;\n }\n }, []);\n\n const scheduleOpen = useCallback(\n (\n hostMenuId: string,\n targetMenuId: string,\n menuItemId: string,\n delay = 300,\n ) => {\n clearAnyScheduledOpenTasks();\n // do we need to set target state to pending-open ?s\n\n menuOpenPendingTimeout.current = window.setTimeout(() => {\n // console.log(\n // `scheduleOpen<timeout> opening menu ${targetMenuId} from menu ${hostMenuId} via menuitem ${menuItemId}`\n // );\n closeMenus(menuItemId);\n menuState.current[hostMenuId] = \"popup-open\";\n menuState.current[targetMenuId] = \"no-popup\";\n openMenu(hostMenuId, targetMenuId, menuItemId);\n }, delay);\n },\n [clearAnyScheduledOpenTasks, closeMenus, openMenu],\n );\n\n const scheduleClose = useCallback(\n (hostMenuId: string, openMenuId: string, itemId: string) => {\n // console.log(\n // `scheduleClose openMenuId ${openMenuId} from parent menu ${hostMenuId} itemId ${itemId}`\n // );\n menuState.current[openMenuId] = \"pending-close\";\n menuClosePendingTimeout.current = window.setTimeout(() => {\n // console.log(`call closeMenus from scheduleClose`);\n closeMenus(itemId);\n }, 400);\n },\n [closeMenus],\n );\n\n const handleRender = useCallback(() => {\n const { current: menus } = openMenus;\n const menu = menus.at(-1);\n const el = menu ? document.getElementById(menu.id) : undefined;\n if (el) {\n const { right, bottom } = el.getBoundingClientRect();\n const { clientHeight, clientWidth } = document.body;\n if (right > clientWidth) {\n const newMenus =\n menus.length > 1\n ? flipSides(rootId, menus)\n : nudgeLeft(menus, right - clientWidth);\n setOpenMenus(newMenus);\n } else if (bottom > clientHeight) {\n const newMenus = nudgeUp(menus, bottom - clientHeight);\n setOpenMenus(newMenus);\n }\n\n if (typeof el.tabIndex === \"number\") {\n el.focus();\n }\n }\n }, [rootId, setOpenMenus]);\n\n // TODO introduce a delay parameter that allows click to requeat an immediate render\n const triggerChildMenu = useCallback<MenuOpenHandler>(\n (menuItemEl, immediate = false) => {\n const { hostMenuId, targetMenuId, menuItemId, isGroup, isOpen } =\n getMenuItemDetails(menuItemEl, rootId);\n const {\n current: { [hostMenuId]: state },\n } = menuState;\n\n const delay = immediate ? 0 : undefined;\n\n // console.log(\n // `%ctriggerChildMenu\n // rootId ${rootId}\n // menuItem ${menuItemId}\n // host menu: ${hostMenuId}\n // target menu: ${targetMenuId}\n // item index: ${menuItemId}\n // state ${state}\n // isGroup ${isGroup} isOpen ${isOpen}\n // openMenus: ${JSON.stringify(openMenus.current)}\n // full state='${JSON.stringify(menuState.current)}`,\n // \"color: green; font-weight: bold;\"\n // );\n\n if (state === \"no-popup\" && isGroup) {\n menuState.current[hostMenuId] = \"popup-pending\";\n scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);\n } else if (state === \"popup-pending\" && !isGroup) {\n menuState.current[hostMenuId] = \"no-popup\";\n clearTimeout(menuOpenPendingTimeout.current);\n menuOpenPendingTimeout.current = undefined;\n } else if (state === \"popup-pending\" && isGroup) {\n clearTimeout(menuOpenPendingTimeout.current);\n scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);\n } else if (state === \"popup-open\") {\n if (menuIsOpen(targetMenuId)) {\n const menuStatus = getOpenMenuStatus(targetMenuId);\n // Close any child menus of the target menu. This can happen if we have\n // opened child menus, then moused out of the menu entirely, to re-enter\n // at a higher level\n closeMenus(menuItemId);\n\n switch (menuStatus) {\n case \"pending-close\":\n // cancel the close\n clearTimeout(menuClosePendingTimeout.current);\n menuClosePendingTimeout.current = undefined;\n menuState.current[targetMenuId] = \"no-popup\";\n clearAnyScheduledOpenTasks();\n break;\n default:\n }\n } else {\n // TODO review the below, suspectb it's over complicating things\n const [parentOfLastOpenedMenu, lastOpenedMenu] =\n openMenus.current.slice(-2);\n if (\n parentOfLastOpenedMenu.id === hostMenuId &&\n menuState.current[lastOpenedMenu.id] !== \"pending-close\" /*&&\n sameLevel*/\n ) {\n scheduleClose(hostMenuId, lastOpenedMenu.id, menuItemId);\n if (isGroup && !isOpen) {\n scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);\n }\n } else if (\n parentOfLastOpenedMenu.id === hostMenuId &&\n isGroup &&\n menuItemId !== lastOpenedMenu.id &&\n menuState.current[lastOpenedMenu.id] === \"pending-close\"\n ) {\n // if there is already an item queued for opening cancel it\n scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);\n } else if (isGroup) {\n // closeMenus(menuId, itemId);\n scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);\n } else if (\n !(\n (menuState.current[lastOpenedMenu.id] === \"pending-close\") /*&&\n sameLevel*/\n )\n ) {\n closeMenus(menuItemId);\n }\n }\n }\n\n if (state === \"pending-close\") {\n clearAnyScheduledOpenTasks();\n clearTimeout(menuClosePendingTimeout.current);\n menuClosePendingTimeout.current = undefined;\n menuState.current[hostMenuId] = \"popup-open\";\n }\n },\n [\n clearAnyScheduledOpenTasks,\n closeMenus,\n getOpenMenuStatus,\n menuIsOpen,\n rootId,\n scheduleClose,\n scheduleOpen,\n ],\n );\n\n const listItemProps: Partial<MenuItemProps> = useMemo(\n () => ({\n onMouseEnter: (evt: MouseEvent) => {\n const menuItemEl = closestListItem(evt.target as HTMLElement);\n triggerChildMenu(menuItemEl);\n onMouseEnterItem(evt, menuItemEl.id);\n },\n\n onClick: (evt: SyntheticEvent) => {\n const listItemEl = closestListItem(evt.target as HTMLElement);\n const { isGroup, menuItemId } = getMenuItemDetails(listItemEl, rootId);\n if (isGroup) {\n triggerChildMenu(listItemEl);\n } else {\n onActivate(menuItemId);\n }\n },\n }),\n [onActivate, onMouseEnterItem, rootId, triggerChildMenu],\n );\n\n return {\n closeMenu,\n handleRender,\n listItemProps,\n openMenu: triggerChildMenu,\n openMenus: openMenus.current,\n };\n};\n"],"names":["useState","useRef","useCallback","useMemo","closestListItem"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-keyboard-navigation.js","sources":["../../src/menu/use-keyboard-navigation.ts"],"sourcesContent":["import {\n FocusEvent,\n KeyboardEvent,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { hasPopup, isRoot } from \"./utils\";\nimport { isNavigationKey } from \"./key-code\";\nimport { isValidNumber } from \"@vuu-ui/vuu-utils\";\nimport { MenuOpenHandler } from \"./MenuList\";\n\nexport type MenuCloseReason = \"tab-away\" | \"close-child-menu\";\n\nexport type MenuCloseHandler = (\n evt: KeyboardEvent,\n reason: MenuCloseReason,\n) => void;\n\nexport interface KeyboardNavigationProps {\n autoHighlightFirstItem?: boolean;\n count: number;\n defaultHighlightedIdx?: number;\n highlightedIndex?: number;\n onActivate: (idx: number) => void;\n onHighlight?: (idx: number) => void;\n onCloseMenu: MenuCloseHandler;\n onOpenMenu?: MenuOpenHandler;\n}\n\nexport interface KeyboardHookListProps {\n // onBlur: (evt: FocusEvent) => void;\n onFocus: (evt: FocusEvent) => void;\n onKeyDown: (evt: KeyboardEvent) => void;\n onMouseDownCapture: () => void;\n onMouseMove: () => void;\n onMouseLeave: () => void;\n}\n\nexport interface NavigationHookResult {\n focusVisible: number;\n controlledHighlighting: boolean;\n highlightedIndex: number;\n setHighlightedIndex: (idx: number) => void;\n // keyboardNavigation: RefObject<boolean>;\n listProps: KeyboardHookListProps;\n setIgnoreFocus: (ignoreFocus: boolean) => void;\n}\n\n// we need a way to set highlightedIdx when selection changes\nexport const useKeyboardNavigation = ({\n autoHighlightFirstItem = false,\n count,\n defaultHighlightedIdx,\n highlightedIndex: highlightedIndexProp,\n onActivate,\n onHighlight,\n onCloseMenu,\n onOpenMenu,\n}: KeyboardNavigationProps): NavigationHookResult => {\n if (\n isValidNumber(highlightedIndexProp) &&\n isValidNumber(defaultHighlightedIdx)\n ) {\n throw Error(\n \"useKeyboardNavigation do not pass values for both highlightedIndex and defaultHighlightedIdx\",\n );\n }\n\n const controlledHighlighting = isValidNumber(highlightedIndexProp);\n const highlightedIndexRef = useRef(\n defaultHighlightedIdx ??\n highlightedIndexProp ??\n (autoHighlightFirstItem ? 0 : -1),\n );\n const [, forceRender] = useState<unknown>(null);\n\n const setHighlightedIdx = useCallback(\n (idx) => {\n highlightedIndexRef.current = idx;\n onHighlight?.(idx);\n forceRender({});\n },\n [onHighlight],\n );\n\n const setHighlightedIndex = useCallback(\n (idx) => {\n if (idx !== highlightedIndexRef.current) {\n if (!controlledHighlighting) {\n setHighlightedIdx(idx);\n }\n }\n },\n [controlledHighlighting, setHighlightedIdx],\n );\n\n // does this belong here or should it be a method passed in?\n const keyBoardNavigation = useRef(true);\n const ignoreFocus = useRef(false);\n const setIgnoreFocus = (value: boolean) => (ignoreFocus.current = value);\n\n const highlightedIndex = controlledHighlighting\n ? highlightedIndexProp\n : highlightedIndexRef.current;\n\n const navigateChildItems = useCallback(\n (e: KeyboardEvent) => {\n const nextIdx = nextItemIdx(count, e.key, highlightedIndexRef.current);\n if (nextIdx !== highlightedIndexRef.current) {\n setHighlightedIndex(nextIdx);\n }\n },\n [count, setHighlightedIndex],\n );\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (isNavigationKey(e)) {\n e.preventDefault();\n e.stopPropagation();\n keyBoardNavigation.current = true;\n navigateChildItems(e);\n } else if (\n (e.key === \"ArrowRight\" || e.key === \"Enter\") &&\n hasPopup(e.target as HTMLElement, highlightedIndex)\n ) {\n const menuEl = e.target as HTMLElement;\n const menuItemEl = menuEl.querySelector(\n `:scope > [data-index='${highlightedIndex}']`,\n ) as HTMLElement;\n\n if (menuItemEl) {\n onOpenMenu?.(menuItemEl, true);\n }\n } else if (e.key === \"ArrowLeft\" && !isRoot(e.target as HTMLElement)) {\n onCloseMenu(e, \"close-child-menu\");\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n e.stopPropagation();\n onActivate && onActivate(highlightedIndex);\n } else if (e.key === \"Tab\") {\n onCloseMenu(e, \"tab-away\");\n }\n },\n [highlightedIndex, navigateChildItems, onActivate, onCloseMenu, onOpenMenu],\n );\n\n const listProps: KeyboardHookListProps = useMemo(\n () => ({\n onFocus: () => {\n if (highlightedIndex === -1) {\n setHighlightedIdx(0);\n }\n },\n onKeyDown: handleKeyDown,\n onMouseDownCapture: () => {\n keyBoardNavigation.current = false;\n setIgnoreFocus(true);\n },\n\n // onMouseEnter would seem less expensive but it misses some cases\n onMouseMove: () => {\n if (keyBoardNavigation.current) {\n keyBoardNavigation.current = false;\n }\n },\n onMouseLeave: () => {\n keyBoardNavigation.current = true;\n setIgnoreFocus(false);\n setHighlightedIndex(-1);\n },\n }),\n [handleKeyDown, highlightedIndex, setHighlightedIdx, setHighlightedIndex],\n );\n\n return {\n focusVisible: keyBoardNavigation.current ? highlightedIndex : -1,\n controlledHighlighting,\n highlightedIndex,\n setHighlightedIndex: setHighlightedIndex,\n listProps,\n setIgnoreFocus,\n };\n};\n\n// need to be able to accommodate disabled items\nfunction nextItemIdx(count: number, key: string, idx: number) {\n if (key === \"ArrowUp\") {\n if (idx > 0) {\n return idx - 1;\n } else {\n return idx;\n }\n } else {\n if (idx === null) {\n return 0;\n } else if (idx === count - 1) {\n return idx;\n } else {\n return idx + 1;\n }\n }\n}\n"],"names":["isValidNumber","useRef","useState","useCallback","isNavigationKey","hasPopup","isRoot","useMemo"],"mappings":";;;;;;;AAmDO,MAAM,wBAAwB,CAAC;AAAA,EACpC,sBAAyB,GAAA,KAAA;AAAA,EACzB,KAAA;AAAA,EACA,qBAAA;AAAA,EACA,gBAAkB,EAAA,oBAAA;AAAA,EAClB,UAAA;AAAA,EACA,WAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAqD,KAAA;AACnD,EAAA,IACEA,sBAAc,CAAA,oBAAoB,CAClC,IAAAA,sBAAA,CAAc,qBAAqB,CACnC,EAAA;AACA,IAAM,MAAA,KAAA;AAAA,MACJ;AAAA,KACF;AAAA;AAGF,EAAM,MAAA,sBAAA,GAAyBA,uBAAc,oBAAoB,CAAA;AACjE,EAAA,MAAM,mBAAsB,GAAAC,YAAA;AAAA,IAC1B,qBAAA,IACE,oBACC,KAAA,sBAAA,GAAyB,CAAI,GAAA,CAAA,CAAA;AAAA,GAClC;AACA,EAAA,MAAM,GAAG,WAAW,CAAA,GAAIC,eAAkB,IAAI,CAAA;AAE9C,EAAA,MAAM,iBAAoB,GAAAC,iBAAA;AAAA,IACxB,CAAC,
|
|
1
|
+
{"version":3,"file":"use-keyboard-navigation.js","sources":["../../src/menu/use-keyboard-navigation.ts"],"sourcesContent":["import {\n FocusEvent,\n KeyboardEvent,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { hasPopup, isRoot } from \"./utils\";\nimport { isNavigationKey } from \"./key-code\";\nimport { isValidNumber } from \"@vuu-ui/vuu-utils\";\nimport { MenuOpenHandler } from \"./MenuList\";\n\nexport type MenuCloseReason = \"tab-away\" | \"close-child-menu\";\n\nexport type MenuCloseHandler = (\n evt: KeyboardEvent,\n reason: MenuCloseReason,\n) => void;\n\nexport interface KeyboardNavigationProps {\n autoHighlightFirstItem?: boolean;\n count: number;\n defaultHighlightedIdx?: number;\n highlightedIndex?: number;\n onActivate: (idx: number) => void;\n onHighlight?: (idx: number) => void;\n onCloseMenu: MenuCloseHandler;\n onOpenMenu?: MenuOpenHandler;\n}\n\nexport interface KeyboardHookListProps {\n // onBlur: (evt: FocusEvent) => void;\n onFocus: (evt: FocusEvent) => void;\n onKeyDown: (evt: KeyboardEvent) => void;\n onMouseDownCapture: () => void;\n onMouseMove: () => void;\n onMouseLeave: () => void;\n}\n\nexport interface NavigationHookResult {\n focusVisible: number;\n controlledHighlighting: boolean;\n highlightedIndex: number;\n setHighlightedIndex: (idx: number) => void;\n // keyboardNavigation: RefObject<boolean>;\n listProps: KeyboardHookListProps;\n setIgnoreFocus: (ignoreFocus: boolean) => void;\n}\n\n// we need a way to set highlightedIdx when selection changes\nexport const useKeyboardNavigation = ({\n autoHighlightFirstItem = false,\n count,\n defaultHighlightedIdx,\n highlightedIndex: highlightedIndexProp,\n onActivate,\n onHighlight,\n onCloseMenu,\n onOpenMenu,\n}: KeyboardNavigationProps): NavigationHookResult => {\n if (\n isValidNumber(highlightedIndexProp) &&\n isValidNumber(defaultHighlightedIdx)\n ) {\n throw Error(\n \"useKeyboardNavigation do not pass values for both highlightedIndex and defaultHighlightedIdx\",\n );\n }\n\n const controlledHighlighting = isValidNumber(highlightedIndexProp);\n const highlightedIndexRef = useRef(\n defaultHighlightedIdx ??\n highlightedIndexProp ??\n (autoHighlightFirstItem ? 0 : -1),\n );\n const [, forceRender] = useState<unknown>(null);\n\n const setHighlightedIdx = useCallback(\n (idx: number) => {\n highlightedIndexRef.current = idx;\n onHighlight?.(idx);\n forceRender({});\n },\n [onHighlight],\n );\n\n const setHighlightedIndex = useCallback(\n (idx: number) => {\n if (idx !== highlightedIndexRef.current) {\n if (!controlledHighlighting) {\n setHighlightedIdx(idx);\n }\n }\n },\n [controlledHighlighting, setHighlightedIdx],\n );\n\n // does this belong here or should it be a method passed in?\n const keyBoardNavigation = useRef(true);\n const ignoreFocus = useRef(false);\n const setIgnoreFocus = (value: boolean) => (ignoreFocus.current = value);\n\n const highlightedIndex = controlledHighlighting\n ? highlightedIndexProp\n : highlightedIndexRef.current;\n\n const navigateChildItems = useCallback(\n (e: KeyboardEvent) => {\n const nextIdx = nextItemIdx(count, e.key, highlightedIndexRef.current);\n if (nextIdx !== highlightedIndexRef.current) {\n setHighlightedIndex(nextIdx);\n }\n },\n [count, setHighlightedIndex],\n );\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (isNavigationKey(e)) {\n e.preventDefault();\n e.stopPropagation();\n keyBoardNavigation.current = true;\n navigateChildItems(e);\n } else if (\n (e.key === \"ArrowRight\" || e.key === \"Enter\") &&\n hasPopup(e.target as HTMLElement, highlightedIndex)\n ) {\n const menuEl = e.target as HTMLElement;\n const menuItemEl = menuEl.querySelector(\n `:scope > [data-index='${highlightedIndex}']`,\n ) as HTMLElement;\n\n if (menuItemEl) {\n onOpenMenu?.(menuItemEl, true);\n }\n } else if (e.key === \"ArrowLeft\" && !isRoot(e.target as HTMLElement)) {\n onCloseMenu(e, \"close-child-menu\");\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n e.stopPropagation();\n onActivate && onActivate(highlightedIndex);\n } else if (e.key === \"Tab\") {\n onCloseMenu(e, \"tab-away\");\n }\n },\n [highlightedIndex, navigateChildItems, onActivate, onCloseMenu, onOpenMenu],\n );\n\n const listProps: KeyboardHookListProps = useMemo(\n () => ({\n onFocus: () => {\n if (highlightedIndex === -1) {\n setHighlightedIdx(0);\n }\n },\n onKeyDown: handleKeyDown,\n onMouseDownCapture: () => {\n keyBoardNavigation.current = false;\n setIgnoreFocus(true);\n },\n\n // onMouseEnter would seem less expensive but it misses some cases\n onMouseMove: () => {\n if (keyBoardNavigation.current) {\n keyBoardNavigation.current = false;\n }\n },\n onMouseLeave: () => {\n keyBoardNavigation.current = true;\n setIgnoreFocus(false);\n setHighlightedIndex(-1);\n },\n }),\n [handleKeyDown, highlightedIndex, setHighlightedIdx, setHighlightedIndex],\n );\n\n return {\n focusVisible: keyBoardNavigation.current ? highlightedIndex : -1,\n controlledHighlighting,\n highlightedIndex,\n setHighlightedIndex: setHighlightedIndex,\n listProps,\n setIgnoreFocus,\n };\n};\n\n// need to be able to accommodate disabled items\nfunction nextItemIdx(count: number, key: string, idx: number) {\n if (key === \"ArrowUp\") {\n if (idx > 0) {\n return idx - 1;\n } else {\n return idx;\n }\n } else {\n if (idx === null) {\n return 0;\n } else if (idx === count - 1) {\n return idx;\n } else {\n return idx + 1;\n }\n }\n}\n"],"names":["isValidNumber","useRef","useState","useCallback","isNavigationKey","hasPopup","isRoot","useMemo"],"mappings":";;;;;;;AAmDO,MAAM,wBAAwB,CAAC;AAAA,EACpC,sBAAyB,GAAA,KAAA;AAAA,EACzB,KAAA;AAAA,EACA,qBAAA;AAAA,EACA,gBAAkB,EAAA,oBAAA;AAAA,EAClB,UAAA;AAAA,EACA,WAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAqD,KAAA;AACnD,EAAA,IACEA,sBAAc,CAAA,oBAAoB,CAClC,IAAAA,sBAAA,CAAc,qBAAqB,CACnC,EAAA;AACA,IAAM,MAAA,KAAA;AAAA,MACJ;AAAA,KACF;AAAA;AAGF,EAAM,MAAA,sBAAA,GAAyBA,uBAAc,oBAAoB,CAAA;AACjE,EAAA,MAAM,mBAAsB,GAAAC,YAAA;AAAA,IAC1B,qBAAA,IACE,oBACC,KAAA,sBAAA,GAAyB,CAAI,GAAA,CAAA,CAAA;AAAA,GAClC;AACA,EAAA,MAAM,GAAG,WAAW,CAAA,GAAIC,eAAkB,IAAI,CAAA;AAE9C,EAAA,MAAM,iBAAoB,GAAAC,iBAAA;AAAA,IACxB,CAAC,GAAgB,KAAA;AACf,MAAA,mBAAA,CAAoB,OAAU,GAAA,GAAA;AAC9B,MAAA,WAAA,GAAc,GAAG,CAAA;AACjB,MAAA,WAAA,CAAY,EAAE,CAAA;AAAA,KAChB;AAAA,IACA,CAAC,WAAW;AAAA,GACd;AAEA,EAAA,MAAM,mBAAsB,GAAAA,iBAAA;AAAA,IAC1B,CAAC,GAAgB,KAAA;AACf,MAAI,IAAA,GAAA,KAAQ,oBAAoB,OAAS,EAAA;AACvC,QAAA,IAAI,CAAC,sBAAwB,EAAA;AAC3B,UAAA,iBAAA,CAAkB,GAAG,CAAA;AAAA;AACvB;AACF,KACF;AAAA,IACA,CAAC,wBAAwB,iBAAiB;AAAA,GAC5C;AAGA,EAAM,MAAA,kBAAA,GAAqBF,aAAO,IAAI,CAAA;AACtC,EAAM,MAAA,WAAA,GAAcA,aAAO,KAAK,CAAA;AAChC,EAAA,MAAM,cAAiB,GAAA,CAAC,KAAoB,KAAA,WAAA,CAAY,OAAU,GAAA,KAAA;AAElE,EAAM,MAAA,gBAAA,GAAmB,sBACrB,GAAA,oBAAA,GACA,mBAAoB,CAAA,OAAA;AAExB,EAAA,MAAM,kBAAqB,GAAAE,iBAAA;AAAA,IACzB,CAAC,CAAqB,KAAA;AACpB,MAAA,MAAM,UAAU,WAAY,CAAA,KAAA,EAAO,CAAE,CAAA,GAAA,EAAK,oBAAoB,OAAO,CAAA;AACrE,MAAI,IAAA,OAAA,KAAY,oBAAoB,OAAS,EAAA;AAC3C,QAAA,mBAAA,CAAoB,OAAO,CAAA;AAAA;AAC7B,KACF;AAAA,IACA,CAAC,OAAO,mBAAmB;AAAA,GAC7B;AAEA,EAAA,MAAM,aAAgB,GAAAA,iBAAA;AAAA,IACpB,CAAC,CAAqB,KAAA;AACpB,MAAI,IAAAC,uBAAA,CAAgB,CAAC,CAAG,EAAA;AACtB,QAAA,CAAA,CAAE,cAAe,EAAA;AACjB,QAAA,CAAA,CAAE,eAAgB,EAAA;AAClB,QAAA,kBAAA,CAAmB,OAAU,GAAA,IAAA;AAC7B,QAAA,kBAAA,CAAmB,CAAC,CAAA;AAAA,OACtB,MAAA,IAAA,CACG,CAAE,CAAA,GAAA,KAAQ,YAAgB,IAAA,CAAA,CAAE,GAAQ,KAAA,OAAA,KACrCC,cAAS,CAAA,CAAA,CAAE,MAAuB,EAAA,gBAAgB,CAClD,EAAA;AACA,QAAA,MAAM,SAAS,CAAE,CAAA,MAAA;AACjB,QAAA,MAAM,aAAa,MAAO,CAAA,aAAA;AAAA,UACxB,yBAAyB,gBAAgB,CAAA,EAAA;AAAA,SAC3C;AAEA,QAAA,IAAI,UAAY,EAAA;AACd,UAAA,UAAA,GAAa,YAAY,IAAI,CAAA;AAAA;AAC/B,OACF,MAAA,IAAW,EAAE,GAAQ,KAAA,WAAA,IAAe,CAACC,YAAO,CAAA,CAAA,CAAE,MAAqB,CAAG,EAAA;AACpE,QAAA,WAAA,CAAY,GAAG,kBAAkB,CAAA;AAAA,OACnC,MAAA,IAAW,CAAE,CAAA,GAAA,KAAQ,OAAS,EAAA;AAC5B,QAAA,CAAA,CAAE,cAAe,EAAA;AACjB,QAAA,CAAA,CAAE,eAAgB,EAAA;AAClB,QAAA,UAAA,IAAc,WAAW,gBAAgB,CAAA;AAAA,OAC3C,MAAA,IAAW,CAAE,CAAA,GAAA,KAAQ,KAAO,EAAA;AAC1B,QAAA,WAAA,CAAY,GAAG,UAAU,CAAA;AAAA;AAC3B,KACF;AAAA,IACA,CAAC,gBAAA,EAAkB,kBAAoB,EAAA,UAAA,EAAY,aAAa,UAAU;AAAA,GAC5E;AAEA,EAAA,MAAM,SAAmC,GAAAC,aAAA;AAAA,IACvC,OAAO;AAAA,MACL,SAAS,MAAM;AACb,QAAA,IAAI,qBAAqB,CAAI,CAAA,EAAA;AAC3B,UAAA,iBAAA,CAAkB,CAAC,CAAA;AAAA;AACrB,OACF;AAAA,MACA,SAAW,EAAA,aAAA;AAAA,MACX,oBAAoB,MAAM;AACxB,QAAA,kBAAA,CAAmB,OAAU,GAAA,KAAA;AAC7B,QAAA,cAAA,CAAe,IAAI,CAAA;AAAA,OACrB;AAAA;AAAA,MAGA,aAAa,MAAM;AACjB,QAAA,IAAI,mBAAmB,OAAS,EAAA;AAC9B,UAAA,kBAAA,CAAmB,OAAU,GAAA,KAAA;AAAA;AAC/B,OACF;AAAA,MACA,cAAc,MAAM;AAClB,QAAA,kBAAA,CAAmB,OAAU,GAAA,IAAA;AAC7B,QAAA,cAAA,CAAe,KAAK,CAAA;AACpB,QAAA,mBAAA,CAAoB,CAAE,CAAA,CAAA;AAAA;AACxB,KACF,CAAA;AAAA,IACA,CAAC,aAAA,EAAe,gBAAkB,EAAA,iBAAA,EAAmB,mBAAmB;AAAA,GAC1E;AAEA,EAAO,OAAA;AAAA,IACL,YAAA,EAAc,kBAAmB,CAAA,OAAA,GAAU,gBAAmB,GAAA,CAAA,CAAA;AAAA,IAC9D,sBAAA;AAAA,IACA,gBAAA;AAAA,IACA,mBAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,GACF;AACF;AAGA,SAAS,WAAA,CAAY,KAAe,EAAA,GAAA,EAAa,GAAa,EAAA;AAC5D,EAAA,IAAI,QAAQ,SAAW,EAAA;AACrB,IAAA,IAAI,MAAM,CAAG,EAAA;AACX,MAAA,OAAO,GAAM,GAAA,CAAA;AAAA,KACR,MAAA;AACL,MAAO,OAAA,GAAA;AAAA;AACT,GACK,MAAA;AACL,IAAA,IAAI,QAAQ,IAAM,EAAA;AAChB,MAAO,OAAA,CAAA;AAAA,KACT,MAAA,IAAW,GAAQ,KAAA,KAAA,GAAQ,CAAG,EAAA;AAC5B,MAAO,OAAA,GAAA;AAAA,KACF,MAAA;AACL,MAAA,OAAO,GAAM,GAAA,CAAA;AAAA;AACf;AAEJ;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useContextMenu.js","sources":["../../src/menu/useContextMenu.tsx"],"sourcesContent":["import {\n ContextMenuItemDescriptor,\n MenuActionHandler,\n MenuBuilder,\n} from \"@vuu-ui/vuu-data-types\";\nimport { ColumnDescriptor } from \"@vuu-ui/vuu-table-types\";\nimport {\n isGroupMenuItemDescriptor,\n useThemeAttributes,\n} from \"@vuu-ui/vuu-utils\";\nimport { cloneElement, useCallback, useContext, useMemo } from \"react\";\nimport {\n MenuActionClosePopup,\n PopupCloseReason,\n PopupService,\n reasonIsMenuAction,\n} from \"../popup\";\nimport { ContextMenu, ContextMenuProps } from \"./ContextMenu\";\nimport { MenuItem, MenuItemGroup } from \"./MenuList\";\nimport { ContextMenuContext } from \"./context-menu-provider\";\n\nexport type ContextMenuOptions = {\n [key: string]: unknown;\n columns?: ColumnDescriptor[];\n contextMenu?: JSX.Element;\n ContextMenuProps?: Partial<ContextMenuProps> & {\n className?: string;\n };\n controlledComponentId?: string;\n};\n\nexport type EventLike = {\n clientX: number;\n clientY: number;\n preventDefault?: () => void;\n stopPropagation?: () => void;\n};\n\nexport type ShowContextMenu = (\n e: EventLike,\n location: string,\n options: ContextMenuOptions,\n) => void;\n\n// The argument allows a top-level menuBuilder to operate outside the Context\nexport const useContextMenu = (\n menuBuilder?: MenuBuilder,\n menuActionHandler?: MenuActionHandler,\n): [ShowContextMenu, () => void] => {\n const ctx = useContext(ContextMenuContext);\n\n const [themeClass, densityClass, dataMode] = useThemeAttributes();\n const themeAttributes = useMemo(\n () => ({\n themeClass,\n densityClass,\n dataMode,\n }),\n [dataMode, densityClass, themeClass],\n );\n\n const buildMenuOptions = useCallback(\n (menuBuilders: MenuBuilder[], location, options) => {\n let results: ContextMenuItemDescriptor[] = [];\n for (const menuBuilder of menuBuilders) {\n // Maybe we should leave the concatenation to the menuBuilder, then it can control menuItem order\n results = results.concat(menuBuilder(location, options));\n }\n return results;\n },\n [],\n );\n\n const handleShowContextMenu = useCallback<ShowContextMenu>(\n (e, location, { ContextMenuProps, contextMenu, ...options }) => {\n e.stopPropagation?.();\n e.preventDefault?.();\n\n if (contextMenu) {\n return showContextMenuComponent(\n {\n x: e.clientX,\n y: e.clientY,\n },\n contextMenu,\n );\n }\n\n const menuBuilders: MenuBuilder[] = [];\n if (menuBuilder) {\n menuBuilders.push(menuBuilder);\n }\n if (\n ctx &&\n Array.isArray(ctx?.menuBuilders) &&\n ctx.menuBuilders.length > 0\n ) {\n menuBuilders.push(...ctx.menuBuilders);\n }\n\n if (menuBuilders.length > 0) {\n const menuItemDescriptors = buildMenuOptions(\n menuBuilders,\n location,\n options,\n );\n\n // const menuHandler = menuActionHandler ?? ctx?.menuActionHandler;\n const menuHandler: MenuActionHandler = (\n action: MenuActionClosePopup,\n ) => {\n if (menuActionHandler?.(action) === true) {\n return true;\n } else {\n return ctx?.menuActionHandler(action);\n }\n };\n\n if (menuItemDescriptors.length && menuHandler) {\n // because showPopup is going to be used to render the context menu, it will not\n // have access to the ContextMenuContext. Pass the theme attributes here\n showContextMenu(e, menuItemDescriptors, menuHandler, {\n PortalProps: {\n themeAttributes,\n },\n ...ContextMenuProps,\n });\n }\n } else {\n console.warn(\n \"useContextMenu, no menuBuilders configured. These should be supplied via the ContextMenuProvider(s)\",\n );\n }\n },\n [buildMenuOptions, ctx, menuActionHandler, menuBuilder, themeAttributes],\n );\n\n const hideContextMenu = useCallback(() => {\n console.log(\"hide context menu\");\n }, []);\n\n return [handleShowContextMenu, hideContextMenu];\n};\n\nconst NO_OPTIONS = {};\n\nconst showContextMenuComponent = (\n position: { x: number; y: number },\n contextMenu: JSX.Element,\n) => {\n PopupService.showPopup({\n focus: true,\n left: 0,\n top: 0,\n component: cloneElement(contextMenu, { position }),\n });\n};\n\nconst showContextMenu = (\n e: EventLike,\n menuDescriptors: ContextMenuItemDescriptor[],\n handleContextMenuAction: MenuActionHandler,\n {\n position: positionProp,\n ...contextMenuProps\n }: ContextMenuOptions[\"ContextMenuProps\"] = NO_OPTIONS,\n) => {\n const menuItems = (menuDescriptors: ContextMenuItemDescriptor[]) => {\n const fromDescriptor = (menuItem: ContextMenuItemDescriptor, i: number) =>\n isGroupMenuItemDescriptor(menuItem) ? (\n <MenuItemGroup key={i} label={menuItem.label}>\n {menuItem.children.map(fromDescriptor)}\n </MenuItemGroup>\n ) : (\n <MenuItem\n key={i}\n action={menuItem.action}\n className={menuItem.className}\n data-icon={menuItem.icon}\n options={menuItem.options}\n >\n {menuItem.label}\n </MenuItem>\n );\n\n return menuDescriptors.map(fromDescriptor);\n };\n\n const handleClose = (reason?: PopupCloseReason) => {\n if (reasonIsMenuAction(reason)) {\n if (reason?.closedBy === \"popup-service\") {\n return;\n }\n handleContextMenuAction(reason);\n // TODO this results in onClose being called twice on component\n // cant simply be removed, some refactoring work needed\n PopupService.hidePopup(reason);\n }\n contextMenuProps?.onClose?.(reason);\n };\n\n const position = positionProp ?? {\n x: e.clientX,\n y: e.clientY,\n };\n\n const component = (\n <ContextMenu\n {...contextMenuProps}\n onClose={handleClose}\n position={position}\n >\n {menuItems(menuDescriptors)}\n </ContextMenu>\n );\n PopupService.showPopup({ left: 0, top: 0, component, focus: true });\n};\n"],"names":["useContext","ContextMenuContext","useThemeAttributes","useMemo","useCallback","menuBuilder","ContextMenuProps","PopupService","cloneElement","menuDescriptors","isGroupMenuItemDescriptor","jsx","MenuItemGroup","MenuItem","reasonIsMenuAction","ContextMenu"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useContextMenu.js","sources":["../../src/menu/useContextMenu.tsx"],"sourcesContent":["import {\n ContextMenuItemDescriptor,\n MenuActionHandler,\n MenuBuilder,\n} from \"@vuu-ui/vuu-data-types\";\nimport { ColumnDescriptor } from \"@vuu-ui/vuu-table-types\";\nimport {\n isGroupMenuItemDescriptor,\n useThemeAttributes,\n} from \"@vuu-ui/vuu-utils\";\nimport { cloneElement, useCallback, useContext, useMemo } from \"react\";\nimport {\n MenuActionClosePopup,\n PopupCloseReason,\n PopupService,\n reasonIsMenuAction,\n} from \"../popup\";\nimport { ContextMenu, ContextMenuProps } from \"./ContextMenu\";\nimport { MenuItem, MenuItemGroup } from \"./MenuList\";\nimport { ContextMenuContext } from \"./context-menu-provider\";\n\nexport type ContextMenuOptions = {\n [key: string]: unknown;\n columns?: ColumnDescriptor[];\n contextMenu?: JSX.Element;\n ContextMenuProps?: Partial<ContextMenuProps> & {\n className?: string;\n };\n controlledComponentId?: string;\n};\n\nexport type EventLike = {\n clientX: number;\n clientY: number;\n preventDefault?: () => void;\n stopPropagation?: () => void;\n};\n\nexport type ShowContextMenu = (\n e: EventLike,\n location: string,\n options: ContextMenuOptions,\n) => void;\n\n// The argument allows a top-level menuBuilder to operate outside the Context\nexport const useContextMenu = (\n menuBuilder?: MenuBuilder,\n menuActionHandler?: MenuActionHandler,\n): [ShowContextMenu, () => void] => {\n const ctx = useContext(ContextMenuContext);\n\n const [themeClass, densityClass, dataMode] = useThemeAttributes();\n const themeAttributes = useMemo(\n () => ({\n themeClass,\n densityClass,\n dataMode,\n }),\n [dataMode, densityClass, themeClass],\n );\n\n const buildMenuOptions = useCallback(\n (menuBuilders: MenuBuilder[], location: string, options: unknown) => {\n let results: ContextMenuItemDescriptor[] = [];\n for (const menuBuilder of menuBuilders) {\n // Maybe we should leave the concatenation to the menuBuilder, then it can control menuItem order\n results = results.concat(menuBuilder(location, options));\n }\n return results;\n },\n [],\n );\n\n const handleShowContextMenu = useCallback<ShowContextMenu>(\n (e, location, { ContextMenuProps, contextMenu, ...options }) => {\n e.stopPropagation?.();\n e.preventDefault?.();\n\n if (contextMenu) {\n return showContextMenuComponent(\n {\n x: e.clientX,\n y: e.clientY,\n },\n contextMenu,\n );\n }\n\n const menuBuilders: MenuBuilder[] = [];\n if (menuBuilder) {\n menuBuilders.push(menuBuilder);\n }\n if (\n ctx &&\n Array.isArray(ctx?.menuBuilders) &&\n ctx.menuBuilders.length > 0\n ) {\n menuBuilders.push(...ctx.menuBuilders);\n }\n\n if (menuBuilders.length > 0) {\n const menuItemDescriptors = buildMenuOptions(\n menuBuilders,\n location,\n options,\n );\n\n // const menuHandler = menuActionHandler ?? ctx?.menuActionHandler;\n const menuHandler: MenuActionHandler = (\n action: MenuActionClosePopup,\n ) => {\n if (menuActionHandler?.(action) === true) {\n return true;\n } else {\n return ctx?.menuActionHandler(action);\n }\n };\n\n if (menuItemDescriptors.length && menuHandler) {\n // because showPopup is going to be used to render the context menu, it will not\n // have access to the ContextMenuContext. Pass the theme attributes here\n showContextMenu(e, menuItemDescriptors, menuHandler, {\n PortalProps: {\n themeAttributes,\n },\n ...ContextMenuProps,\n });\n }\n } else {\n console.warn(\n \"useContextMenu, no menuBuilders configured. These should be supplied via the ContextMenuProvider(s)\",\n );\n }\n },\n [buildMenuOptions, ctx, menuActionHandler, menuBuilder, themeAttributes],\n );\n\n const hideContextMenu = useCallback(() => {\n console.log(\"hide context menu\");\n }, []);\n\n return [handleShowContextMenu, hideContextMenu];\n};\n\nconst NO_OPTIONS = {};\n\nconst showContextMenuComponent = (\n position: { x: number; y: number },\n contextMenu: JSX.Element,\n) => {\n PopupService.showPopup({\n focus: true,\n left: 0,\n top: 0,\n component: cloneElement(contextMenu, { position }),\n });\n};\n\nconst showContextMenu = (\n e: EventLike,\n menuDescriptors: ContextMenuItemDescriptor[],\n handleContextMenuAction: MenuActionHandler,\n {\n position: positionProp,\n ...contextMenuProps\n }: ContextMenuOptions[\"ContextMenuProps\"] = NO_OPTIONS,\n) => {\n const menuItems = (menuDescriptors: ContextMenuItemDescriptor[]) => {\n const fromDescriptor = (menuItem: ContextMenuItemDescriptor, i: number) =>\n isGroupMenuItemDescriptor(menuItem) ? (\n <MenuItemGroup key={i} label={menuItem.label}>\n {menuItem.children.map(fromDescriptor)}\n </MenuItemGroup>\n ) : (\n <MenuItem\n key={i}\n action={menuItem.action}\n className={menuItem.className}\n data-icon={menuItem.icon}\n options={menuItem.options}\n >\n {menuItem.label}\n </MenuItem>\n );\n\n return menuDescriptors.map(fromDescriptor);\n };\n\n const handleClose = (reason?: PopupCloseReason) => {\n if (reasonIsMenuAction(reason)) {\n if (reason?.closedBy === \"popup-service\") {\n return;\n }\n handleContextMenuAction(reason);\n // TODO this results in onClose being called twice on component\n // cant simply be removed, some refactoring work needed\n PopupService.hidePopup(reason);\n }\n contextMenuProps?.onClose?.(reason);\n };\n\n const position = positionProp ?? {\n x: e.clientX,\n y: e.clientY,\n };\n\n const component = (\n <ContextMenu\n {...contextMenuProps}\n onClose={handleClose}\n position={position}\n >\n {menuItems(menuDescriptors)}\n </ContextMenu>\n );\n PopupService.showPopup({ left: 0, top: 0, component, focus: true });\n};\n"],"names":["useContext","ContextMenuContext","useThemeAttributes","useMemo","useCallback","menuBuilder","ContextMenuProps","PopupService","cloneElement","menuDescriptors","isGroupMenuItemDescriptor","jsx","MenuItemGroup","MenuItem","reasonIsMenuAction","ContextMenu"],"mappings":";;;;;;;;;;;;;AA6Ca,MAAA,cAAA,GAAiB,CAC5B,WAAA,EACA,iBACkC,KAAA;AAClC,EAAM,MAAA,GAAA,GAAMA,iBAAWC,sCAAkB,CAAA;AAEzC,EAAA,MAAM,CAAC,UAAA,EAAY,YAAc,EAAA,QAAQ,IAAIC,2BAAmB,EAAA;AAChE,EAAA,MAAM,eAAkB,GAAAC,aAAA;AAAA,IACtB,OAAO;AAAA,MACL,UAAA;AAAA,MACA,YAAA;AAAA,MACA;AAAA,KACF,CAAA;AAAA,IACA,CAAC,QAAU,EAAA,YAAA,EAAc,UAAU;AAAA,GACrC;AAEA,EAAA,MAAM,gBAAmB,GAAAC,iBAAA;AAAA,IACvB,CAAC,YAA6B,EAAA,QAAA,EAAkB,OAAqB,KAAA;AACnE,MAAA,IAAI,UAAuC,EAAC;AAC5C,MAAA,KAAA,MAAWC,gBAAe,YAAc,EAAA;AAEtC,QAAA,OAAA,GAAU,OAAQ,CAAA,MAAA,CAAOA,YAAY,CAAA,QAAA,EAAU,OAAO,CAAC,CAAA;AAAA;AAEzD,MAAO,OAAA,OAAA;AAAA,KACT;AAAA,IACA;AAAC,GACH;AAEA,EAAA,MAAM,qBAAwB,GAAAD,iBAAA;AAAA,IAC5B,CAAC,GAAG,QAAU,EAAA,EAAE,kBAAAE,iBAAkB,EAAA,WAAA,EAAa,GAAG,OAAA,EAAc,KAAA;AAC9D,MAAA,CAAA,CAAE,eAAkB,IAAA;AACpB,MAAA,CAAA,CAAE,cAAiB,IAAA;AAEnB,MAAA,IAAI,WAAa,EAAA;AACf,QAAO,OAAA,wBAAA;AAAA,UACL;AAAA,YACE,GAAG,CAAE,CAAA,OAAA;AAAA,YACL,GAAG,CAAE,CAAA;AAAA,WACP;AAAA,UACA;AAAA,SACF;AAAA;AAGF,MAAA,MAAM,eAA8B,EAAC;AACrC,MAAA,IAAI,WAAa,EAAA;AACf,QAAA,YAAA,CAAa,KAAK,WAAW,CAAA;AAAA;AAE/B,MACE,IAAA,GAAA,IACA,MAAM,OAAQ,CAAA,GAAA,EAAK,YAAY,CAC/B,IAAA,GAAA,CAAI,YAAa,CAAA,MAAA,GAAS,CAC1B,EAAA;AACA,QAAa,YAAA,CAAA,IAAA,CAAK,GAAG,GAAA,CAAI,YAAY,CAAA;AAAA;AAGvC,MAAI,IAAA,YAAA,CAAa,SAAS,CAAG,EAAA;AAC3B,QAAA,MAAM,mBAAsB,GAAA,gBAAA;AAAA,UAC1B,YAAA;AAAA,UACA,QAAA;AAAA,UACA;AAAA,SACF;AAGA,QAAM,MAAA,WAAA,GAAiC,CACrC,MACG,KAAA;AACH,UAAI,IAAA,iBAAA,GAAoB,MAAM,CAAA,KAAM,IAAM,EAAA;AACxC,YAAO,OAAA,IAAA;AAAA,WACF,MAAA;AACL,YAAO,OAAA,GAAA,EAAK,kBAAkB,MAAM,CAAA;AAAA;AACtC,SACF;AAEA,QAAI,IAAA,mBAAA,CAAoB,UAAU,WAAa,EAAA;AAG7C,UAAgB,eAAA,CAAA,CAAA,EAAG,qBAAqB,WAAa,EAAA;AAAA,YACnD,WAAa,EAAA;AAAA,cACX;AAAA,aACF;AAAA,YACA,GAAGA;AAAA,WACJ,CAAA;AAAA;AACH,OACK,MAAA;AACL,QAAQ,OAAA,CAAA,IAAA;AAAA,UACN;AAAA,SACF;AAAA;AACF,KACF;AAAA,IACA,CAAC,gBAAA,EAAkB,GAAK,EAAA,iBAAA,EAAmB,aAAa,eAAe;AAAA,GACzE;AAEA,EAAM,MAAA,eAAA,GAAkBF,kBAAY,MAAM;AACxC,IAAA,OAAA,CAAQ,IAAI,mBAAmB,CAAA;AAAA,GACjC,EAAG,EAAE,CAAA;AAEL,EAAO,OAAA,CAAC,uBAAuB,eAAe,CAAA;AAChD;AAEA,MAAM,aAAa,EAAC;AAEpB,MAAM,wBAAA,GAA2B,CAC/B,QAAA,EACA,WACG,KAAA;AACH,EAAAG,yBAAA,CAAa,SAAU,CAAA;AAAA,IACrB,KAAO,EAAA,IAAA;AAAA,IACP,IAAM,EAAA,CAAA;AAAA,IACN,GAAK,EAAA,CAAA;AAAA,IACL,SAAW,EAAAC,kBAAA,CAAa,WAAa,EAAA,EAAE,UAAU;AAAA,GAClD,CAAA;AACH,CAAA;AAEA,MAAM,eAAkB,GAAA,CACtB,CACA,EAAA,eAAA,EACA,uBACA,EAAA;AAAA,EACE,QAAU,EAAA,YAAA;AAAA,EACV,GAAG;AACL,CAAA,GAA4C,UACzC,KAAA;AACH,EAAM,MAAA,SAAA,GAAY,CAACC,gBAAiD,KAAA;AAClE,IAAA,MAAM,iBAAiB,CAAC,QAAA,EAAqC,MAC3DC,kCAA0B,CAAA,QAAQ,oBAC/BC,cAAA,CAAAC,sBAAA,EAAA,EAAsB,KAAO,EAAA,QAAA,CAAS,OACpC,QAAS,EAAA,QAAA,CAAA,QAAA,CAAS,IAAI,cAAc,CAAA,EAAA,EADnB,CAEpB,CAEA,mBAAAD,cAAA;AAAA,MAACE,iBAAA;AAAA,MAAA;AAAA,QAEC,QAAQ,QAAS,CAAA,MAAA;AAAA,QACjB,WAAW,QAAS,CAAA,SAAA;AAAA,QACpB,aAAW,QAAS,CAAA,IAAA;AAAA,QACpB,SAAS,QAAS,CAAA,OAAA;AAAA,QAEjB,QAAS,EAAA,QAAA,CAAA;AAAA,OAAA;AAAA,MANL;AAAA,KAOP;AAGJ,IAAOJ,OAAAA,gBAAAA,CAAgB,IAAI,cAAc,CAAA;AAAA,GAC3C;AAEA,EAAM,MAAA,WAAA,GAAc,CAAC,MAA8B,KAAA;AACjD,IAAI,IAAAK,+BAAA,CAAmB,MAAM,CAAG,EAAA;AAC9B,MAAI,IAAA,MAAA,EAAQ,aAAa,eAAiB,EAAA;AACxC,QAAA;AAAA;AAEF,MAAA,uBAAA,CAAwB,MAAM,CAAA;AAG9B,MAAAP,yBAAA,CAAa,UAAU,MAAM,CAAA;AAAA;AAE/B,IAAA,gBAAA,EAAkB,UAAU,MAAM,CAAA;AAAA,GACpC;AAEA,EAAA,MAAM,WAAW,YAAgB,IAAA;AAAA,IAC/B,GAAG,CAAE,CAAA,OAAA;AAAA,IACL,GAAG,CAAE,CAAA;AAAA,GACP;AAEA,EAAA,MAAM,SACJ,mBAAAI,cAAA;AAAA,IAACI,uBAAA;AAAA,IAAA;AAAA,MACE,GAAG,gBAAA;AAAA,MACJ,OAAS,EAAA,WAAA;AAAA,MACT,QAAA;AAAA,MAEC,oBAAU,eAAe;AAAA;AAAA,GAC5B;AAEF,EAAaR,yBAAA,CAAA,SAAA,CAAU,EAAE,IAAM,EAAA,CAAA,EAAG,KAAK,CAAG,EAAA,SAAA,EAAW,KAAO,EAAA,IAAA,EAAM,CAAA;AACpE,CAAA;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePopupMenu.js","sources":["../../src/popup-menu/usePopupMenu.ts"],"sourcesContent":["import {\n AriaAttributes,\n MouseEvent,\n useCallback,\n useRef,\n useState,\n} from \"react\";\nimport { MenuOpenHandler } from \"../menu\";\nimport { PopupMenuProps } from \"./PopupMenu\";\nimport { getPositionRelativeToAnchor } from \"../popup/getPositionRelativeToAnchor\";\nimport { useContextMenu } from \"../menu\";\nimport { PopupCloseCallback, reasonIsClickAway } from \"../popup/popup-service\";\nimport { PopupPlacement } from \"../popup/Popup\";\n\nexport interface PopupMenuHookProps\n extends Pick<\n PopupMenuProps,\n | \"anchorElement\"\n | \"menuActionHandler\"\n | \"menuBuilder\"\n | \"menuClassName\"\n | \"menuOptions\"\n | \"onMenuClose\"\n | \"onMenuOpen\"\n > {\n id: string;\n menuLocation: string;\n popupPlacement: PopupPlacement;\n tabIndex: number;\n}\n\nexport const usePopupMenu = ({\n anchorElement,\n id,\n menuActionHandler,\n menuBuilder,\n menuClassName,\n menuLocation,\n menuOptions,\n onMenuClose,\n onMenuOpen,\n popupPlacement,\n tabIndex,\n}: PopupMenuHookProps) => {\n const [menuOpen, _setMenuOpen] = useState(false);\n const suppressShowMenuRef = useRef(false);\n const rootRef = useRef<HTMLButtonElement>(null);\n\n const setMenuOpen = useCallback(\n (isOpen) => {\n _setMenuOpen(isOpen);\n if (isOpen) {\n onMenuOpen?.();\n }\n },\n [onMenuOpen]
|
|
1
|
+
{"version":3,"file":"usePopupMenu.js","sources":["../../src/popup-menu/usePopupMenu.ts"],"sourcesContent":["import {\n AriaAttributes,\n MouseEvent,\n useCallback,\n useRef,\n useState,\n} from \"react\";\nimport { MenuOpenHandler } from \"../menu\";\nimport { PopupMenuProps } from \"./PopupMenu\";\nimport { getPositionRelativeToAnchor } from \"../popup/getPositionRelativeToAnchor\";\nimport { useContextMenu } from \"../menu\";\nimport { PopupCloseCallback, reasonIsClickAway } from \"../popup/popup-service\";\nimport { PopupPlacement } from \"../popup/Popup\";\n\nexport interface PopupMenuHookProps\n extends Pick<\n PopupMenuProps,\n | \"anchorElement\"\n | \"menuActionHandler\"\n | \"menuBuilder\"\n | \"menuClassName\"\n | \"menuOptions\"\n | \"onMenuClose\"\n | \"onMenuOpen\"\n > {\n id: string;\n menuLocation: string;\n popupPlacement: PopupPlacement;\n tabIndex: number;\n}\n\nexport const usePopupMenu = ({\n anchorElement,\n id,\n menuActionHandler,\n menuBuilder,\n menuClassName,\n menuLocation,\n menuOptions,\n onMenuClose,\n onMenuOpen,\n popupPlacement,\n tabIndex,\n}: PopupMenuHookProps) => {\n const [menuOpen, _setMenuOpen] = useState(false);\n const suppressShowMenuRef = useRef(false);\n const rootRef = useRef<HTMLButtonElement>(null);\n\n const setMenuOpen = useCallback(\n (isOpen: boolean) => {\n _setMenuOpen(isOpen);\n if (isOpen) {\n onMenuOpen?.();\n }\n },\n [onMenuOpen],\n );\n\n const [showContextMenu] = useContextMenu(menuBuilder, menuActionHandler);\n\n const handleOpenMenu = useCallback<MenuOpenHandler>((el) => {\n console.log(`menu Open `, {\n el,\n });\n }, []);\n\n const handleMenuClose = useCallback<PopupCloseCallback>(\n (reason) => {\n setMenuOpen(false);\n // If user has clicked the MenuButton whilst menu is open, we want to close it.\n // The PopupService will close it for us as a 'click-away' event. We don't want\n // that click on the button to re-open it.\n if (reasonIsClickAway(reason)) {\n const target = reason.mouseEvt.target as HTMLElement;\n if (target === rootRef.current) {\n suppressShowMenuRef.current = true;\n }\n onMenuClose?.(reason);\n } else {\n requestAnimationFrame(() => {\n onMenuClose?.(reason);\n if (tabIndex !== -1 && reason?.type !== \"tab-away\") {\n rootRef.current?.focus();\n }\n });\n }\n },\n [onMenuClose, setMenuOpen, tabIndex],\n );\n\n const showMenu = useCallback(\n (e: MouseEvent<HTMLElement>) => {\n if (suppressShowMenuRef.current) {\n suppressShowMenuRef.current = false;\n } else {\n const anchorEl = anchorElement?.current ?? rootRef.current;\n if (anchorEl) {\n const {\n left: x,\n top: y,\n width,\n } = getPositionRelativeToAnchor(anchorEl, popupPlacement, 0, 0);\n setMenuOpen(true);\n\n showContextMenu(e, menuLocation, {\n ContextMenuProps: {\n className: menuClassName,\n id: `${id}-menu`,\n onClose: handleMenuClose,\n openMenu: handleOpenMenu,\n position: {\n x,\n y,\n },\n style: { width: width ? width - 2 : undefined },\n },\n ...menuOptions,\n });\n }\n }\n },\n [\n anchorElement,\n handleMenuClose,\n handleOpenMenu,\n id,\n menuClassName,\n menuLocation,\n menuOptions,\n popupPlacement,\n setMenuOpen,\n showContextMenu,\n ],\n );\n\n const ariaAttributes: AriaAttributes = {\n \"aria-controls\": menuOpen ? `${id}-menu` : undefined,\n \"aria-expanded\": menuOpen,\n \"aria-haspopup\": \"menu\",\n };\n\n const buttonProps = {\n id,\n onClick: showMenu,\n tabIndex,\n };\n\n return { ariaAttributes, buttonProps, menuOpen, rootRef };\n};\n"],"names":["useState","useRef","useCallback","useContextMenu","reasonIsClickAway","getPositionRelativeToAnchor"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-menu-provider.js","sources":["../../src/menu/context-menu-provider.tsx"],"sourcesContent":["import type {\n ContextMenuContextType,\n MenuActionHandler,\n MenuBuilder,\n} from \"@vuu-ui/vuu-data-types\";\nimport { createContext, ReactNode, useCallback, useMemo } from \"react\";\n\nexport const ContextMenuContext = createContext<ContextMenuContextType | null>(\n null,\n);\n\nexport interface ContextMenuConfiguration {\n menuActionHandler?: MenuActionHandler;\n menuBuilder: MenuBuilder;\n}\n\nexport interface ContextMenuProviderProps extends ContextMenuConfiguration {\n children: ReactNode;\n label?: string;\n}\n\ninterface ProviderProps extends ContextMenuProviderProps {\n context: ContextMenuContextType | null;\n}\n\nconst Provider = ({\n children,\n context,\n menuActionHandler,\n menuBuilder,\n}: ProviderProps) => {\n const menuBuilders = useMemo(() => {\n if (context?.menuBuilders && menuBuilder) {\n return context.menuBuilders.concat(menuBuilder);\n } else if (menuBuilder) {\n return [menuBuilder];\n } else {\n return context?.menuBuilders || [];\n }\n }, [context, menuBuilder]);\n\n const handleMenuAction = useCallback(\n (reason) => {\n if (menuActionHandler?.(reason)) {\n return true;\n }\n\n if (context?.menuActionHandler?.(reason)) {\n return true;\n }\n },\n [context, menuActionHandler],\n );\n\n return (\n <ContextMenuContext.Provider\n value={{\n menuActionHandler: handleMenuAction,\n menuBuilders,\n }}\n >\n {children}\n </ContextMenuContext.Provider>\n );\n};\n\n// Need an option for local menu to override higher-level menu, rather than extend\nexport const ContextMenuProvider = ({\n children,\n label,\n menuActionHandler,\n menuBuilder,\n}: ContextMenuProviderProps) => {\n return (\n <ContextMenuContext.Consumer>\n {(parentContext) => (\n <Provider\n context={parentContext}\n label={label}\n menuActionHandler={menuActionHandler}\n menuBuilder={menuBuilder}\n >\n {children}\n </Provider>\n )}\n </ContextMenuContext.Consumer>\n );\n};\n"],"names":[],"mappings":";;;AAOO,MAAM,kBAAqB,GAAA,aAAA;AAAA,EAChC;AACF;AAgBA,MAAM,WAAW,CAAC;AAAA,EAChB,QAAA;AAAA,EACA,OAAA;AAAA,EACA,iBAAA;AAAA,EACA;AACF,CAAqB,KAAA;AACnB,EAAM,MAAA,YAAA,GAAe,QAAQ,MAAM;AACjC,IAAI,IAAA,OAAA,EAAS,gBAAgB,WAAa,EAAA;AACxC,MAAO,OAAA,OAAA,CAAQ,YAAa,CAAA,MAAA,CAAO,WAAW,CAAA;AAAA,eACrC,WAAa,EAAA;AACtB,MAAA,OAAO,CAAC,WAAW,CAAA;AAAA,KACd,MAAA;AACL,MAAO,OAAA,OAAA,EAAS,gBAAgB,EAAC;AAAA;AACnC,GACC,EAAA,CAAC,OAAS,EAAA,WAAW,CAAC,CAAA;AAEzB,EAAA,MAAM,gBAAmB,GAAA,WAAA;AAAA,IACvB,CAAC,MAAW,KAAA;AACV,MAAI,IAAA,iBAAA,GAAoB,MAAM,CAAG,EAAA;AAC/B,QAAO,OAAA,IAAA;AAAA;AAGT,MAAI,IAAA,OAAA,EAAS,iBAAoB,GAAA,MAAM,CAAG,EAAA;AACxC,QAAO,OAAA,IAAA;AAAA;AACT,KACF;AAAA,IACA,CAAC,SAAS,iBAAiB;AAAA,GAC7B;AAEA,EACE,uBAAA,GAAA;AAAA,IAAC,kBAAmB,CAAA,QAAA;AAAA,IAAnB;AAAA,MACC,KAAO,EAAA;AAAA,QACL,iBAAmB,EAAA,gBAAA;AAAA,QACnB;AAAA,OACF;AAAA,MAEC;AAAA;AAAA,GACH;AAEJ,CAAA;AAGO,MAAM,sBAAsB,CAAC;AAAA,EAClC,QAAA;AAAA,EACA,KAAA;AAAA,EACA,iBAAA;AAAA,EACA;AACF,CAAgC,KAAA;AAC9B,EAAA,uBACG,GAAA,CAAA,kBAAA,CAAmB,QAAnB,EAAA,EACE,WAAC,aACA,qBAAA,GAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,OAAS,EAAA,aAAA;AAAA,MACT,KAAA;AAAA,MACA,iBAAA;AAAA,MACA,WAAA;AAAA,MAEC;AAAA;AAAA,GAGP,EAAA,CAAA;AAEJ;;;;"}
|
|
1
|
+
{"version":3,"file":"context-menu-provider.js","sources":["../../src/menu/context-menu-provider.tsx"],"sourcesContent":["import type {\n ContextMenuContextType,\n MenuActionHandler,\n MenuBuilder,\n} from \"@vuu-ui/vuu-data-types\";\nimport { createContext, ReactNode, useCallback, useMemo } from \"react\";\n\nexport const ContextMenuContext = createContext<ContextMenuContextType | null>(\n null,\n);\n\nexport interface ContextMenuConfiguration {\n menuActionHandler?: MenuActionHandler;\n menuBuilder: MenuBuilder;\n}\n\nexport interface ContextMenuProviderProps extends ContextMenuConfiguration {\n children: ReactNode;\n label?: string;\n}\n\ninterface ProviderProps extends ContextMenuProviderProps {\n context: ContextMenuContextType | null;\n}\n\nconst Provider = ({\n children,\n context,\n menuActionHandler,\n menuBuilder,\n}: ProviderProps) => {\n const menuBuilders = useMemo(() => {\n if (context?.menuBuilders && menuBuilder) {\n return context.menuBuilders.concat(menuBuilder);\n } else if (menuBuilder) {\n return [menuBuilder];\n } else {\n return context?.menuBuilders || [];\n }\n }, [context, menuBuilder]);\n\n const handleMenuAction = useCallback<MenuActionHandler>(\n (reason) => {\n if (menuActionHandler?.(reason)) {\n return true;\n }\n\n if (context?.menuActionHandler?.(reason)) {\n return true;\n }\n },\n [context, menuActionHandler],\n );\n\n return (\n <ContextMenuContext.Provider\n value={{\n menuActionHandler: handleMenuAction,\n menuBuilders,\n }}\n >\n {children}\n </ContextMenuContext.Provider>\n );\n};\n\n// Need an option for local menu to override higher-level menu, rather than extend\nexport const ContextMenuProvider = ({\n children,\n label,\n menuActionHandler,\n menuBuilder,\n}: ContextMenuProviderProps) => {\n return (\n <ContextMenuContext.Consumer>\n {(parentContext) => (\n <Provider\n context={parentContext}\n label={label}\n menuActionHandler={menuActionHandler}\n menuBuilder={menuBuilder}\n >\n {children}\n </Provider>\n )}\n </ContextMenuContext.Consumer>\n );\n};\n"],"names":[],"mappings":";;;AAOO,MAAM,kBAAqB,GAAA,aAAA;AAAA,EAChC;AACF;AAgBA,MAAM,WAAW,CAAC;AAAA,EAChB,QAAA;AAAA,EACA,OAAA;AAAA,EACA,iBAAA;AAAA,EACA;AACF,CAAqB,KAAA;AACnB,EAAM,MAAA,YAAA,GAAe,QAAQ,MAAM;AACjC,IAAI,IAAA,OAAA,EAAS,gBAAgB,WAAa,EAAA;AACxC,MAAO,OAAA,OAAA,CAAQ,YAAa,CAAA,MAAA,CAAO,WAAW,CAAA;AAAA,eACrC,WAAa,EAAA;AACtB,MAAA,OAAO,CAAC,WAAW,CAAA;AAAA,KACd,MAAA;AACL,MAAO,OAAA,OAAA,EAAS,gBAAgB,EAAC;AAAA;AACnC,GACC,EAAA,CAAC,OAAS,EAAA,WAAW,CAAC,CAAA;AAEzB,EAAA,MAAM,gBAAmB,GAAA,WAAA;AAAA,IACvB,CAAC,MAAW,KAAA;AACV,MAAI,IAAA,iBAAA,GAAoB,MAAM,CAAG,EAAA;AAC/B,QAAO,OAAA,IAAA;AAAA;AAGT,MAAI,IAAA,OAAA,EAAS,iBAAoB,GAAA,MAAM,CAAG,EAAA;AACxC,QAAO,OAAA,IAAA;AAAA;AACT,KACF;AAAA,IACA,CAAC,SAAS,iBAAiB;AAAA,GAC7B;AAEA,EACE,uBAAA,GAAA;AAAA,IAAC,kBAAmB,CAAA,QAAA;AAAA,IAAnB;AAAA,MACC,KAAO,EAAA;AAAA,QACL,iBAAmB,EAAA,gBAAA;AAAA,QACnB;AAAA,OACF;AAAA,MAEC;AAAA;AAAA,GACH;AAEJ,CAAA;AAGO,MAAM,sBAAsB,CAAC;AAAA,EAClC,QAAA;AAAA,EACA,KAAA;AAAA,EACA,iBAAA;AAAA,EACA;AACF,CAAgC,KAAA;AAC9B,EAAA,uBACG,GAAA,CAAA,kBAAA,CAAmB,QAAnB,EAAA,EACE,WAAC,aACA,qBAAA,GAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,OAAS,EAAA,aAAA;AAAA,MACT,KAAA;AAAA,MACA,iBAAA;AAAA,MACA,WAAA;AAAA,MAEC;AAAA;AAAA,GAGP,EAAA,CAAA;AAEJ;;;;"}
|
package/esm/menu/use-cascade.js
CHANGED
|
@@ -86,14 +86,16 @@ const useCascade = ({
|
|
|
86
86
|
setOpenMenus([{ id: rootId, left: posX, top: posY }]);
|
|
87
87
|
} else {
|
|
88
88
|
menuState.current[hostMenuId] = "popup-open";
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
89
|
+
if (itemId) {
|
|
90
|
+
const el = document.getElementById(itemId);
|
|
91
|
+
if (el !== null) {
|
|
92
|
+
const { left, top } = getPosition(el, openMenus.current);
|
|
93
|
+
setOpenMenus(
|
|
94
|
+
openMenus.current.concat({ id: targetMenuId, left, top })
|
|
95
|
+
);
|
|
96
|
+
} else {
|
|
97
|
+
throw Error(`openMenu no menuItem ${itemId}`);
|
|
98
|
+
}
|
|
97
99
|
}
|
|
98
100
|
}
|
|
99
101
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-cascade.js","sources":["../../src/menu/use-cascade.ts"],"sourcesContent":["import {\n MouseEvent,\n SyntheticEvent,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport { closestListItem } from \"./list-dom-utils\";\nimport { MenuItemProps, MenuOpenHandler } from \"./MenuList\";\n// import {mousePosition} from './aim/utils';\n// import {aiming} from './aim/aim';\n\nconst nudge = (\n menus: RuntimeMenuDescriptor[],\n distance: number,\n pos: \"left\" | \"top\"\n) => {\n return menus.map((m, i) =>\n i === menus.length - 1\n ? {\n ...m,\n [pos]: m[pos] - distance,\n }\n : m\n );\n};\nconst nudgeLeft = (menus: RuntimeMenuDescriptor[], distance: number) =>\n nudge(menus, distance, \"left\");\nconst nudgeUp = (menus: RuntimeMenuDescriptor[], distance: number) =>\n nudge(menus, distance, \"top\");\n\nconst flipSides = (id: string, menus: RuntimeMenuDescriptor[]) => {\n const [parentMenu, menu] = menus.slice(-2);\n const el = document.getElementById(`${id}-${menu.id}`);\n if (el === null) {\n throw Error(`useCascade.flipSides element with id ${menu.id} not found`);\n }\n const { width } = el.getBoundingClientRect();\n return menus.map((m) =>\n m === menu\n ? {\n ...m,\n left: parentMenu.left - (width - 2),\n }\n : m\n );\n};\n\n// const closedNode = (el: HTMLElement) =>\n// el.ariaHasPopup === \"true\" && el.ariaExpanded !== \"true\";\nconst getPosition = (el: HTMLElement, openMenus: RuntimeMenuDescriptor[]) => {\n const [{ left, top: menuTop }] = openMenus.slice(-1);\n // const {top, right, bottom, left} = el.getBoundingClientRect();\n // this will not work for MenuList within window, we need the\n // const {offsetLeft: left, offsetTop: menuTop} = el.closest('.vuuMenuList');\n const { offsetWidth: width, offsetTop: top } = el;\n return { left: left + width, top: top + menuTop };\n};\n\nexport type RuntimeMenuDescriptor = {\n id: string;\n left: number;\n top: number;\n};\n\n/** menuitem-vuu-1-0 vuu-1 */\nexport const getHostMenuId = (id: string, rootId: string) => {\n const pos = id.lastIndexOf(\"-\");\n if (id.startsWith(\"menuitem\")) {\n return pos > -1 ? id.slice(9, pos) : rootId;\n } else {\n return pos > -1 ? id.slice(0, pos) : rootId;\n }\n};\n\nconst getTargetMenuId = (id: string) => id.slice(9);\n\nconst getMenuItemDetails = (\n { ariaExpanded, ariaHasPopup, id }: HTMLElement,\n rootId: string\n) => {\n if (id.startsWith(\"menuitem\")) {\n return {\n hostMenuId: getHostMenuId(id, rootId),\n targetMenuId: getTargetMenuId(id),\n menuItemId: id,\n isGroup: ariaHasPopup === \"true\",\n isOpen: ariaExpanded === \"true\",\n };\n } else {\n throw Error(`getMenuItemDetails #${id} is not a menuitem`);\n }\n};\n\nexport interface CascadeHookProps {\n id: string;\n onActivate: (menuId: string) => void;\n onMouseEnterItem: (evt: MouseEvent, itemId: string) => void;\n position: { x: number; y: number };\n}\n\nexport interface CascadeHooksResult {\n closeMenu: () => void;\n handleRender: () => void;\n listItemProps: Partial<MenuItemProps>;\n openMenu: MenuOpenHandler;\n openMenus: RuntimeMenuDescriptor[];\n}\n\ntype MenuStatus = \"no-popup\" | \"popup-open\" | \"pending-close\" | \"popup-pending\";\ntype MenuState = { [key: string]: MenuStatus };\n\nexport const useCascade = ({\n id: rootId,\n onActivate,\n onMouseEnterItem,\n position: { x: posX, y: posY },\n}: CascadeHookProps): CascadeHooksResult => {\n const [, forceRefresh] = useState({});\n const openMenus = useRef<RuntimeMenuDescriptor[]>([\n { id: rootId, left: posX, top: posY },\n ]);\n\n const menuIsOpen = useCallback(\n (menuId: string) =>\n openMenus.current.findIndex((menu) => menu.id === menuId) !== -1,\n []\n );\n\n const getOpenMenuStatus = useCallback((menuId: string) => {\n const state = menuState.current[menuId];\n if (state === undefined) {\n throw Error(`getOpenMenuState no entry for menu ${menuId}`);\n }\n return state;\n }, []);\n\n const setOpenMenus = useCallback((menus: RuntimeMenuDescriptor[]) => {\n openMenus.current = menus;\n forceRefresh({});\n }, []);\n\n const menuOpenPendingTimeout = useRef<number | undefined>();\n const menuClosePendingTimeout = useRef<number | undefined>();\n const menuState = useRef<MenuState>({ [rootId]: \"no-popup\" });\n // const prevLevel = useRef(0);\n\n // const prevAim = useRef({mousePos: null, distance: true});\n\n const openMenu = useCallback(\n (hostMenuId = rootId, targetMenuId: string, itemId = null) => {\n if (hostMenuId === rootId && itemId === null) {\n setOpenMenus([{ id: rootId, left: posX, top: posY }]);\n } else {\n menuState.current[hostMenuId] = \"popup-open\";\n const el = document.getElementById(itemId) as HTMLElement;\n if (el !== null) {\n const { left, top } = getPosition(el, openMenus.current);\n setOpenMenus(\n openMenus.current.concat({ id: targetMenuId, left, top })\n );\n } else {\n throw Error(`openMenu no menuItem ${itemId}`);\n }\n }\n },\n [rootId, posX, posY, setOpenMenus]\n );\n\n const closeMenu = useCallback(\n (menuId?: string) => {\n if (menuId === rootId) {\n setOpenMenus([]);\n } else {\n const menus = openMenus.current.slice();\n const lastMenu = menus.pop() as RuntimeMenuDescriptor;\n menuState.current[lastMenu.id] = \"no-popup\";\n const parentMenu = menus.at(-1);\n if (parentMenu) {\n menuState.current[parentMenu.id] = \"no-popup\";\n }\n setOpenMenus(menus);\n }\n },\n [rootId, setOpenMenus]\n );\n\n const closeMenus = useCallback(\n (menuItemId) => {\n const menus = openMenus.current.slice();\n const menuItemMenuId = menuItemId.slice(9);\n let { id: lastMenuId } = menus.at(-1) as RuntimeMenuDescriptor;\n while (menus.length > 1 && !menuItemMenuId.startsWith(lastMenuId)) {\n const parentMenuId = getHostMenuId(lastMenuId, rootId);\n menus.pop();\n menuState.current[lastMenuId] = \"no-popup\";\n menuState.current[parentMenuId] = \"no-popup\";\n ({ id: lastMenuId } = menus[menus.length - 1]);\n }\n if (menus.length < openMenus.current.length) {\n setOpenMenus(menus);\n }\n },\n [rootId, setOpenMenus]\n );\n\n const clearAnyScheduledOpenTasks = useCallback(() => {\n if (menuOpenPendingTimeout.current) {\n clearTimeout(menuOpenPendingTimeout.current);\n menuOpenPendingTimeout.current = undefined;\n }\n }, []);\n\n const scheduleOpen = useCallback(\n (\n hostMenuId: string,\n targetMenuId: string,\n menuItemId: string,\n delay = 300\n ) => {\n clearAnyScheduledOpenTasks();\n // do we need to set target state to pending-open ?s\n\n menuOpenPendingTimeout.current = window.setTimeout(() => {\n // console.log(\n // `scheduleOpen<timeout> opening menu ${targetMenuId} from menu ${hostMenuId} via menuitem ${menuItemId}`\n // );\n closeMenus(menuItemId);\n menuState.current[hostMenuId] = \"popup-open\";\n menuState.current[targetMenuId] = \"no-popup\";\n openMenu(hostMenuId, targetMenuId, menuItemId);\n }, delay);\n },\n [clearAnyScheduledOpenTasks, closeMenus, openMenu]\n );\n\n const scheduleClose = useCallback(\n (hostMenuId: string, openMenuId: string, itemId: string) => {\n // console.log(\n // `scheduleClose openMenuId ${openMenuId} from parent menu ${hostMenuId} itemId ${itemId}`\n // );\n menuState.current[openMenuId] = \"pending-close\";\n menuClosePendingTimeout.current = window.setTimeout(() => {\n // console.log(`call closeMenus from scheduleClose`);\n closeMenus(itemId);\n }, 400);\n },\n [closeMenus]\n );\n\n const handleRender = useCallback(() => {\n const { current: menus } = openMenus;\n const menu = menus.at(-1);\n const el = menu ? document.getElementById(menu.id) : undefined;\n if (el) {\n const { right, bottom } = el.getBoundingClientRect();\n const { clientHeight, clientWidth } = document.body;\n if (right > clientWidth) {\n const newMenus =\n menus.length > 1\n ? flipSides(rootId, menus)\n : nudgeLeft(menus, right - clientWidth);\n setOpenMenus(newMenus);\n } else if (bottom > clientHeight) {\n const newMenus = nudgeUp(menus, bottom - clientHeight);\n setOpenMenus(newMenus);\n }\n\n if (typeof el.tabIndex === \"number\") {\n el.focus();\n }\n }\n }, [rootId, setOpenMenus]);\n\n // TODO introduce a delay parameter that allows click to requeat an immediate render\n const triggerChildMenu = useCallback<MenuOpenHandler>(\n (menuItemEl, immediate = false) => {\n const { hostMenuId, targetMenuId, menuItemId, isGroup, isOpen } =\n getMenuItemDetails(menuItemEl, rootId);\n const {\n current: { [hostMenuId]: state },\n } = menuState;\n\n const delay = immediate ? 0 : undefined;\n\n // console.log(\n // `%ctriggerChildMenu\n // rootId ${rootId}\n // menuItem ${menuItemId}\n // host menu: ${hostMenuId}\n // target menu: ${targetMenuId}\n // item index: ${menuItemId}\n // state ${state}\n // isGroup ${isGroup} isOpen ${isOpen}\n // openMenus: ${JSON.stringify(openMenus.current)}\n // full state='${JSON.stringify(menuState.current)}`,\n // \"color: green; font-weight: bold;\"\n // );\n\n if (state === \"no-popup\" && isGroup) {\n menuState.current[hostMenuId] = \"popup-pending\";\n scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);\n } else if (state === \"popup-pending\" && !isGroup) {\n menuState.current[hostMenuId] = \"no-popup\";\n clearTimeout(menuOpenPendingTimeout.current);\n menuOpenPendingTimeout.current = undefined;\n } else if (state === \"popup-pending\" && isGroup) {\n clearTimeout(menuOpenPendingTimeout.current);\n scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);\n } else if (state === \"popup-open\") {\n if (menuIsOpen(targetMenuId)) {\n const menuStatus = getOpenMenuStatus(targetMenuId);\n // Close any child menus of the target menu. This can happen if we have\n // opened child menus, then moused out of the menu entirely, to re-enter\n // at a higher level\n closeMenus(menuItemId);\n\n switch (menuStatus) {\n case \"pending-close\":\n // cancel the close\n clearTimeout(menuClosePendingTimeout.current);\n menuClosePendingTimeout.current = undefined;\n menuState.current[targetMenuId] = \"no-popup\";\n clearAnyScheduledOpenTasks();\n break;\n default:\n }\n } else {\n // TODO review the below, suspectb it's over complicating things\n const [parentOfLastOpenedMenu, lastOpenedMenu] =\n openMenus.current.slice(-2);\n if (\n parentOfLastOpenedMenu.id === hostMenuId &&\n menuState.current[lastOpenedMenu.id] !== \"pending-close\" /*&&\n sameLevel*/\n ) {\n scheduleClose(hostMenuId, lastOpenedMenu.id, menuItemId);\n if (isGroup && !isOpen) {\n scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);\n }\n } else if (\n parentOfLastOpenedMenu.id === hostMenuId &&\n isGroup &&\n menuItemId !== lastOpenedMenu.id &&\n menuState.current[lastOpenedMenu.id] === \"pending-close\"\n ) {\n // if there is already an item queued for opening cancel it\n scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);\n } else if (isGroup) {\n // closeMenus(menuId, itemId);\n scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);\n } else if (\n !(\n (menuState.current[lastOpenedMenu.id] === \"pending-close\") /*&&\n sameLevel*/\n )\n ) {\n closeMenus(menuItemId);\n }\n }\n }\n\n if (state === \"pending-close\") {\n clearAnyScheduledOpenTasks();\n clearTimeout(menuClosePendingTimeout.current);\n menuClosePendingTimeout.current = undefined;\n menuState.current[hostMenuId] = \"popup-open\";\n }\n },\n [\n clearAnyScheduledOpenTasks,\n closeMenus,\n getOpenMenuStatus,\n menuIsOpen,\n rootId,\n scheduleClose,\n scheduleOpen,\n ]\n );\n\n const listItemProps: Partial<MenuItemProps> = useMemo(\n () => ({\n onMouseEnter: (evt: MouseEvent) => {\n const menuItemEl = closestListItem(evt.target as HTMLElement);\n triggerChildMenu(menuItemEl);\n onMouseEnterItem(evt, menuItemEl.id);\n },\n\n onClick: (evt: SyntheticEvent) => {\n const listItemEl = closestListItem(evt.target as HTMLElement);\n const { isGroup, menuItemId } = getMenuItemDetails(listItemEl, rootId);\n if (isGroup) {\n triggerChildMenu(listItemEl);\n } else {\n onActivate(menuItemId);\n }\n },\n }),\n [onActivate, onMouseEnterItem, rootId, triggerChildMenu]\n );\n\n return {\n closeMenu,\n handleRender,\n listItemProps,\n openMenu: triggerChildMenu,\n openMenus: openMenus.current,\n };\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"use-cascade.js","sources":["../../src/menu/use-cascade.ts"],"sourcesContent":["import {\n MouseEvent,\n SyntheticEvent,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport { closestListItem } from \"./list-dom-utils\";\nimport { MenuItemProps, MenuOpenHandler } from \"./MenuList\";\n// import {mousePosition} from './aim/utils';\n// import {aiming} from './aim/aim';\n\nconst nudge = (\n menus: RuntimeMenuDescriptor[],\n distance: number,\n pos: \"left\" | \"top\",\n) => {\n return menus.map((m, i) =>\n i === menus.length - 1\n ? {\n ...m,\n [pos]: m[pos] - distance,\n }\n : m,\n );\n};\nconst nudgeLeft = (menus: RuntimeMenuDescriptor[], distance: number) =>\n nudge(menus, distance, \"left\");\nconst nudgeUp = (menus: RuntimeMenuDescriptor[], distance: number) =>\n nudge(menus, distance, \"top\");\n\nconst flipSides = (id: string, menus: RuntimeMenuDescriptor[]) => {\n const [parentMenu, menu] = menus.slice(-2);\n const el = document.getElementById(`${id}-${menu.id}`);\n if (el === null) {\n throw Error(`useCascade.flipSides element with id ${menu.id} not found`);\n }\n const { width } = el.getBoundingClientRect();\n return menus.map((m) =>\n m === menu\n ? {\n ...m,\n left: parentMenu.left - (width - 2),\n }\n : m,\n );\n};\n\n// const closedNode = (el: HTMLElement) =>\n// el.ariaHasPopup === \"true\" && el.ariaExpanded !== \"true\";\nconst getPosition = (el: HTMLElement, openMenus: RuntimeMenuDescriptor[]) => {\n const [{ left, top: menuTop }] = openMenus.slice(-1);\n // const {top, right, bottom, left} = el.getBoundingClientRect();\n // this will not work for MenuList within window, we need the\n // const {offsetLeft: left, offsetTop: menuTop} = el.closest('.vuuMenuList');\n const { offsetWidth: width, offsetTop: top } = el;\n return { left: left + width, top: top + menuTop };\n};\n\nexport type RuntimeMenuDescriptor = {\n id: string;\n left: number;\n top: number;\n};\n\n/** menuitem-vuu-1-0 vuu-1 */\nexport const getHostMenuId = (id: string, rootId: string) => {\n const pos = id.lastIndexOf(\"-\");\n if (id.startsWith(\"menuitem\")) {\n return pos > -1 ? id.slice(9, pos) : rootId;\n } else {\n return pos > -1 ? id.slice(0, pos) : rootId;\n }\n};\n\nconst getTargetMenuId = (id: string) => id.slice(9);\n\nconst getMenuItemDetails = (\n { ariaExpanded, ariaHasPopup, id }: HTMLElement,\n rootId: string,\n) => {\n if (id.startsWith(\"menuitem\")) {\n return {\n hostMenuId: getHostMenuId(id, rootId),\n targetMenuId: getTargetMenuId(id),\n menuItemId: id,\n isGroup: ariaHasPopup === \"true\",\n isOpen: ariaExpanded === \"true\",\n };\n } else {\n throw Error(`getMenuItemDetails #${id} is not a menuitem`);\n }\n};\n\nexport interface CascadeHookProps {\n id: string;\n onActivate: (menuId: string) => void;\n onMouseEnterItem: (evt: MouseEvent, itemId: string) => void;\n position: { x: number; y: number };\n}\n\nexport interface CascadeHooksResult {\n closeMenu: () => void;\n handleRender: () => void;\n listItemProps: Partial<MenuItemProps>;\n openMenu: MenuOpenHandler;\n openMenus: RuntimeMenuDescriptor[];\n}\n\ntype MenuStatus = \"no-popup\" | \"popup-open\" | \"pending-close\" | \"popup-pending\";\ntype MenuState = { [key: string]: MenuStatus };\n\nexport const useCascade = ({\n id: rootId,\n onActivate,\n onMouseEnterItem,\n position: { x: posX, y: posY },\n}: CascadeHookProps): CascadeHooksResult => {\n const [, forceRefresh] = useState({});\n const openMenus = useRef<RuntimeMenuDescriptor[]>([\n { id: rootId, left: posX, top: posY },\n ]);\n\n const menuIsOpen = useCallback(\n (menuId: string) =>\n openMenus.current.findIndex((menu) => menu.id === menuId) !== -1,\n [],\n );\n\n const getOpenMenuStatus = useCallback((menuId: string) => {\n const state = menuState.current[menuId];\n if (state === undefined) {\n throw Error(`getOpenMenuState no entry for menu ${menuId}`);\n }\n return state;\n }, []);\n\n const setOpenMenus = useCallback((menus: RuntimeMenuDescriptor[]) => {\n openMenus.current = menus;\n forceRefresh({});\n }, []);\n\n const menuOpenPendingTimeout = useRef<number | undefined>();\n const menuClosePendingTimeout = useRef<number | undefined>();\n const menuState = useRef<MenuState>({ [rootId]: \"no-popup\" });\n // const prevLevel = useRef(0);\n\n // const prevAim = useRef({mousePos: null, distance: true});\n\n const openMenu = useCallback(\n (\n hostMenuId = rootId,\n targetMenuId: string,\n itemId: string | null = null,\n ) => {\n if (hostMenuId === rootId && itemId === null) {\n setOpenMenus([{ id: rootId, left: posX, top: posY }]);\n } else {\n menuState.current[hostMenuId] = \"popup-open\";\n if (itemId) {\n const el = document.getElementById(itemId) as HTMLElement;\n if (el !== null) {\n const { left, top } = getPosition(el, openMenus.current);\n setOpenMenus(\n openMenus.current.concat({ id: targetMenuId, left, top }),\n );\n } else {\n throw Error(`openMenu no menuItem ${itemId}`);\n }\n }\n }\n },\n [rootId, posX, posY, setOpenMenus],\n );\n\n const closeMenu = useCallback(\n (menuId?: string) => {\n if (menuId === rootId) {\n setOpenMenus([]);\n } else {\n const menus = openMenus.current.slice();\n const lastMenu = menus.pop() as RuntimeMenuDescriptor;\n menuState.current[lastMenu.id] = \"no-popup\";\n const parentMenu = menus.at(-1);\n if (parentMenu) {\n menuState.current[parentMenu.id] = \"no-popup\";\n }\n setOpenMenus(menus);\n }\n },\n [rootId, setOpenMenus],\n );\n\n const closeMenus = useCallback(\n (menuItemId: string) => {\n const menus = openMenus.current.slice();\n const menuItemMenuId = menuItemId.slice(9);\n let { id: lastMenuId } = menus.at(-1) as RuntimeMenuDescriptor;\n while (menus.length > 1 && !menuItemMenuId.startsWith(lastMenuId)) {\n const parentMenuId = getHostMenuId(lastMenuId, rootId);\n menus.pop();\n menuState.current[lastMenuId] = \"no-popup\";\n menuState.current[parentMenuId] = \"no-popup\";\n ({ id: lastMenuId } = menus[menus.length - 1]);\n }\n if (menus.length < openMenus.current.length) {\n setOpenMenus(menus);\n }\n },\n [rootId, setOpenMenus],\n );\n\n const clearAnyScheduledOpenTasks = useCallback(() => {\n if (menuOpenPendingTimeout.current) {\n clearTimeout(menuOpenPendingTimeout.current);\n menuOpenPendingTimeout.current = undefined;\n }\n }, []);\n\n const scheduleOpen = useCallback(\n (\n hostMenuId: string,\n targetMenuId: string,\n menuItemId: string,\n delay = 300,\n ) => {\n clearAnyScheduledOpenTasks();\n // do we need to set target state to pending-open ?s\n\n menuOpenPendingTimeout.current = window.setTimeout(() => {\n // console.log(\n // `scheduleOpen<timeout> opening menu ${targetMenuId} from menu ${hostMenuId} via menuitem ${menuItemId}`\n // );\n closeMenus(menuItemId);\n menuState.current[hostMenuId] = \"popup-open\";\n menuState.current[targetMenuId] = \"no-popup\";\n openMenu(hostMenuId, targetMenuId, menuItemId);\n }, delay);\n },\n [clearAnyScheduledOpenTasks, closeMenus, openMenu],\n );\n\n const scheduleClose = useCallback(\n (hostMenuId: string, openMenuId: string, itemId: string) => {\n // console.log(\n // `scheduleClose openMenuId ${openMenuId} from parent menu ${hostMenuId} itemId ${itemId}`\n // );\n menuState.current[openMenuId] = \"pending-close\";\n menuClosePendingTimeout.current = window.setTimeout(() => {\n // console.log(`call closeMenus from scheduleClose`);\n closeMenus(itemId);\n }, 400);\n },\n [closeMenus],\n );\n\n const handleRender = useCallback(() => {\n const { current: menus } = openMenus;\n const menu = menus.at(-1);\n const el = menu ? document.getElementById(menu.id) : undefined;\n if (el) {\n const { right, bottom } = el.getBoundingClientRect();\n const { clientHeight, clientWidth } = document.body;\n if (right > clientWidth) {\n const newMenus =\n menus.length > 1\n ? flipSides(rootId, menus)\n : nudgeLeft(menus, right - clientWidth);\n setOpenMenus(newMenus);\n } else if (bottom > clientHeight) {\n const newMenus = nudgeUp(menus, bottom - clientHeight);\n setOpenMenus(newMenus);\n }\n\n if (typeof el.tabIndex === \"number\") {\n el.focus();\n }\n }\n }, [rootId, setOpenMenus]);\n\n // TODO introduce a delay parameter that allows click to requeat an immediate render\n const triggerChildMenu = useCallback<MenuOpenHandler>(\n (menuItemEl, immediate = false) => {\n const { hostMenuId, targetMenuId, menuItemId, isGroup, isOpen } =\n getMenuItemDetails(menuItemEl, rootId);\n const {\n current: { [hostMenuId]: state },\n } = menuState;\n\n const delay = immediate ? 0 : undefined;\n\n // console.log(\n // `%ctriggerChildMenu\n // rootId ${rootId}\n // menuItem ${menuItemId}\n // host menu: ${hostMenuId}\n // target menu: ${targetMenuId}\n // item index: ${menuItemId}\n // state ${state}\n // isGroup ${isGroup} isOpen ${isOpen}\n // openMenus: ${JSON.stringify(openMenus.current)}\n // full state='${JSON.stringify(menuState.current)}`,\n // \"color: green; font-weight: bold;\"\n // );\n\n if (state === \"no-popup\" && isGroup) {\n menuState.current[hostMenuId] = \"popup-pending\";\n scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);\n } else if (state === \"popup-pending\" && !isGroup) {\n menuState.current[hostMenuId] = \"no-popup\";\n clearTimeout(menuOpenPendingTimeout.current);\n menuOpenPendingTimeout.current = undefined;\n } else if (state === \"popup-pending\" && isGroup) {\n clearTimeout(menuOpenPendingTimeout.current);\n scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);\n } else if (state === \"popup-open\") {\n if (menuIsOpen(targetMenuId)) {\n const menuStatus = getOpenMenuStatus(targetMenuId);\n // Close any child menus of the target menu. This can happen if we have\n // opened child menus, then moused out of the menu entirely, to re-enter\n // at a higher level\n closeMenus(menuItemId);\n\n switch (menuStatus) {\n case \"pending-close\":\n // cancel the close\n clearTimeout(menuClosePendingTimeout.current);\n menuClosePendingTimeout.current = undefined;\n menuState.current[targetMenuId] = \"no-popup\";\n clearAnyScheduledOpenTasks();\n break;\n default:\n }\n } else {\n // TODO review the below, suspectb it's over complicating things\n const [parentOfLastOpenedMenu, lastOpenedMenu] =\n openMenus.current.slice(-2);\n if (\n parentOfLastOpenedMenu.id === hostMenuId &&\n menuState.current[lastOpenedMenu.id] !== \"pending-close\" /*&&\n sameLevel*/\n ) {\n scheduleClose(hostMenuId, lastOpenedMenu.id, menuItemId);\n if (isGroup && !isOpen) {\n scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);\n }\n } else if (\n parentOfLastOpenedMenu.id === hostMenuId &&\n isGroup &&\n menuItemId !== lastOpenedMenu.id &&\n menuState.current[lastOpenedMenu.id] === \"pending-close\"\n ) {\n // if there is already an item queued for opening cancel it\n scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);\n } else if (isGroup) {\n // closeMenus(menuId, itemId);\n scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);\n } else if (\n !(\n (menuState.current[lastOpenedMenu.id] === \"pending-close\") /*&&\n sameLevel*/\n )\n ) {\n closeMenus(menuItemId);\n }\n }\n }\n\n if (state === \"pending-close\") {\n clearAnyScheduledOpenTasks();\n clearTimeout(menuClosePendingTimeout.current);\n menuClosePendingTimeout.current = undefined;\n menuState.current[hostMenuId] = \"popup-open\";\n }\n },\n [\n clearAnyScheduledOpenTasks,\n closeMenus,\n getOpenMenuStatus,\n menuIsOpen,\n rootId,\n scheduleClose,\n scheduleOpen,\n ],\n );\n\n const listItemProps: Partial<MenuItemProps> = useMemo(\n () => ({\n onMouseEnter: (evt: MouseEvent) => {\n const menuItemEl = closestListItem(evt.target as HTMLElement);\n triggerChildMenu(menuItemEl);\n onMouseEnterItem(evt, menuItemEl.id);\n },\n\n onClick: (evt: SyntheticEvent) => {\n const listItemEl = closestListItem(evt.target as HTMLElement);\n const { isGroup, menuItemId } = getMenuItemDetails(listItemEl, rootId);\n if (isGroup) {\n triggerChildMenu(listItemEl);\n } else {\n onActivate(menuItemId);\n }\n },\n }),\n [onActivate, onMouseEnterItem, rootId, triggerChildMenu],\n );\n\n return {\n closeMenu,\n handleRender,\n listItemProps,\n openMenu: triggerChildMenu,\n openMenus: openMenus.current,\n };\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-keyboard-navigation.js","sources":["../../src/menu/use-keyboard-navigation.ts"],"sourcesContent":["import {\n FocusEvent,\n KeyboardEvent,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { hasPopup, isRoot } from \"./utils\";\nimport { isNavigationKey } from \"./key-code\";\nimport { isValidNumber } from \"@vuu-ui/vuu-utils\";\nimport { MenuOpenHandler } from \"./MenuList\";\n\nexport type MenuCloseReason = \"tab-away\" | \"close-child-menu\";\n\nexport type MenuCloseHandler = (\n evt: KeyboardEvent,\n reason: MenuCloseReason,\n) => void;\n\nexport interface KeyboardNavigationProps {\n autoHighlightFirstItem?: boolean;\n count: number;\n defaultHighlightedIdx?: number;\n highlightedIndex?: number;\n onActivate: (idx: number) => void;\n onHighlight?: (idx: number) => void;\n onCloseMenu: MenuCloseHandler;\n onOpenMenu?: MenuOpenHandler;\n}\n\nexport interface KeyboardHookListProps {\n // onBlur: (evt: FocusEvent) => void;\n onFocus: (evt: FocusEvent) => void;\n onKeyDown: (evt: KeyboardEvent) => void;\n onMouseDownCapture: () => void;\n onMouseMove: () => void;\n onMouseLeave: () => void;\n}\n\nexport interface NavigationHookResult {\n focusVisible: number;\n controlledHighlighting: boolean;\n highlightedIndex: number;\n setHighlightedIndex: (idx: number) => void;\n // keyboardNavigation: RefObject<boolean>;\n listProps: KeyboardHookListProps;\n setIgnoreFocus: (ignoreFocus: boolean) => void;\n}\n\n// we need a way to set highlightedIdx when selection changes\nexport const useKeyboardNavigation = ({\n autoHighlightFirstItem = false,\n count,\n defaultHighlightedIdx,\n highlightedIndex: highlightedIndexProp,\n onActivate,\n onHighlight,\n onCloseMenu,\n onOpenMenu,\n}: KeyboardNavigationProps): NavigationHookResult => {\n if (\n isValidNumber(highlightedIndexProp) &&\n isValidNumber(defaultHighlightedIdx)\n ) {\n throw Error(\n \"useKeyboardNavigation do not pass values for both highlightedIndex and defaultHighlightedIdx\",\n );\n }\n\n const controlledHighlighting = isValidNumber(highlightedIndexProp);\n const highlightedIndexRef = useRef(\n defaultHighlightedIdx ??\n highlightedIndexProp ??\n (autoHighlightFirstItem ? 0 : -1),\n );\n const [, forceRender] = useState<unknown>(null);\n\n const setHighlightedIdx = useCallback(\n (idx) => {\n highlightedIndexRef.current = idx;\n onHighlight?.(idx);\n forceRender({});\n },\n [onHighlight],\n );\n\n const setHighlightedIndex = useCallback(\n (idx) => {\n if (idx !== highlightedIndexRef.current) {\n if (!controlledHighlighting) {\n setHighlightedIdx(idx);\n }\n }\n },\n [controlledHighlighting, setHighlightedIdx],\n );\n\n // does this belong here or should it be a method passed in?\n const keyBoardNavigation = useRef(true);\n const ignoreFocus = useRef(false);\n const setIgnoreFocus = (value: boolean) => (ignoreFocus.current = value);\n\n const highlightedIndex = controlledHighlighting\n ? highlightedIndexProp\n : highlightedIndexRef.current;\n\n const navigateChildItems = useCallback(\n (e: KeyboardEvent) => {\n const nextIdx = nextItemIdx(count, e.key, highlightedIndexRef.current);\n if (nextIdx !== highlightedIndexRef.current) {\n setHighlightedIndex(nextIdx);\n }\n },\n [count, setHighlightedIndex],\n );\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (isNavigationKey(e)) {\n e.preventDefault();\n e.stopPropagation();\n keyBoardNavigation.current = true;\n navigateChildItems(e);\n } else if (\n (e.key === \"ArrowRight\" || e.key === \"Enter\") &&\n hasPopup(e.target as HTMLElement, highlightedIndex)\n ) {\n const menuEl = e.target as HTMLElement;\n const menuItemEl = menuEl.querySelector(\n `:scope > [data-index='${highlightedIndex}']`,\n ) as HTMLElement;\n\n if (menuItemEl) {\n onOpenMenu?.(menuItemEl, true);\n }\n } else if (e.key === \"ArrowLeft\" && !isRoot(e.target as HTMLElement)) {\n onCloseMenu(e, \"close-child-menu\");\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n e.stopPropagation();\n onActivate && onActivate(highlightedIndex);\n } else if (e.key === \"Tab\") {\n onCloseMenu(e, \"tab-away\");\n }\n },\n [highlightedIndex, navigateChildItems, onActivate, onCloseMenu, onOpenMenu],\n );\n\n const listProps: KeyboardHookListProps = useMemo(\n () => ({\n onFocus: () => {\n if (highlightedIndex === -1) {\n setHighlightedIdx(0);\n }\n },\n onKeyDown: handleKeyDown,\n onMouseDownCapture: () => {\n keyBoardNavigation.current = false;\n setIgnoreFocus(true);\n },\n\n // onMouseEnter would seem less expensive but it misses some cases\n onMouseMove: () => {\n if (keyBoardNavigation.current) {\n keyBoardNavigation.current = false;\n }\n },\n onMouseLeave: () => {\n keyBoardNavigation.current = true;\n setIgnoreFocus(false);\n setHighlightedIndex(-1);\n },\n }),\n [handleKeyDown, highlightedIndex, setHighlightedIdx, setHighlightedIndex],\n );\n\n return {\n focusVisible: keyBoardNavigation.current ? highlightedIndex : -1,\n controlledHighlighting,\n highlightedIndex,\n setHighlightedIndex: setHighlightedIndex,\n listProps,\n setIgnoreFocus,\n };\n};\n\n// need to be able to accommodate disabled items\nfunction nextItemIdx(count: number, key: string, idx: number) {\n if (key === \"ArrowUp\") {\n if (idx > 0) {\n return idx - 1;\n } else {\n return idx;\n }\n } else {\n if (idx === null) {\n return 0;\n } else if (idx === count - 1) {\n return idx;\n } else {\n return idx + 1;\n }\n }\n}\n"],"names":[],"mappings":";;;;;AAmDO,MAAM,wBAAwB,CAAC;AAAA,EACpC,sBAAyB,GAAA,KAAA;AAAA,EACzB,KAAA;AAAA,EACA,qBAAA;AAAA,EACA,gBAAkB,EAAA,oBAAA;AAAA,EAClB,UAAA;AAAA,EACA,WAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAqD,KAAA;AACnD,EAAA,IACE,aAAc,CAAA,oBAAoB,CAClC,IAAA,aAAA,CAAc,qBAAqB,CACnC,EAAA;AACA,IAAM,MAAA,KAAA;AAAA,MACJ;AAAA,KACF;AAAA;AAGF,EAAM,MAAA,sBAAA,GAAyB,cAAc,oBAAoB,CAAA;AACjE,EAAA,MAAM,mBAAsB,GAAA,MAAA;AAAA,IAC1B,qBAAA,IACE,oBACC,KAAA,sBAAA,GAAyB,CAAI,GAAA,CAAA,CAAA;AAAA,GAClC;AACA,EAAA,MAAM,GAAG,WAAW,CAAA,GAAI,SAAkB,IAAI,CAAA;AAE9C,EAAA,MAAM,iBAAoB,GAAA,WAAA;AAAA,IACxB,CAAC,
|
|
1
|
+
{"version":3,"file":"use-keyboard-navigation.js","sources":["../../src/menu/use-keyboard-navigation.ts"],"sourcesContent":["import {\n FocusEvent,\n KeyboardEvent,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { hasPopup, isRoot } from \"./utils\";\nimport { isNavigationKey } from \"./key-code\";\nimport { isValidNumber } from \"@vuu-ui/vuu-utils\";\nimport { MenuOpenHandler } from \"./MenuList\";\n\nexport type MenuCloseReason = \"tab-away\" | \"close-child-menu\";\n\nexport type MenuCloseHandler = (\n evt: KeyboardEvent,\n reason: MenuCloseReason,\n) => void;\n\nexport interface KeyboardNavigationProps {\n autoHighlightFirstItem?: boolean;\n count: number;\n defaultHighlightedIdx?: number;\n highlightedIndex?: number;\n onActivate: (idx: number) => void;\n onHighlight?: (idx: number) => void;\n onCloseMenu: MenuCloseHandler;\n onOpenMenu?: MenuOpenHandler;\n}\n\nexport interface KeyboardHookListProps {\n // onBlur: (evt: FocusEvent) => void;\n onFocus: (evt: FocusEvent) => void;\n onKeyDown: (evt: KeyboardEvent) => void;\n onMouseDownCapture: () => void;\n onMouseMove: () => void;\n onMouseLeave: () => void;\n}\n\nexport interface NavigationHookResult {\n focusVisible: number;\n controlledHighlighting: boolean;\n highlightedIndex: number;\n setHighlightedIndex: (idx: number) => void;\n // keyboardNavigation: RefObject<boolean>;\n listProps: KeyboardHookListProps;\n setIgnoreFocus: (ignoreFocus: boolean) => void;\n}\n\n// we need a way to set highlightedIdx when selection changes\nexport const useKeyboardNavigation = ({\n autoHighlightFirstItem = false,\n count,\n defaultHighlightedIdx,\n highlightedIndex: highlightedIndexProp,\n onActivate,\n onHighlight,\n onCloseMenu,\n onOpenMenu,\n}: KeyboardNavigationProps): NavigationHookResult => {\n if (\n isValidNumber(highlightedIndexProp) &&\n isValidNumber(defaultHighlightedIdx)\n ) {\n throw Error(\n \"useKeyboardNavigation do not pass values for both highlightedIndex and defaultHighlightedIdx\",\n );\n }\n\n const controlledHighlighting = isValidNumber(highlightedIndexProp);\n const highlightedIndexRef = useRef(\n defaultHighlightedIdx ??\n highlightedIndexProp ??\n (autoHighlightFirstItem ? 0 : -1),\n );\n const [, forceRender] = useState<unknown>(null);\n\n const setHighlightedIdx = useCallback(\n (idx: number) => {\n highlightedIndexRef.current = idx;\n onHighlight?.(idx);\n forceRender({});\n },\n [onHighlight],\n );\n\n const setHighlightedIndex = useCallback(\n (idx: number) => {\n if (idx !== highlightedIndexRef.current) {\n if (!controlledHighlighting) {\n setHighlightedIdx(idx);\n }\n }\n },\n [controlledHighlighting, setHighlightedIdx],\n );\n\n // does this belong here or should it be a method passed in?\n const keyBoardNavigation = useRef(true);\n const ignoreFocus = useRef(false);\n const setIgnoreFocus = (value: boolean) => (ignoreFocus.current = value);\n\n const highlightedIndex = controlledHighlighting\n ? highlightedIndexProp\n : highlightedIndexRef.current;\n\n const navigateChildItems = useCallback(\n (e: KeyboardEvent) => {\n const nextIdx = nextItemIdx(count, e.key, highlightedIndexRef.current);\n if (nextIdx !== highlightedIndexRef.current) {\n setHighlightedIndex(nextIdx);\n }\n },\n [count, setHighlightedIndex],\n );\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (isNavigationKey(e)) {\n e.preventDefault();\n e.stopPropagation();\n keyBoardNavigation.current = true;\n navigateChildItems(e);\n } else if (\n (e.key === \"ArrowRight\" || e.key === \"Enter\") &&\n hasPopup(e.target as HTMLElement, highlightedIndex)\n ) {\n const menuEl = e.target as HTMLElement;\n const menuItemEl = menuEl.querySelector(\n `:scope > [data-index='${highlightedIndex}']`,\n ) as HTMLElement;\n\n if (menuItemEl) {\n onOpenMenu?.(menuItemEl, true);\n }\n } else if (e.key === \"ArrowLeft\" && !isRoot(e.target as HTMLElement)) {\n onCloseMenu(e, \"close-child-menu\");\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n e.stopPropagation();\n onActivate && onActivate(highlightedIndex);\n } else if (e.key === \"Tab\") {\n onCloseMenu(e, \"tab-away\");\n }\n },\n [highlightedIndex, navigateChildItems, onActivate, onCloseMenu, onOpenMenu],\n );\n\n const listProps: KeyboardHookListProps = useMemo(\n () => ({\n onFocus: () => {\n if (highlightedIndex === -1) {\n setHighlightedIdx(0);\n }\n },\n onKeyDown: handleKeyDown,\n onMouseDownCapture: () => {\n keyBoardNavigation.current = false;\n setIgnoreFocus(true);\n },\n\n // onMouseEnter would seem less expensive but it misses some cases\n onMouseMove: () => {\n if (keyBoardNavigation.current) {\n keyBoardNavigation.current = false;\n }\n },\n onMouseLeave: () => {\n keyBoardNavigation.current = true;\n setIgnoreFocus(false);\n setHighlightedIndex(-1);\n },\n }),\n [handleKeyDown, highlightedIndex, setHighlightedIdx, setHighlightedIndex],\n );\n\n return {\n focusVisible: keyBoardNavigation.current ? highlightedIndex : -1,\n controlledHighlighting,\n highlightedIndex,\n setHighlightedIndex: setHighlightedIndex,\n listProps,\n setIgnoreFocus,\n };\n};\n\n// need to be able to accommodate disabled items\nfunction nextItemIdx(count: number, key: string, idx: number) {\n if (key === \"ArrowUp\") {\n if (idx > 0) {\n return idx - 1;\n } else {\n return idx;\n }\n } else {\n if (idx === null) {\n return 0;\n } else if (idx === count - 1) {\n return idx;\n } else {\n return idx + 1;\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useContextMenu.js","sources":["../../src/menu/useContextMenu.tsx"],"sourcesContent":["import {\n ContextMenuItemDescriptor,\n MenuActionHandler,\n MenuBuilder,\n} from \"@vuu-ui/vuu-data-types\";\nimport { ColumnDescriptor } from \"@vuu-ui/vuu-table-types\";\nimport {\n isGroupMenuItemDescriptor,\n useThemeAttributes,\n} from \"@vuu-ui/vuu-utils\";\nimport { cloneElement, useCallback, useContext, useMemo } from \"react\";\nimport {\n MenuActionClosePopup,\n PopupCloseReason,\n PopupService,\n reasonIsMenuAction,\n} from \"../popup\";\nimport { ContextMenu, ContextMenuProps } from \"./ContextMenu\";\nimport { MenuItem, MenuItemGroup } from \"./MenuList\";\nimport { ContextMenuContext } from \"./context-menu-provider\";\n\nexport type ContextMenuOptions = {\n [key: string]: unknown;\n columns?: ColumnDescriptor[];\n contextMenu?: JSX.Element;\n ContextMenuProps?: Partial<ContextMenuProps> & {\n className?: string;\n };\n controlledComponentId?: string;\n};\n\nexport type EventLike = {\n clientX: number;\n clientY: number;\n preventDefault?: () => void;\n stopPropagation?: () => void;\n};\n\nexport type ShowContextMenu = (\n e: EventLike,\n location: string,\n options: ContextMenuOptions,\n) => void;\n\n// The argument allows a top-level menuBuilder to operate outside the Context\nexport const useContextMenu = (\n menuBuilder?: MenuBuilder,\n menuActionHandler?: MenuActionHandler,\n): [ShowContextMenu, () => void] => {\n const ctx = useContext(ContextMenuContext);\n\n const [themeClass, densityClass, dataMode] = useThemeAttributes();\n const themeAttributes = useMemo(\n () => ({\n themeClass,\n densityClass,\n dataMode,\n }),\n [dataMode, densityClass, themeClass],\n );\n\n const buildMenuOptions = useCallback(\n (menuBuilders: MenuBuilder[], location, options) => {\n let results: ContextMenuItemDescriptor[] = [];\n for (const menuBuilder of menuBuilders) {\n // Maybe we should leave the concatenation to the menuBuilder, then it can control menuItem order\n results = results.concat(menuBuilder(location, options));\n }\n return results;\n },\n [],\n );\n\n const handleShowContextMenu = useCallback<ShowContextMenu>(\n (e, location, { ContextMenuProps, contextMenu, ...options }) => {\n e.stopPropagation?.();\n e.preventDefault?.();\n\n if (contextMenu) {\n return showContextMenuComponent(\n {\n x: e.clientX,\n y: e.clientY,\n },\n contextMenu,\n );\n }\n\n const menuBuilders: MenuBuilder[] = [];\n if (menuBuilder) {\n menuBuilders.push(menuBuilder);\n }\n if (\n ctx &&\n Array.isArray(ctx?.menuBuilders) &&\n ctx.menuBuilders.length > 0\n ) {\n menuBuilders.push(...ctx.menuBuilders);\n }\n\n if (menuBuilders.length > 0) {\n const menuItemDescriptors = buildMenuOptions(\n menuBuilders,\n location,\n options,\n );\n\n // const menuHandler = menuActionHandler ?? ctx?.menuActionHandler;\n const menuHandler: MenuActionHandler = (\n action: MenuActionClosePopup,\n ) => {\n if (menuActionHandler?.(action) === true) {\n return true;\n } else {\n return ctx?.menuActionHandler(action);\n }\n };\n\n if (menuItemDescriptors.length && menuHandler) {\n // because showPopup is going to be used to render the context menu, it will not\n // have access to the ContextMenuContext. Pass the theme attributes here\n showContextMenu(e, menuItemDescriptors, menuHandler, {\n PortalProps: {\n themeAttributes,\n },\n ...ContextMenuProps,\n });\n }\n } else {\n console.warn(\n \"useContextMenu, no menuBuilders configured. These should be supplied via the ContextMenuProvider(s)\",\n );\n }\n },\n [buildMenuOptions, ctx, menuActionHandler, menuBuilder, themeAttributes],\n );\n\n const hideContextMenu = useCallback(() => {\n console.log(\"hide context menu\");\n }, []);\n\n return [handleShowContextMenu, hideContextMenu];\n};\n\nconst NO_OPTIONS = {};\n\nconst showContextMenuComponent = (\n position: { x: number; y: number },\n contextMenu: JSX.Element,\n) => {\n PopupService.showPopup({\n focus: true,\n left: 0,\n top: 0,\n component: cloneElement(contextMenu, { position }),\n });\n};\n\nconst showContextMenu = (\n e: EventLike,\n menuDescriptors: ContextMenuItemDescriptor[],\n handleContextMenuAction: MenuActionHandler,\n {\n position: positionProp,\n ...contextMenuProps\n }: ContextMenuOptions[\"ContextMenuProps\"] = NO_OPTIONS,\n) => {\n const menuItems = (menuDescriptors: ContextMenuItemDescriptor[]) => {\n const fromDescriptor = (menuItem: ContextMenuItemDescriptor, i: number) =>\n isGroupMenuItemDescriptor(menuItem) ? (\n <MenuItemGroup key={i} label={menuItem.label}>\n {menuItem.children.map(fromDescriptor)}\n </MenuItemGroup>\n ) : (\n <MenuItem\n key={i}\n action={menuItem.action}\n className={menuItem.className}\n data-icon={menuItem.icon}\n options={menuItem.options}\n >\n {menuItem.label}\n </MenuItem>\n );\n\n return menuDescriptors.map(fromDescriptor);\n };\n\n const handleClose = (reason?: PopupCloseReason) => {\n if (reasonIsMenuAction(reason)) {\n if (reason?.closedBy === \"popup-service\") {\n return;\n }\n handleContextMenuAction(reason);\n // TODO this results in onClose being called twice on component\n // cant simply be removed, some refactoring work needed\n PopupService.hidePopup(reason);\n }\n contextMenuProps?.onClose?.(reason);\n };\n\n const position = positionProp ?? {\n x: e.clientX,\n y: e.clientY,\n };\n\n const component = (\n <ContextMenu\n {...contextMenuProps}\n onClose={handleClose}\n position={position}\n >\n {menuItems(menuDescriptors)}\n </ContextMenu>\n );\n PopupService.showPopup({ left: 0, top: 0, component, focus: true });\n};\n"],"names":["menuBuilder","ContextMenuProps","menuDescriptors"],"mappings":";;;;;;;;;;;AA6Ca,MAAA,cAAA,GAAiB,CAC5B,WAAA,EACA,iBACkC,KAAA;AAClC,EAAM,MAAA,GAAA,GAAM,WAAW,kBAAkB,CAAA;AAEzC,EAAA,MAAM,CAAC,UAAA,EAAY,YAAc,EAAA,QAAQ,IAAI,kBAAmB,EAAA;AAChE,EAAA,MAAM,eAAkB,GAAA,OAAA;AAAA,IACtB,OAAO;AAAA,MACL,UAAA;AAAA,MACA,YAAA;AAAA,MACA;AAAA,KACF,CAAA;AAAA,IACA,CAAC,QAAU,EAAA,YAAA,EAAc,UAAU;AAAA,GACrC;AAEA,EAAA,MAAM,gBAAmB,GAAA,WAAA;AAAA,IACvB,CAAC,YAA6B,EAAA,QAAA,
|
|
1
|
+
{"version":3,"file":"useContextMenu.js","sources":["../../src/menu/useContextMenu.tsx"],"sourcesContent":["import {\n ContextMenuItemDescriptor,\n MenuActionHandler,\n MenuBuilder,\n} from \"@vuu-ui/vuu-data-types\";\nimport { ColumnDescriptor } from \"@vuu-ui/vuu-table-types\";\nimport {\n isGroupMenuItemDescriptor,\n useThemeAttributes,\n} from \"@vuu-ui/vuu-utils\";\nimport { cloneElement, useCallback, useContext, useMemo } from \"react\";\nimport {\n MenuActionClosePopup,\n PopupCloseReason,\n PopupService,\n reasonIsMenuAction,\n} from \"../popup\";\nimport { ContextMenu, ContextMenuProps } from \"./ContextMenu\";\nimport { MenuItem, MenuItemGroup } from \"./MenuList\";\nimport { ContextMenuContext } from \"./context-menu-provider\";\n\nexport type ContextMenuOptions = {\n [key: string]: unknown;\n columns?: ColumnDescriptor[];\n contextMenu?: JSX.Element;\n ContextMenuProps?: Partial<ContextMenuProps> & {\n className?: string;\n };\n controlledComponentId?: string;\n};\n\nexport type EventLike = {\n clientX: number;\n clientY: number;\n preventDefault?: () => void;\n stopPropagation?: () => void;\n};\n\nexport type ShowContextMenu = (\n e: EventLike,\n location: string,\n options: ContextMenuOptions,\n) => void;\n\n// The argument allows a top-level menuBuilder to operate outside the Context\nexport const useContextMenu = (\n menuBuilder?: MenuBuilder,\n menuActionHandler?: MenuActionHandler,\n): [ShowContextMenu, () => void] => {\n const ctx = useContext(ContextMenuContext);\n\n const [themeClass, densityClass, dataMode] = useThemeAttributes();\n const themeAttributes = useMemo(\n () => ({\n themeClass,\n densityClass,\n dataMode,\n }),\n [dataMode, densityClass, themeClass],\n );\n\n const buildMenuOptions = useCallback(\n (menuBuilders: MenuBuilder[], location: string, options: unknown) => {\n let results: ContextMenuItemDescriptor[] = [];\n for (const menuBuilder of menuBuilders) {\n // Maybe we should leave the concatenation to the menuBuilder, then it can control menuItem order\n results = results.concat(menuBuilder(location, options));\n }\n return results;\n },\n [],\n );\n\n const handleShowContextMenu = useCallback<ShowContextMenu>(\n (e, location, { ContextMenuProps, contextMenu, ...options }) => {\n e.stopPropagation?.();\n e.preventDefault?.();\n\n if (contextMenu) {\n return showContextMenuComponent(\n {\n x: e.clientX,\n y: e.clientY,\n },\n contextMenu,\n );\n }\n\n const menuBuilders: MenuBuilder[] = [];\n if (menuBuilder) {\n menuBuilders.push(menuBuilder);\n }\n if (\n ctx &&\n Array.isArray(ctx?.menuBuilders) &&\n ctx.menuBuilders.length > 0\n ) {\n menuBuilders.push(...ctx.menuBuilders);\n }\n\n if (menuBuilders.length > 0) {\n const menuItemDescriptors = buildMenuOptions(\n menuBuilders,\n location,\n options,\n );\n\n // const menuHandler = menuActionHandler ?? ctx?.menuActionHandler;\n const menuHandler: MenuActionHandler = (\n action: MenuActionClosePopup,\n ) => {\n if (menuActionHandler?.(action) === true) {\n return true;\n } else {\n return ctx?.menuActionHandler(action);\n }\n };\n\n if (menuItemDescriptors.length && menuHandler) {\n // because showPopup is going to be used to render the context menu, it will not\n // have access to the ContextMenuContext. Pass the theme attributes here\n showContextMenu(e, menuItemDescriptors, menuHandler, {\n PortalProps: {\n themeAttributes,\n },\n ...ContextMenuProps,\n });\n }\n } else {\n console.warn(\n \"useContextMenu, no menuBuilders configured. These should be supplied via the ContextMenuProvider(s)\",\n );\n }\n },\n [buildMenuOptions, ctx, menuActionHandler, menuBuilder, themeAttributes],\n );\n\n const hideContextMenu = useCallback(() => {\n console.log(\"hide context menu\");\n }, []);\n\n return [handleShowContextMenu, hideContextMenu];\n};\n\nconst NO_OPTIONS = {};\n\nconst showContextMenuComponent = (\n position: { x: number; y: number },\n contextMenu: JSX.Element,\n) => {\n PopupService.showPopup({\n focus: true,\n left: 0,\n top: 0,\n component: cloneElement(contextMenu, { position }),\n });\n};\n\nconst showContextMenu = (\n e: EventLike,\n menuDescriptors: ContextMenuItemDescriptor[],\n handleContextMenuAction: MenuActionHandler,\n {\n position: positionProp,\n ...contextMenuProps\n }: ContextMenuOptions[\"ContextMenuProps\"] = NO_OPTIONS,\n) => {\n const menuItems = (menuDescriptors: ContextMenuItemDescriptor[]) => {\n const fromDescriptor = (menuItem: ContextMenuItemDescriptor, i: number) =>\n isGroupMenuItemDescriptor(menuItem) ? (\n <MenuItemGroup key={i} label={menuItem.label}>\n {menuItem.children.map(fromDescriptor)}\n </MenuItemGroup>\n ) : (\n <MenuItem\n key={i}\n action={menuItem.action}\n className={menuItem.className}\n data-icon={menuItem.icon}\n options={menuItem.options}\n >\n {menuItem.label}\n </MenuItem>\n );\n\n return menuDescriptors.map(fromDescriptor);\n };\n\n const handleClose = (reason?: PopupCloseReason) => {\n if (reasonIsMenuAction(reason)) {\n if (reason?.closedBy === \"popup-service\") {\n return;\n }\n handleContextMenuAction(reason);\n // TODO this results in onClose being called twice on component\n // cant simply be removed, some refactoring work needed\n PopupService.hidePopup(reason);\n }\n contextMenuProps?.onClose?.(reason);\n };\n\n const position = positionProp ?? {\n x: e.clientX,\n y: e.clientY,\n };\n\n const component = (\n <ContextMenu\n {...contextMenuProps}\n onClose={handleClose}\n position={position}\n >\n {menuItems(menuDescriptors)}\n </ContextMenu>\n );\n PopupService.showPopup({ left: 0, top: 0, component, focus: true });\n};\n"],"names":["menuBuilder","ContextMenuProps","menuDescriptors"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePopupMenu.js","sources":["../../src/popup-menu/usePopupMenu.ts"],"sourcesContent":["import {\n AriaAttributes,\n MouseEvent,\n useCallback,\n useRef,\n useState,\n} from \"react\";\nimport { MenuOpenHandler } from \"../menu\";\nimport { PopupMenuProps } from \"./PopupMenu\";\nimport { getPositionRelativeToAnchor } from \"../popup/getPositionRelativeToAnchor\";\nimport { useContextMenu } from \"../menu\";\nimport { PopupCloseCallback, reasonIsClickAway } from \"../popup/popup-service\";\nimport { PopupPlacement } from \"../popup/Popup\";\n\nexport interface PopupMenuHookProps\n extends Pick<\n PopupMenuProps,\n | \"anchorElement\"\n | \"menuActionHandler\"\n | \"menuBuilder\"\n | \"menuClassName\"\n | \"menuOptions\"\n | \"onMenuClose\"\n | \"onMenuOpen\"\n > {\n id: string;\n menuLocation: string;\n popupPlacement: PopupPlacement;\n tabIndex: number;\n}\n\nexport const usePopupMenu = ({\n anchorElement,\n id,\n menuActionHandler,\n menuBuilder,\n menuClassName,\n menuLocation,\n menuOptions,\n onMenuClose,\n onMenuOpen,\n popupPlacement,\n tabIndex,\n}: PopupMenuHookProps) => {\n const [menuOpen, _setMenuOpen] = useState(false);\n const suppressShowMenuRef = useRef(false);\n const rootRef = useRef<HTMLButtonElement>(null);\n\n const setMenuOpen = useCallback(\n (isOpen) => {\n _setMenuOpen(isOpen);\n if (isOpen) {\n onMenuOpen?.();\n }\n },\n [onMenuOpen]
|
|
1
|
+
{"version":3,"file":"usePopupMenu.js","sources":["../../src/popup-menu/usePopupMenu.ts"],"sourcesContent":["import {\n AriaAttributes,\n MouseEvent,\n useCallback,\n useRef,\n useState,\n} from \"react\";\nimport { MenuOpenHandler } from \"../menu\";\nimport { PopupMenuProps } from \"./PopupMenu\";\nimport { getPositionRelativeToAnchor } from \"../popup/getPositionRelativeToAnchor\";\nimport { useContextMenu } from \"../menu\";\nimport { PopupCloseCallback, reasonIsClickAway } from \"../popup/popup-service\";\nimport { PopupPlacement } from \"../popup/Popup\";\n\nexport interface PopupMenuHookProps\n extends Pick<\n PopupMenuProps,\n | \"anchorElement\"\n | \"menuActionHandler\"\n | \"menuBuilder\"\n | \"menuClassName\"\n | \"menuOptions\"\n | \"onMenuClose\"\n | \"onMenuOpen\"\n > {\n id: string;\n menuLocation: string;\n popupPlacement: PopupPlacement;\n tabIndex: number;\n}\n\nexport const usePopupMenu = ({\n anchorElement,\n id,\n menuActionHandler,\n menuBuilder,\n menuClassName,\n menuLocation,\n menuOptions,\n onMenuClose,\n onMenuOpen,\n popupPlacement,\n tabIndex,\n}: PopupMenuHookProps) => {\n const [menuOpen, _setMenuOpen] = useState(false);\n const suppressShowMenuRef = useRef(false);\n const rootRef = useRef<HTMLButtonElement>(null);\n\n const setMenuOpen = useCallback(\n (isOpen: boolean) => {\n _setMenuOpen(isOpen);\n if (isOpen) {\n onMenuOpen?.();\n }\n },\n [onMenuOpen],\n );\n\n const [showContextMenu] = useContextMenu(menuBuilder, menuActionHandler);\n\n const handleOpenMenu = useCallback<MenuOpenHandler>((el) => {\n console.log(`menu Open `, {\n el,\n });\n }, []);\n\n const handleMenuClose = useCallback<PopupCloseCallback>(\n (reason) => {\n setMenuOpen(false);\n // If user has clicked the MenuButton whilst menu is open, we want to close it.\n // The PopupService will close it for us as a 'click-away' event. We don't want\n // that click on the button to re-open it.\n if (reasonIsClickAway(reason)) {\n const target = reason.mouseEvt.target as HTMLElement;\n if (target === rootRef.current) {\n suppressShowMenuRef.current = true;\n }\n onMenuClose?.(reason);\n } else {\n requestAnimationFrame(() => {\n onMenuClose?.(reason);\n if (tabIndex !== -1 && reason?.type !== \"tab-away\") {\n rootRef.current?.focus();\n }\n });\n }\n },\n [onMenuClose, setMenuOpen, tabIndex],\n );\n\n const showMenu = useCallback(\n (e: MouseEvent<HTMLElement>) => {\n if (suppressShowMenuRef.current) {\n suppressShowMenuRef.current = false;\n } else {\n const anchorEl = anchorElement?.current ?? rootRef.current;\n if (anchorEl) {\n const {\n left: x,\n top: y,\n width,\n } = getPositionRelativeToAnchor(anchorEl, popupPlacement, 0, 0);\n setMenuOpen(true);\n\n showContextMenu(e, menuLocation, {\n ContextMenuProps: {\n className: menuClassName,\n id: `${id}-menu`,\n onClose: handleMenuClose,\n openMenu: handleOpenMenu,\n position: {\n x,\n y,\n },\n style: { width: width ? width - 2 : undefined },\n },\n ...menuOptions,\n });\n }\n }\n },\n [\n anchorElement,\n handleMenuClose,\n handleOpenMenu,\n id,\n menuClassName,\n menuLocation,\n menuOptions,\n popupPlacement,\n setMenuOpen,\n showContextMenu,\n ],\n );\n\n const ariaAttributes: AriaAttributes = {\n \"aria-controls\": menuOpen ? `${id}-menu` : undefined,\n \"aria-expanded\": menuOpen,\n \"aria-haspopup\": \"menu\",\n };\n\n const buttonProps = {\n id,\n onClick: showMenu,\n tabIndex,\n };\n\n return { ariaAttributes, buttonProps, menuOpen, rootRef };\n};\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
2
|
+
"version": "0.10.0",
|
|
3
3
|
"description": "VUU popup components - Context Menu, Dialog etc",
|
|
4
4
|
"author": "heswell",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@salt-ds/core": "1.
|
|
7
|
+
"@salt-ds/core": "1.43.0",
|
|
8
8
|
"@salt-ds/styles": "0.2.1",
|
|
9
9
|
"@salt-ds/window": "0.1.1",
|
|
10
|
-
"@vuu-ui/vuu-data-types": "0.
|
|
11
|
-
"@vuu-ui/vuu-layout": "0.
|
|
12
|
-
"@vuu-ui/vuu-utils": "0.
|
|
13
|
-
"@vuu-ui/vuu-ui-controls": "0.
|
|
10
|
+
"@vuu-ui/vuu-data-types": "0.10.0",
|
|
11
|
+
"@vuu-ui/vuu-layout": "0.10.0",
|
|
12
|
+
"@vuu-ui/vuu-utils": "0.10.0",
|
|
13
|
+
"@vuu-ui/vuu-ui-controls": "0.10.0"
|
|
14
14
|
},
|
|
15
15
|
"peerDependencies": {
|
|
16
16
|
"clsx": "^2.0.0",
|
|
17
|
-
"react": "
|
|
18
|
-
"react-dom": "
|
|
17
|
+
"react": "^18.3.1",
|
|
18
|
+
"react-dom": "^18.3.1"
|
|
19
19
|
},
|
|
20
20
|
"sideEffects": false,
|
|
21
21
|
"files": [
|
|
@@ -13,7 +13,7 @@ export declare const useTooltip: ({ anchorQuery, id: idProp, placement, tooltipC
|
|
|
13
13
|
onMouseEnter: (evt: MouseEvent) => void;
|
|
14
14
|
onMouseLeave: () => void;
|
|
15
15
|
};
|
|
16
|
-
hideTooltip: (defer?:
|
|
17
|
-
showTooltip: (ref?:
|
|
16
|
+
hideTooltip: (defer?: number) => void;
|
|
17
|
+
showTooltip: (ref?: import("react").MutableRefObject<HTMLElement | null>) => void;
|
|
18
18
|
tooltipProps: TooltipProps | undefined;
|
|
19
19
|
};
|