import clsx from 'clsx'; import { AnimatePresence, motion } from 'framer-motion'; import { useCallback, useLayoutEffect, useMemo, useState } from 'react'; import { animateSideAppear } from '@/styling/animations'; import { globals } from '@/utils/constants'; import { IconDropArrow, IconPageRight } from '../Icons'; import { CProps } from '../props'; import MiniButton from './MiniButton'; import Overlay from './Overlay'; interface SelectTreeProps extends CProps.Styling { items: ItemType[]; value: ItemType; setValue: (newItem: ItemType) => void; getParent: (item: ItemType) => ItemType; getLabel: (item: ItemType) => string; getDescription: (item: ItemType) => string; prefix: string; } function SelectTree({ items, value, getParent, getLabel, getDescription, setValue, prefix, ...restProps }: SelectTreeProps) { const foldable = useMemo( () => new Set(items.filter(item => getParent(item) !== item).map(item => getParent(item))), [items, getParent] ); const [folded, setFolded] = useState(items); useLayoutEffect(() => { setFolded(items.filter(item => getParent(value) !== item && getParent(getParent(value)) !== item)); }, [value, getParent, items]); const onFoldItem = useCallback( (target: ItemType, showChildren: boolean) => { setFolded(prev => items.filter(item => { if (item === target) { return !showChildren; } if (!showChildren && (getParent(item) === target || getParent(getParent(item)) === target)) { return true; } else { return prev.includes(item); } }) ); }, [items, getParent] ); const handleClickFold = useCallback( (event: CProps.EventMouse, target: ItemType, showChildren: boolean) => { event.preventDefault(); event.stopPropagation(); onFoldItem(target, showChildren); }, [onFoldItem] ); const handleSetValue = useCallback( (event: CProps.EventMouse, target: ItemType) => { event.preventDefault(); event.stopPropagation(); setValue(target); }, [setValue] ); return (
{items.map((item, index) => getParent(item) === item || !folded.includes(getParent(item)) ? ( handleSetValue(event, item)} initial={{ ...animateSideAppear.initial }} animate={{ ...animateSideAppear.animate }} exit={{ ...animateSideAppear.exit }} > {foldable.has(item) ? ( : } onClick={event => handleClickFold(event, item, folded.includes(item))} /> ) : null} {getParent(item) === item ? getLabel(item) : `- ${getLabel(item).toLowerCase()}`} ) : null )}
); } export default SelectTree;