Path: blob/1.0-develop/resources/scripts/components/elements/dropdown/Dropdown.tsx
10262 views
import React, { ElementType, forwardRef, useMemo } from 'react';1import { Menu, Transition } from '@headlessui/react';2import styles from './style.module.css';3import classNames from 'classnames';4import DropdownItem from '@/components/elements/dropdown/DropdownItem';5import DropdownButton from '@/components/elements/dropdown/DropdownButton';67interface Props {8as?: ElementType;9children: React.ReactNode;10}1112const DropdownGap = ({ invisible }: { invisible?: boolean }) => (13<div className={classNames('border m-2', { 'border-neutral-700': !invisible, 'border-transparent': invisible })} />14);1516type TypedChild = (React.ReactChild | React.ReactFragment | React.ReactPortal) & {17type?: JSX.Element;18};1920const Dropdown = forwardRef<typeof Menu, Props>(({ as, children }, ref) => {21const [Button, items] = useMemo(() => {22const list = React.Children.toArray(children) as unknown as TypedChild[];2324return [25list.filter((child) => child.type === DropdownButton),26list.filter((child) => child.type !== DropdownButton),27];28}, [children]);2930if (!Button) {31throw new Error('Cannot mount <Dropdown /> component without a child <Dropdown.Button />.');32}3334return (35<Menu as={as || 'div'} className={styles.menu} ref={ref}>36{Button}37<Transition38enter={'transition duration-100 ease-out'}39enterFrom={'transition scale-95 opacity-0'}40enterTo={'transform scale-100 opacity-100'}41leave={'transition duration-75 ease-out'}42leaveFrom={'transform scale-100 opacity-100'}43leaveTo={'transform scale-95 opacity-0'}44>45<Menu.Items className={classNames(styles.items_container, 'w-56')}>46<div className={'px-1 py-1'}>{items}</div>47</Menu.Items>48</Transition>49</Menu>50);51});5253const _Dropdown = Object.assign(Dropdown, {54Button: DropdownButton,55Item: DropdownItem,56Gap: DropdownGap,57});5859export { _Dropdown as default };606162