84 lines
2.5 KiB
TypeScript
84 lines
2.5 KiB
TypeScript
import React, { useRef, useEffect, useState } from 'react';
|
|
import { animated, useSpring } from '@react-spring/web';
|
|
import clsx from 'clsx';
|
|
|
|
interface MCDropdownProps {
|
|
id: string;
|
|
options: { [key: string]: string };
|
|
onSelect: (value: string) => void;
|
|
selectedValue?: string;
|
|
className?: string;
|
|
width: number;
|
|
isOpen: boolean;
|
|
onToggle: (id: string) => void;
|
|
}
|
|
|
|
const MCDropdown: React.FC<MCDropdownProps> = ({
|
|
id,
|
|
options,
|
|
onSelect,
|
|
selectedValue,
|
|
className = "relative",
|
|
width,
|
|
isOpen,
|
|
onToggle,
|
|
}) => {
|
|
const contentRef = useRef<HTMLDivElement>(null);
|
|
const [contentHeight, setContentHeight] = useState(0);
|
|
|
|
useEffect(() => {
|
|
if (contentRef.current) {
|
|
setContentHeight(contentRef.current.scrollHeight);
|
|
}
|
|
}, [options]);
|
|
|
|
const springProps = useSpring({
|
|
height: isOpen ? contentHeight : 0,
|
|
opacity: isOpen ? 1 : 0,
|
|
config: { tension: 300, friction: 30 }
|
|
});
|
|
|
|
return (
|
|
<div className={`${className} inline-block`} style={{ width: `${width}px` }}>
|
|
<button
|
|
onClick={() => onToggle(id)}
|
|
className={
|
|
clsx("rounded-full hover:text-white transition duration-300 ease-in-out px-5 py-2 text-center w-full flex items-center justify-between",
|
|
selectedValue ? "bg-mti-purple text-white" : "bg-mti-purple-ultralight text-mti-purple-light"
|
|
)}
|
|
>
|
|
<span className="truncate p-1">{selectedValue || 'Select an option'}</span>
|
|
<svg
|
|
className={`w-4 h-4 transform transition-transform ${isOpen ? 'rotate-180' : ''}`}
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
>
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
|
|
</svg>
|
|
</button>
|
|
<animated.div
|
|
style={{ ...springProps, width: `${width}px` }}
|
|
className="absolute z-10 mt-1 overflow-hidden bg-white rounded-md shadow-lg"
|
|
>
|
|
<div ref={contentRef}>
|
|
{Object.entries(options).sort((a, b) => a[0].localeCompare(b[0])).map(([key, value]) => (
|
|
<div
|
|
key={key}
|
|
onClick={() => {
|
|
onSelect(value);
|
|
onToggle(id);
|
|
}}
|
|
className="p-4 hover:bg-mti-purple-ultralight cursor-pointer whitespace-nowrap"
|
|
>
|
|
<span>{value}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</animated.div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default MCDropdown; |