{"version":3,"file":"Dropdown.cjs","sources":["../../../src/components/Dropdown/Dropdown.tsx"],"sourcesContent":["'use client'\n\nimport {\n  type FC,\n  type MutableRefObject,\n  type PropsWithChildren,\n  type ReactNode,\n  createContext,\n  createRef,\n  useCallback,\n  useContext,\n  useEffect,\n  useId,\n  useMemo,\n  useRef,\n  useState,\n} from 'react'\n\nimport { usePortal } from '../../hooks/usePortal'\n\nimport { type Rect, getFirstTabbable, isEventFromChild } from './dropdownHelper'\n\ntype Props = PropsWithChildren<{\n  onOpen?: () => void\n  onClose?: () => void\n}>\n\ntype DropdownContextType = {\n  active: boolean\n  triggerRect: Rect\n  triggerElementRef: MutableRefObject<HTMLDivElement | null>\n  rootTriggerRef: MutableRefObject<HTMLDivElement | null> | null\n  onClickTrigger: (rect: Rect) => void\n  onClickCloser: () => void\n  DropdownContentRoot: FC<{ children: ReactNode }>\n  contentId: string\n}\n\nconst initialRect = { top: 0, right: 0, bottom: 0, left: 0 }\n\nexport const DropdownContext = createContext<DropdownContextType>({\n  active: false,\n  triggerRect: initialRect,\n  triggerElementRef: createRef(),\n  rootTriggerRef: null,\n  onClickTrigger: () => {\n    /* noop */\n  },\n  onClickCloser: () => {\n    /* noop */\n  },\n  DropdownContentRoot: () => null,\n  contentId: '',\n})\n\nexport const Dropdown: FC<Props> = ({ onOpen, onClose, children }) => {\n  const [active, setActive] = useState(false)\n  const [triggerRect, setTriggerRect] = useState<Rect>(initialRect)\n\n  const { rootTriggerRef } = useContext(DropdownContext)\n  const { createPortal, portalRoot, isPortalRootMounted, isChildPortal, PortalParentProvider } =\n    usePortal()\n\n  const triggerElementRef = useRef<HTMLDivElement>(null)\n  const contentId = useId()\n\n  if (portalRoot) {\n    portalRoot.setAttribute('id', contentId)\n  }\n\n  useEffect(() => {\n    const onClickBody = (e: any) => {\n      // ignore events from events within DropdownTrigger and DropdownContent\n      if (!isEventFromChild(e, triggerElementRef.current) && !isChildPortal(e.target)) {\n        setActive(false)\n      }\n    }\n\n    document.body.addEventListener('click', onClickBody, false)\n\n    return () => {\n      document.body.removeEventListener('click', onClickBody, false)\n    }\n  }, [isChildPortal, portalRoot])\n\n  // This is the root container of a dropdown content located in outside the DOM tree\n  const DropdownContentRoot = useMemo<FC<{ children: ReactNode }>>(() => {\n    const result: FC<{ children: ReactNode }> = (props) =>\n      active ? createPortal(props.children) : null\n\n    // set the displayName explicit for DevTools\n    result.displayName = 'DropdownContentRoot'\n\n    return result\n  }, [active, createPortal])\n\n  const togglerRef = useRef({\n    isPortalRootMounted,\n    onOpen,\n    onClose,\n  })\n  useEffect(() => {\n    togglerRef.current = {\n      isPortalRootMounted,\n      onOpen,\n      onClose,\n    }\n  }, [isPortalRootMounted, onOpen, onClose])\n\n  useEffect(() => {\n    if (togglerRef.current.isPortalRootMounted()) {\n      togglerRef.current[active ? 'onOpen' : 'onClose']?.()\n    }\n  }, [active])\n\n  const onClickTrigger = useCallback((rect: Rect) => {\n    setActive((current) => {\n      const newActive = !current\n\n      if (newActive) {\n        setTriggerRect(rect)\n      }\n\n      return newActive\n    })\n  }, [])\n\n  const onClickCloser = useCallback(() => {\n    setActive(false)\n\n    // return focus to the Trigger\n    getFirstTabbable(triggerElementRef)?.focus()\n  }, [])\n\n  return (\n    <PortalParentProvider>\n      <DropdownContext.Provider\n        value={{\n          active,\n          triggerRect,\n          triggerElementRef,\n          rootTriggerRef: rootTriggerRef || triggerElementRef || null,\n          onClickTrigger,\n          onClickCloser,\n          DropdownContentRoot,\n          contentId,\n        }}\n      >\n        {children}\n      </DropdownContext.Provider>\n    </PortalParentProvider>\n  )\n}\n"],"names":[],"mappings":";;;;;;;;AAsCA;AAEO;AACL;AACA;;AAEA;;;;;;;AAOA;AACA;AACD;AAEM;;;;AAKL;AAGA;AACA;;AAGE;;;AAIA;;AAEE;;;AAGF;;AAIA;;AAEA;AACF;;AAGA;;;AAKE;AAEA;AACF;;;;;AAMC;;;;;;;;;AAUC;AACE;;AAEJ;AAEA;AACE;AACE;;;;AAMA;AACF;;AAGF;;;AAIE;;;;;;AAUM;;;;;AAKD;AAMT;;;"}