83 lines
2.2 KiB
TypeScript
Executable File
83 lines
2.2 KiB
TypeScript
Executable File
import { FC, PropsWithChildren, ReactNode, useCallback, useState } from "react";
|
|
|
|
interface IProps {
|
|
expandOnHover?: boolean;
|
|
expanded?: boolean;
|
|
title?: ReactNode;
|
|
}
|
|
|
|
export const Accordion: FC<PropsWithChildren<IProps>> = (
|
|
{ children, expandOnHover, expanded, title },
|
|
) => {
|
|
const [open, setOpen] = useState(false);
|
|
|
|
return (
|
|
<div
|
|
data-expanded={open || expanded}
|
|
data-expandonhover={expandOnHover}
|
|
className={(expandOnHover ? "group/hover" : "group/controlled") +
|
|
" group"}
|
|
onClick={() => !title && !expandOnHover && setOpen(!open)}
|
|
>
|
|
{!!title && (
|
|
<div
|
|
className="flex justify-between cursor-pointer"
|
|
onClick={() => !expandOnHover && setOpen(!open)}
|
|
>
|
|
<div className="accordion-title">
|
|
{title}
|
|
</div>
|
|
<div
|
|
className={`
|
|
group-hover/hover:-rotate-180
|
|
group-data-[expanded]:-rotate-180
|
|
transition-transform
|
|
duration-500
|
|
grid
|
|
rounded-full
|
|
h-min
|
|
mr-2
|
|
mt-1
|
|
scale-y-50
|
|
`}
|
|
>
|
|
<span className="block w-2 h-2 rotate-45 border-r-2 border-b-2 place-self-center">
|
|
</span>
|
|
<span className="block w-2 h-2 rotate-45 border-r-2 border-b-2 place-self-center">
|
|
</span>
|
|
</div>
|
|
</div>
|
|
)}
|
|
{children}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export const AccordionContent: FC<PropsWithChildren> = ({ children }) => {
|
|
const [height, setHeight] = useState(0);
|
|
|
|
const updateRef = useCallback((node: HTMLDivElement | null) => {
|
|
if (node) {
|
|
setHeight(node.clientHeight);
|
|
} else {
|
|
setHeight(0);
|
|
}
|
|
}, []);
|
|
|
|
const Child = () => (
|
|
<div className="absolute bottom-0 w-full" ref={updateRef}>
|
|
{children}
|
|
</div>
|
|
);
|
|
|
|
return (
|
|
<div className="relative overflow-hidden">
|
|
{<Child />}
|
|
<span
|
|
style={{ ["--v-height" as never]: height + "px" }}
|
|
className="w-0 block h-0 group-hover/hover:h-variable group-data-[expanded]/controlled:h-variable transition-all duration-700"
|
|
/>
|
|
</div>
|
|
);
|
|
};
|