import React, { useState, useRef, useEffect } from "react"; // Dropdown Item Component const DropdownItem = ({ label, href, onClick, }: { label: string; href?: string; onClick?: () => void; }) => ( { e.preventDefault(); onClick?.(); }} > {label} ); // Nested Dropdown Component const NestedDropdown = ({ label, children, onSelect, }: { label: string; children: React.ReactNode; onSelect: (selectedLabel: string) => void; }) => { const [open, setOpen] = useState(false); return (
{/* Dropdown Trigger */}
setOpen(!open)} // Toggle submenu on click > {label} {open ? "▼" : "▶"}
{/* Submenu */} {open && (
{React.Children.map(children, (child) => { if (React.isValidElement(child)) { // Clone the element and pass the `onSelect` prop only if it's expected return React.cloneElement(child as React.ReactElement, { onSelect }); } return child; // Return non-element children as-is })}
)}
); }; // Recursive Function to Render Nested Data const renderNestedData = ( data: Record, onSelect: (selectedLabel: string) => void ) => { return Object.entries(data).map(([key, value]) => { if (typeof value === "object" && !Array.isArray(value)) { // If the value is an object, render it as a nested dropdown return ( {renderNestedData(value, onSelect)} ); } else if (Array.isArray(value)) { // If the value is an array, render each item as a dropdown item return value.map((item, index) => ( onSelect(item)} /> )); } else { // If the value is a simple string, render it as a dropdown item return ( onSelect(value)} /> ); } }); }; // Main Multi-Level Dropdown Component const MultiLevelDropdown = ({ data }: { data: Record }) => { const [open, setOpen] = useState(false); const [selectedLabel, setSelectedLabel] = useState("Dropdown trigger"); const dropdownRef = useRef(null); // Handle outer click to close the dropdown useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if ( dropdownRef.current && !dropdownRef.current.contains(event.target as Node) ) { setOpen(false); } }; document.addEventListener("mousedown", handleClickOutside); return () => { document.removeEventListener("mousedown", handleClickOutside); }; }, []); // Handle selection of an item const handleSelect = (selectedLabel: string) => { setSelectedLabel(selectedLabel); // Update the dropdown trigger text setOpen(false); // Close the dropdown }; return (
{/* Dropdown Trigger Button */} {/* Dropdown Menu */} {open && (
{renderNestedData(data, handleSelect)}
)}
); }; export default MultiLevelDropdown;