import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
import { DropdownMenuRadioGroup } from '@radix-ui/react-dropdown-menu';
import { CheckIcon } from '@radix-ui/react-icons';
import classnames from 'classnames';
import { motion } from 'framer-motion';
import type { ForwardedRef, HTMLAttributes, ReactNode } from 'react';
import { forwardRef, useImperativeHandle, useLayoutEffect, useState } from 'react';
interface DropdownMenuRadioProps {
children: ReactNode;
onValueChange: ((v: { label: string; value: string }) => void) | null;
value: string;
label?: string;
items: {
label: string;
value: string;
}[];
}
export function DropdownMenuRadio({
children,
items,
onValueChange,
label,
value,
}: DropdownMenuRadioProps) {
const handleChange = (value: string) => {
const item = items.find((item) => item.value === value);
if (item && onValueChange) {
onValueChange(item);
}
};
return (
{children}
{label && {label}}
{items.map((item) => (
{item.label}
))}
);
}
export interface DropdownProps {
children: ReactNode;
items: (
| {
label: string;
onSelect?: () => void;
disabled?: boolean;
leftSlot?: ReactNode;
}
| '-----'
)[];
}
export function Dropdown({ children, items }: DropdownProps) {
return (
{children}
{items.map((item, i) => {
if (item === '-----') {
return ;
} else {
return (
item.onSelect?.()}
disabled={item.disabled}
leftSlot={item.leftSlot}
>
{item.label}
);
}
})}
);
}
const dropdownMenuClasses = 'bg-background rounded-md shadow-lg p-1.5 border border-gray-100';
interface DropdownMenuPortalProps {
children: ReactNode;
}
function DropdownMenuPortal({ children }: DropdownMenuPortalProps) {
return (
('#radix-portal')}>
{children}
);
}
const DropdownMenuContent = forwardRef(
function DropdownMenuContent(
{ className, children, ...props }: DropdownMenu.DropdownMenuContentProps,
ref: ForwardedRef,
) {
const [styles, setStyles] = useState<{ maxHeight: number }>();
const [divRef, setDivRef] = useState(null);
useImperativeHandle(ref, () => divRef);
const initDivRef = (ref: HTMLDivElement | null) => {
setDivRef(ref);
};
// Calculate the max height so we can scroll
useLayoutEffect(() => {
if (divRef === null) return;
// Needs to be in a setTimeout because the ref is not positioned yet
// TODO: Make this better?
setTimeout(() => {
const windowBox = document.documentElement.getBoundingClientRect();
const menuBox = divRef.getBoundingClientRect();
const styles = { maxHeight: windowBox.height - menuBox.top - 5 - 45 };
setStyles(styles);
});
}, [divRef]);
return (
{children}
);
},
);
type DropdownMenuItemProps = DropdownMenu.DropdownMenuItemProps & ItemInnerProps;
function DropdownMenuItem({
leftSlot,
rightSlot,
className,
children,
disabled,
...props
}: DropdownMenuItemProps) {
return (
{children}
);
}
// type DropdownMenuCheckboxItemProps = DropdownMenu.DropdownMenuCheckboxItemProps & ItemInnerProps;
//
// function DropdownMenuCheckboxItem({
// leftSlot,
// rightSlot,
// children,
// ...props
// }: DropdownMenuCheckboxItemProps) {
// return (
//
//
// {children}
//
//
// );
// }
// type DropdownMenuSubTriggerProps = DropdownMenu.DropdownMenuSubTriggerProps & ItemInnerProps;
//
// function DropdownMenuSubTrigger({
// leftSlot,
// rightSlot,
// children,
// ...props
// }: DropdownMenuSubTriggerProps) {
// return (
//
//
// {children}
//
//
// );
// }
type DropdownMenuRadioItemProps = Omit<
DropdownMenu.DropdownMenuRadioItemProps & ItemInnerProps,
'leftSlot'
>;
function DropdownMenuRadioItem({ rightSlot, children, ...props }: DropdownMenuRadioItemProps) {
return (
}
rightSlot={rightSlot}
>
{children}
);
}
// const DropdownMenuSubContent = forwardRef(
// function DropdownMenuSubContent(
// { className, ...props }: DropdownMenu.DropdownMenuSubContentProps,
// ref,
// ) {
// return (
//
// );
// },
// );
function DropdownMenuLabel({ className, children, ...props }: DropdownMenu.DropdownMenuLabelProps) {
return (
{children}
);
}
function DropdownMenuSeparator({ className, ...props }: DropdownMenu.DropdownMenuSeparatorProps) {
return (
);
}
function DropdownMenuTrigger({
children,
className,
...props
}: DropdownMenu.DropdownMenuTriggerProps) {
return (
{children}
);
}
interface ItemInnerProps extends HTMLAttributes {
leftSlot?: ReactNode;
rightSlot?: ReactNode;
children: ReactNode;
noHover?: boolean;
}
const ItemInner = forwardRef(function ItemInner(
{ leftSlot, rightSlot, children, className, noHover, ...props }: ItemInnerProps,
ref,
) {
return (
{leftSlot &&
{leftSlot}
}
{children}
{rightSlot &&
{rightSlot}
}
);
});