{"version":3,"file":"index.mjs","names":["Children","ComponentPropsWithRef","ReactElement","RefObject","cloneElement","isValidElement","useEffect","useEffectEvent","useRef","useState","FloatingFocusManager","FloatingPortal","autoUpdate","flip","offset","shift","size","useDismiss","useFloating","useInteractions","useListNavigation","useRole","useTypeahead","ContextMenuItemProps","Dialog","useRefDebounce","CustomContextEvent","CustomEvent","emulated","originalEvent","Event","Props","targetRef","HTMLElement","children","eventName","debounceOpenning","ContextMenu","style","activeIndex","setActiveIndex","isOpen","setIsOpen","isOpenDebounceRef","contextEvent","MouseEvent","listItemsRef","HTMLButtonElement","listContentRef","map","child","props","label","refs","floatingStyles","context","open","onOpenChange","middleware","mainAxis","alignmentAxis","apply","elements","availableHeight","firstChild","floating","firstElementChild","maxHeight","Math","min","padding","placement","window","matchMedia","matches","undefined","strategy","whileElementsMounted","role","dismiss","listNavigation","listRef","onNavigate","typeahead","enabled","onMatch","getFloatingProps","getItemProps","onContextMenuStable","onContextMenu","e","preventDefault","isEmulatedContextMenu","type","detail","current","setPositionReference","getBoundingClientRect","width","height","x","clientX","y","clientY","top","right","bottom","left","stableTarget","document","documentElement","addEventListener","removeEventListener","setFloating","index","tabIndex","ref","node","onMouseUp","onClick","React","ComponentPropsWithRef","ReactNode","RefObject","clsx","ContextMenuItemMouseEvent","MouseEvent","HTMLButtonElement","CustomEvent","ContextMenuItemProps","Omit","label","disabled","icon","onClick","e","ref","ContextMenuItem","t0","$","_c","className","props","t1","t2","t3","t4"],"sources":["../../../src/components/context-menu/ContextMenu.tsx","../../../src/components/context-menu/ContextMenuItem.tsx"],"sourcesContent":["import {\n  Children,\n  ComponentPropsWithRef,\n  ReactElement,\n  RefObject,\n  cloneElement,\n  isValidElement,\n  useEffect,\n  useEffectEvent,\n  useRef,\n  useState,\n} from \"react\";\nimport {\n  FloatingFocusManager,\n  FloatingPortal,\n  autoUpdate,\n  flip,\n  offset,\n  shift,\n  size,\n  useDismiss,\n  useFloating,\n  useInteractions,\n  useListNavigation,\n  useRole,\n  useTypeahead,\n} from \"@floating-ui/react\";\n\nimport { ContextMenuItemProps } from \"./ContextMenuItem\";\nimport { Dialog } from \"../dialog/Dialog\";\nimport { useRefDebounce } from \"../../hooks\";\n\ntype CustomContextEvent = CustomEvent<{ emulated: boolean; originalEvent: Event }>;\n\ninterface Props extends ComponentPropsWithRef<\"div\"> {\n  targetRef?: RefObject<HTMLElement>;\n  children: ReactElement[] | ReactElement;\n  eventName?: \"contextmenu\" | string;\n  debounceOpenning?: number;\n}\nexport function ContextMenu({ targetRef, children, style, eventName = \"contextmenu\" }: Props) {\n  const [activeIndex, setActiveIndex] = useState<number | null>(null);\n  const [isOpen, setIsOpen] = useState(false);\n  const isOpenDebounceRef = useRefDebounce(isOpen, 200);\n  const contextEvent = useRef<MouseEvent | CustomEvent | null>(null);\n  const listItemsRef = useRef<(HTMLButtonElement | null)[]>([]);\n  const listContentRef = useRef(\n    Children.map(children, (child) =>\n      isValidElement<ContextMenuItemProps>(child) ? child.props.label : null,\n    ) as (string | null)[],\n  );\n\n  const { refs, floatingStyles, context } = useFloating({\n    open: isOpen,\n    onOpenChange: setIsOpen,\n    middleware: [\n      offset({ mainAxis: 5, alignmentAxis: 4 }),\n      flip(),\n      size({\n        apply({ elements, availableHeight }) {\n          const firstChild = elements.floating.firstElementChild as HTMLElement;\n          if (firstChild) {\n            firstChild.style.maxHeight = `${Math.min(availableHeight, 300)}px`;\n          }\n        },\n        padding: 10,\n      }),\n      shift({ padding: 10 }),\n    ],\n    /**\n     * it is better to be less demanding on small screen sizes to see the content displayed correctly\n     */\n    placement: window.matchMedia(\"(min-width: 700px)\").matches ? \"right-start\" : undefined,\n    strategy: \"fixed\",\n    whileElementsMounted: autoUpdate,\n  });\n\n  const role = useRole(context, { role: \"menu\" });\n  const dismiss = useDismiss(context);\n\n  const listNavigation = useListNavigation(context, {\n    listRef: listItemsRef,\n    onNavigate: setActiveIndex,\n    activeIndex,\n  });\n  const typeahead = useTypeahead(context, {\n    enabled: isOpen,\n    listRef: listContentRef,\n    onMatch: setActiveIndex,\n    activeIndex,\n  });\n\n  const { getFloatingProps, getItemProps } = useInteractions([\n    role,\n    dismiss,\n    listNavigation,\n    typeahead,\n  ]);\n\n  const onContextMenuStable = useEffectEvent(function onContextMenu(\n    e: MouseEvent | CustomContextEvent,\n  ) {\n    e.preventDefault();\n    /**\n     * in certain cases (maplibre-gl) we will not be able to use the\n     * native \"contextmenu\" event for touch screens and we will emulate this\n     * with a simple \"click\" event\n     *\n     * with emulated event if the context menu has just been closed we probably\n     * do not want a click to immediately reopen a new context menu\n     */\n    const isEmulatedContextMenu =\n      e.type !== \"contextmenu\" && (e as CustomContextEvent).detail.emulated;\n\n    if (isEmulatedContextMenu && isOpenDebounceRef.current) {\n      return;\n    }\n\n    const originalEvent = e instanceof MouseEvent ? e : (e.detail.originalEvent as MouseEvent);\n    contextEvent.current = e;\n\n    refs.setPositionReference({\n      getBoundingClientRect() {\n        return {\n          width: 0,\n          height: 0,\n          x: originalEvent.clientX,\n          y: originalEvent.clientY,\n          top: originalEvent.clientY,\n          right: originalEvent.clientX,\n          bottom: originalEvent.clientY,\n          left: originalEvent.clientX,\n        };\n      },\n    });\n\n    setIsOpen(true);\n    isOpenDebounceRef.current = true;\n  });\n\n  useEffect(() => {\n    const stableTarget = targetRef?.current ?? document.documentElement;\n    // console.log(\"add contextmenu\", targetRef);\n    stableTarget.addEventListener(eventName as \"contextmenu\", onContextMenuStable);\n    return () => {\n      // console.log(\"remove contextmenu\", targetRef);\n      stableTarget.removeEventListener(eventName as \"contextmenu\", onContextMenuStable);\n    };\n  }, [eventName, targetRef]);\n\n  return (\n    <FloatingPortal>\n      {isOpen && (\n        <FloatingFocusManager context={context} initialFocus={refs.floating}>\n          <div\n            className=\"z-dialog outline-hidden\"\n            ref={refs.setFloating}\n            style={{ ...floatingStyles, ...style }}\n            {...getFloatingProps()}\n          >\n            <Dialog placement={context.placement} className=\"z-context-menu max-h-80 overflow-auto\">\n              {Children.map(\n                children,\n                (child, index) =>\n                  isValidElement<ContextMenuItemProps>(child) &&\n                  cloneElement(\n                    child,\n                    getItemProps({\n                      tabIndex: activeIndex === index ? 0 : -1,\n                      ref(node: HTMLButtonElement) {\n                        listItemsRef.current[index] = node;\n                      },\n                      onMouseUp() {\n                        child.props.onClick?.(contextEvent.current);\n                        setIsOpen(false);\n                      },\n                    }),\n                  ),\n              )}\n            </Dialog>\n          </div>\n        </FloatingFocusManager>\n      )}\n    </FloatingPortal>\n  );\n}\n","import React, { ComponentPropsWithRef, ReactNode, RefObject } from \"react\";\nimport clsx from \"clsx\";\n\nexport type ContextMenuItemMouseEvent =\n  | React.MouseEvent<HTMLButtonElement>\n  | MouseEvent\n  | CustomEvent\n  | null;\n\nexport interface ContextMenuItemProps extends Omit<ComponentPropsWithRef<\"button\">, \"onClick\"> {\n  label: string;\n  disabled?: boolean;\n  icon?: ReactNode;\n  onClick?: (e: ContextMenuItemMouseEvent) => void;\n  ref?: RefObject<HTMLButtonElement>;\n}\n\nexport function ContextMenuItem({\n  label,\n  disabled,\n  icon,\n  className,\n  ref,\n  ...props\n}: ContextMenuItemProps) {\n  return (\n    <button\n      {...props}\n      className={clsx([\"option\", className])}\n      ref={ref}\n      role=\"menuitem\"\n      data-presentation=\"compact\"\n      {...(disabled ? { disabled } : {})}\n    >\n      {icon}\n      <span className=\"content\">{label}</span>\n    </button>\n  );\n}\n"],"mappings":"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"}