import { useState, useRef, useEffect, useCallback } from "react"; import { Popover, TextInput } from "@mantine/core"; import { IBaseProperty, SelectTypeOptions, Choice, } from "@/features/base/types/base.types"; import { choiceColor } from "@/features/base/components/cells/choice-color"; import cellClasses from "@/features/base/styles/cells.module.css"; type CellMultiSelectProps = { value: unknown; property: IBaseProperty; rowId: string; isEditing: boolean; onCommit: (value: unknown) => void; onCancel: () => void; }; export function CellMultiSelect({ value, property, isEditing, onCommit, onCancel, }: CellMultiSelectProps) { const typeOptions = property.typeOptions as SelectTypeOptions | undefined; const choices = typeOptions?.choices ?? []; const selectedIds = Array.isArray(value) ? (value as string[]) : []; const selectedSet = new Set(selectedIds); const selectedChoices = choices.filter((c) => selectedSet.has(c.id)); const [search, setSearch] = useState(""); const searchRef = useRef(null); useEffect(() => { if (isEditing) { setSearch(""); requestAnimationFrame(() => searchRef.current?.focus()); } }, [isEditing]); const filteredChoices = search ? choices.filter((c) => c.name.toLowerCase().includes(search.toLowerCase())) : choices; const handleToggle = useCallback( (choice: Choice) => { const newIds = selectedSet.has(choice.id) ? selectedIds.filter((id) => id !== choice.id) : [...selectedIds, choice.id]; onCommit(newIds); }, [selectedIds, selectedSet, onCommit], ); const handleKeyDown = useCallback( (e: React.KeyboardEvent) => { if (e.key === "Escape") { e.preventDefault(); onCancel(); } }, [onCancel], ); const MAX_VISIBLE = 3; if (isEditing) { return (
setSearch(e.currentTarget.value)} onKeyDown={handleKeyDown} mb={4} />
{filteredChoices.map((choice) => (
handleToggle(choice)} > {choice.name}
))}
); } if (selectedChoices.length === 0) { return ; } return ; } function BadgeList({ choices, maxVisible, }: { choices: Choice[]; maxVisible: number; }) { const visible = choices.slice(0, maxVisible); const overflow = choices.length - maxVisible; return (
{visible.map((choice) => ( {choice.name} ))} {overflow > 0 && ( +{overflow} )}
); }