import React from 'react'; import { MenuToggle, Menu, MenuContent, MenuList, MenuItem, MenuGroup, MenuInput, Popper, Tooltip, Divider, TextInput } from '@patternfly/react-core'; import { Link } from '@reach/router'; import ThIcon from '@patternfly/react-icons/dist/js/icons/th-icon'; import pfIcon from 'pf-logo-small.svg'; export const ComposableApplicationLauncher: React.FunctionComponent = () => { const [isOpen, setIsOpen] = React.useState(false); const [refFullOptions, setRefFullOptions] = React.useState(); const [favorites, setFavorites] = React.useState([]); const [filteredIds, setFilteredIds] = React.useState(['*']); const menuRef = React.useRef(null); const toggleRef = React.useRef(null); const containerRef = React.useRef(null); const handleMenuKeys = (event: KeyboardEvent) => { if (!isOpen) { return; } if (menuRef.current?.contains(event.target as Node) || toggleRef.current?.contains(event.target as Node)) { if (event.key === 'Escape') { setIsOpen(!isOpen); toggleRef.current?.focus(); } } }; const handleClickOutside = (event: MouseEvent) => { if (isOpen && !menuRef.current?.contains(event.target as Node)) { setIsOpen(false); } }; const onToggleClick = (ev: React.MouseEvent) => { ev.stopPropagation(); // Stop handleClickOutside from handling setTimeout(() => { if (menuRef.current) { const firstElement = menuRef.current.querySelector( 'li > button:not(:disabled), li > a:not(:disabled), input:not(:disabled)' ); firstElement && (firstElement as HTMLElement).focus(); setRefFullOptions(Array.from(menuRef.current.querySelectorAll('li:not(li[role=separator])'))); } }, 0); setIsOpen(!isOpen); }; React.useEffect(() => { window.addEventListener('keydown', handleMenuKeys); window.addEventListener('click', handleClickOutside); return () => { window.removeEventListener('keydown', handleMenuKeys); window.removeEventListener('click', handleClickOutside); }; }, [isOpen, menuRef]); const toggle = ( ); const menuItems = [ Application 1 ev.preventDefault()} > Application 2 , , } > @reach/router Link } component={props => } > @reach/router Link with icon , , Launch Application 3} position="right"> Application 3 with tooltip Unavailable Application ]; const createFavorites = (favIds: string[]) => { const favorites: unknown[] = []; menuItems.forEach(item => { if (item.type === MenuList) { item.props.children.filter(child => { if (favIds.includes(child.props.itemId)) { favorites.push(child); } }); } else if (item.type === MenuGroup) { item.props.children.props.children.filter(child => { if (favIds.includes(child.props.itemId)) { favorites.push(child); } }); } else { if (favIds.includes(item.props.itemId)) { favorites.push(item); } } }); return favorites; }; const filterItems = (items: any[], filteredIds: string[]) => { if (filteredIds.length === 1 && filteredIds[0] === '*') { return items; } let keepDivider = false; const filteredCopy = items .map(group => { if (group.type === MenuGroup) { const filteredGroup = React.cloneElement(group, { children: React.cloneElement(group.props.children, { children: group.props.children.props.children.filter(child => { if (filteredIds.includes(child.props.itemId)) { return child; } }) }) }); const filteredList = filteredGroup.props.children; if (filteredList.props.children.length > 0) { keepDivider = true; return filteredGroup; } else { keepDivider = false; } } else if (group.type === MenuList) { const filteredGroup = React.cloneElement(group, { children: group.props.children.filter(child => { if (filteredIds.includes(child.props.itemId)) { return child; } }) }); if (filteredGroup.props.children.length > 0) { keepDivider = true; return filteredGroup; } else { keepDivider = false; } } else { if ((keepDivider && group.type === Divider) || filteredIds.includes(group.props.itemId)) { return group; } } }) .filter(newGroup => newGroup); if (filteredCopy.length > 0) { const lastGroup = filteredCopy.pop(); if (lastGroup.type !== Divider) { filteredCopy.push(lastGroup); } } return filteredCopy; }; const onTextChange = (textValue: string) => { if (textValue === '') { setFilteredIds(['*']); return; } const filteredIds = refFullOptions ?.filter(item => (item as HTMLElement).innerText.toLowerCase().includes(textValue.toString().toLowerCase())) .map(item => item.id) || []; setFilteredIds(filteredIds); }; const onFavorite = (event: any, itemId: string, actionId: string) => { event.stopPropagation(); if (actionId === 'fav') { const isFavorite = favorites.includes(itemId); if (isFavorite) { setFavorites(favorites.filter(fav => fav !== itemId)); } else { setFavorites([...favorites, itemId]); } } }; const filteredFavorites = filterItems(createFavorites(favorites), filteredIds); const filteredItems = filterItems(menuItems, filteredIds); if (filteredItems.length === 0) { filteredItems.push(No results found); } const menu = ( // eslint-disable-next-line no-console console.log('selected', itemId)}> onTextChange(value)} /> {filteredFavorites.length > 0 && ( {filteredFavorites} )} {filteredItems} ); return (
); };