import { AnimatePresence } from 'framer-motion'; import { Card, Box, BoxProps, Portal } from '../../../general'; import styled from 'styled-components'; import { getAnchorPointByElement, getMenuHeight, Position, Orientation, Dimensions, } from '../../util/position'; import { useState, useEffect, useCallback, useMemo } from 'react'; import { MenuItem, MenuItemProps } from './MenuItem'; import { useMenu } from './useMenu'; const WIDTH = 180; const MAX_HEIGHT = 300; const MENU_ITEM_HEIGHT = 36; const DIVIDER_HEIGHT = 2; const PADDING = 4; const Divider = styled(Box)` width: 95%; border: 1px solid rgba(var(--rlm-border-rgba)); opacity: 0.3; margin: 1px auto; `; type MenuType = 'custom' | 'options'; export type MenuProps = { id: string; orientation: Orientation; anchorRef?: React.RefObject; triggerEl?: React.ReactNode; controlledIsOpen?: boolean; closableIds?: string[]; closableClasses?: string[]; children?: React.ReactNode; dimensions?: Dimensions; offset?: Position; options?: MenuItemProps[]; } & BoxProps; export const Menu = ({ id, triggerEl, children, dimensions, orientation = 'bottom-right', offset = { x: 0, y: 2 }, options, className, closableIds, closableClasses, }: MenuProps) => { let innerContent: React.ReactNode; let type: MenuType = 'custom'; // calculate the height of the menu based on the number of options // or use the passed in dimensions const menuHeight = useMemo( () => dimensions?.height || getMenuHeight(options || [], MENU_ITEM_HEIGHT, DIVIDER_HEIGHT, PADDING), [dimensions, options] ); // create dimensions object for the menu const menuDimensions = { width: dimensions?.width || WIDTH, height: menuHeight, }; const { isOpen, menuRef, position, toggleMenu } = useMenu( orientation, menuDimensions, offset, closableIds, closableClasses ); if (!children && options && options.length > 0) { type = 'options'; innerContent = options.map((option, index) => { const divider = index > 0 && options[index - 1].section !== option.section; return (
{divider && }
); }); } else { type = 'custom'; innerContent = children; } const isCustom = type === 'custom'; const preventPropagation = useCallback((event: React.MouseEvent) => { event.stopPropagation(); }, []); return ( <> {triggerEl && ( {triggerEl} )} {isOpen && position && ( {innerContent} )} ); }; export type CustomMenuProps = { id: string; orientation: Orientation; anchorRef?: React.RefObject; children?: React.ReactNode; dimensions?: Dimensions; offset?: Position; } & BoxProps; export const CustomMenu = ({ anchorRef, id, children, dimensions, orientation, offset, }: CustomMenuProps) => { const [anchorPoint, setAnchorPoint] = useState(null); useEffect(() => { const el = anchorRef?.current; console.log('CustomMenu', el); if (el) { const height = el.offsetHeight; setAnchorPoint( getAnchorPointByElement( el, { width: dimensions?.width || WIDTH, height: dimensions?.height || height, }, orientation, offset ) ); } }, [anchorRef]); console.log('CustomMenu achnor', anchorPoint); if (!anchorPoint) return null; return ( {children} ); };