import { useState, useMemo, useEffect } from 'react'; import { Box, Checkbox, Typography, TextField, Popover, InputAdornment, } from '@mui/material'; import { ExpandMore, ChevronRight, ArrowDropDown } from '@mui/icons-material'; import { SimpleTreeView, TreeItem } from '@mui/x-tree-view'; import { CheckBoxOutlineBlank, CheckBox, IndeterminateCheckBox, } from '@mui/icons-material'; const CollapsibleTree = ({ columnTree, placeholder = 'Скрыть столбцы', placeholderSelect = 'Скрыто столбцов: ', selectedIds = [], onSelectNode, }) => { const [expandedItems, setExpandedItems] = useState([]); const [anchorEl, setAnchorEl] = useState(null); const [selectedNodes, setSelectedNodes] = useState([]); useEffect(() => { setSelectedNodes(selectedIds); }, [selectedIds]); const handleExpandedItemsChange = (event, itemIds) => { setExpandedItems(itemIds); }; const handleSelectAll = (isSelected) => { for (const col of columnTree) { onSelectNode?.(col, !isSelected); } }; const getChildrenIds = (node) => { const getLeafColumn = (col) => { const hasColumns = col.columns && Array.isArray(col.columns); if (!hasColumns || col.columns.length === 0) { return [col]; } const allChildrenAreLeaves = col.columns.every( child => !child.columns || !Array.isArray(child.columns) || child.columns.length === 0 ); if (allChildrenAreLeaves) { return col.columns; } return col.columns.flatMap((childCol) => getLeafColumn(childCol)); }; const leafColumns = getLeafColumn(node); return leafColumns.map((c) => c.id || c.accessorKey); }; const isNodeChecked = (node) => { const childrenIds = getChildrenIds(node); const selectedChildren = childrenIds.filter((id) => selectedNodes.includes(id) , ); if (selectedChildren.length === 0) return false; if (selectedChildren.length === childrenIds.length) return true; return 'indeterminate'; }; const handleNodeCheck = (node, isSelected) => { onSelectNode?.(node, !isSelected); }; const getId = (column) => { const getFullColumnPath = (column) => { const ancestors = []; let current = column; while (current) { ancestors.unshift(current.id || current.accessorKey); current = current.parent; } return ancestors; }; return getFullColumnPath(column).join('_'); }; const renderTree = (nodes) => { if (!nodes || nodes.length === 0) return null; return nodes.map((node) => { const checkStatus = isNodeChecked(node); return ( e.stopPropagation()} checked={checkStatus === true} indeterminate={checkStatus === 'indeterminate'} onChange={() => handleNodeCheck( node, checkStatus === 'indeterminate' ? true : !checkStatus, ) } icon={} checkedIcon={} indeterminateIcon={} /> {node.columnDef?.header || node.name || node.header || 'Без названия'} } > {node.columns && node.columns.length > 0 && renderTree(node.columns)} ); }); }; const treeElements = useMemo(() => { return columnTree ? renderTree(columnTree) : null; }, [columnTree, selectedNodes]); const handleOpen = (event) => { setAnchorEl(event.currentTarget); }; const handleClose = () => { setAnchorEl(null); }; const selectedCount = selectedNodes.length - 1; //1 колонка всегда скрыта const isAllSelected = () => { if (!columnTree) return false; let isSelect = true; for (const col of columnTree) { const isChecked = isNodeChecked(col); isSelect = isChecked === 'indeterminate' ? false : isChecked && isSelect; } return isSelect; }; const open = Boolean(anchorEl); const id = open ? 'tree-popover' : undefined; const getDisplayValue = () => { if (selectedCount === 0) { return ''; } return `${placeholderSelect} ${selectedCount}`; }; return ( <> ), }, }} sx={{ cursor: 'pointer', height: '2.5rem', padding: 0, '& .MuiInputBase-root': { cursor: 'pointer', height: '2.5rem', }, '& input': { cursor: 'pointer', }, }} /> 0 && !isAllSelected()} onChange={(e) => handleSelectAll(e.target.checked)} icon={} checkedIcon={} indeterminateIcon={} /> Выбрать все {treeElements} ); }; export default CollapsibleTree;