UNPKG

flowbite-react

Version:

Official React components built for Flowbite and Tailwind CSS

165 lines (162 loc) 5.37 kB
'use client'; import { jsxs, jsx } from 'react/jsx-runtime'; import { useListNavigation, useTypeahead, FloatingFocusManager, FloatingList } from '@floating-ui/react'; import { useState, useRef, useCallback, useMemo, useEffect, cloneElement } from 'react'; import { HiOutlineChevronDown, HiOutlineChevronUp, HiOutlineChevronRight, HiOutlineChevronLeft } from 'react-icons/hi'; import { twMerge } from 'tailwind-merge'; import { mergeDeep } from '../../helpers/merge-deep.mjs'; import { useBaseFLoating, useFloatingInteractions } from '../../hooks/use-floating.mjs'; import { getTheme } from '../../theme-store/index.mjs'; import { Button } from '../Button/Button.mjs'; import '../Button/ButtonGroup.mjs'; import { DropdownContext } from './DropdownContext.mjs'; import { DropdownDivider } from './DropdownDivider.mjs'; import { DropdownHeader } from './DropdownHeader.mjs'; import { DropdownItem } from './DropdownItem.mjs'; const icons = { top: HiOutlineChevronUp, right: HiOutlineChevronRight, bottom: HiOutlineChevronDown, left: HiOutlineChevronLeft }; const Trigger = ({ refs, children, inline, theme, disabled, setButtonWidth, getReferenceProps, renderTrigger, ...buttonProps }) => { const ref = refs.reference; const a11yProps = getReferenceProps(); useEffect(() => { if (ref.current) { setButtonWidth?.(ref.current.clientWidth); } }, [ref, setButtonWidth]); if (renderTrigger) { const triggerElement = renderTrigger(theme); return cloneElement(triggerElement, { ref: refs.setReference, disabled, ...a11yProps, ...triggerElement.props }); } return inline ? /* @__PURE__ */ jsx("button", { type: "button", ref: refs.setReference, className: theme?.inlineWrapper, disabled, ...a11yProps, children }) : /* @__PURE__ */ jsx(Button, { ...buttonProps, disabled, type: "button", ref: refs.setReference, ...a11yProps, children }); }; const DropdownComponent = ({ children, className, dismissOnClick = true, theme: customTheme = {}, renderTrigger, ...props }) => { const [open, setOpen] = useState(false); const [activeIndex, setActiveIndex] = useState(null); const [selectedIndex, setSelectedIndex] = useState(null); const [buttonWidth, setButtonWidth] = useState(void 0); const elementsRef = useRef([]); const labelsRef = useRef([]); const theme = mergeDeep(getTheme().dropdown, customTheme); const theirProps = props; const dataTestId = props["data-testid"] || "flowbite-dropdown-target"; const { placement = props.inline ? "bottom-start" : "bottom", trigger = "click", label, inline, arrowIcon = true, ...buttonProps } = theirProps; const handleSelect = useCallback((index) => { setSelectedIndex(index); setOpen(false); }, []); const handleTypeaheadMatch = useCallback( (index) => { if (open) { setActiveIndex(index); } else { handleSelect(index); } }, [open, handleSelect] ); const { context, floatingStyles, refs } = useBaseFLoating({ open, setOpen, placement }); const listNav = useListNavigation(context, { listRef: elementsRef, activeIndex, selectedIndex, onNavigate: setActiveIndex }); const typeahead = useTypeahead(context, { listRef: labelsRef, activeIndex, selectedIndex, onMatch: handleTypeaheadMatch }); const { getReferenceProps, getFloatingProps, getItemProps } = useFloatingInteractions({ context, role: "menu", trigger, interactions: [listNav, typeahead] }); const Icon = useMemo(() => { const [p] = placement.split("-"); return icons[p] ?? HiOutlineChevronDown; }, [placement]); return /* @__PURE__ */ jsxs(DropdownContext.Provider, { value: { theme, activeIndex, dismissOnClick, getItemProps, handleSelect }, children: [ /* @__PURE__ */ jsxs( Trigger, { ...buttonProps, refs, inline, theme, "data-testid": dataTestId, className: twMerge(theme.floating.target, buttonProps.className), setButtonWidth, getReferenceProps, renderTrigger, children: [ label, arrowIcon && /* @__PURE__ */ jsx(Icon, { className: theme.arrowIcon }) ] } ), open && /* @__PURE__ */ jsx(FloatingFocusManager, { context, modal: false, children: /* @__PURE__ */ jsx( "div", { ref: refs.setFloating, style: { ...floatingStyles, minWidth: buttonWidth }, "data-testid": "flowbite-dropdown", "aria-expanded": open, ...getFloatingProps({ className: twMerge( theme.floating.base, theme.floating.animation, "duration-100", !open && theme.floating.hidden, theme.floating.style.auto, className ) }), children: /* @__PURE__ */ jsx(FloatingList, { elementsRef, labelsRef, children: /* @__PURE__ */ jsx("ul", { className: theme.content, tabIndex: -1, children }) }) } ) }) ] }); }; DropdownComponent.displayName = "Dropdown"; DropdownHeader.displayName = "Dropdown.Header"; DropdownDivider.displayName = "Dropdown.Divider"; const Dropdown = Object.assign(DropdownComponent, { Item: DropdownItem, Header: DropdownHeader, Divider: DropdownDivider }); export { Dropdown }; //# sourceMappingURL=Dropdown.mjs.map