Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pterodactyl
GitHub Repository: pterodactyl/panel
Path: blob/1.0-develop/resources/scripts/components/elements/dropdown/Dropdown.tsx
10262 views
1
import React, { ElementType, forwardRef, useMemo } from 'react';
2
import { Menu, Transition } from '@headlessui/react';
3
import styles from './style.module.css';
4
import classNames from 'classnames';
5
import DropdownItem from '@/components/elements/dropdown/DropdownItem';
6
import DropdownButton from '@/components/elements/dropdown/DropdownButton';
7
8
interface Props {
9
as?: ElementType;
10
children: React.ReactNode;
11
}
12
13
const DropdownGap = ({ invisible }: { invisible?: boolean }) => (
14
<div className={classNames('border m-2', { 'border-neutral-700': !invisible, 'border-transparent': invisible })} />
15
);
16
17
type TypedChild = (React.ReactChild | React.ReactFragment | React.ReactPortal) & {
18
type?: JSX.Element;
19
};
20
21
const Dropdown = forwardRef<typeof Menu, Props>(({ as, children }, ref) => {
22
const [Button, items] = useMemo(() => {
23
const list = React.Children.toArray(children) as unknown as TypedChild[];
24
25
return [
26
list.filter((child) => child.type === DropdownButton),
27
list.filter((child) => child.type !== DropdownButton),
28
];
29
}, [children]);
30
31
if (!Button) {
32
throw new Error('Cannot mount <Dropdown /> component without a child <Dropdown.Button />.');
33
}
34
35
return (
36
<Menu as={as || 'div'} className={styles.menu} ref={ref}>
37
{Button}
38
<Transition
39
enter={'transition duration-100 ease-out'}
40
enterFrom={'transition scale-95 opacity-0'}
41
enterTo={'transform scale-100 opacity-100'}
42
leave={'transition duration-75 ease-out'}
43
leaveFrom={'transform scale-100 opacity-100'}
44
leaveTo={'transform scale-95 opacity-0'}
45
>
46
<Menu.Items className={classNames(styles.items_container, 'w-56')}>
47
<div className={'px-1 py-1'}>{items}</div>
48
</Menu.Items>
49
</Transition>
50
</Menu>
51
);
52
});
53
54
const _Dropdown = Object.assign(Dropdown, {
55
Button: DropdownButton,
56
Item: DropdownItem,
57
Gap: DropdownGap,
58
});
59
60
export { _Dropdown as default };
61
62