```tsx import React from 'react'; import { Tree } from '@salutejs/plasma-web'; export function App() { const treeData = [ { title: 'Основной каталог', key: '0-0', children: [ { title: 'Документы', key: '0-0-0', children: [ { title: 'Отчёты', key: '0-0-0-0', disabled: true, }, { title: 'Проекты', key: '0-0-0-1', children: [ { title: 'Проект Альфа', key: '0-0-0-1-0', }, { title: 'Проект Бета', key: '0-0-0-1-1', }, ], }, { title: 'Категории', key: '0-0-0-2', children: [ { title: 'Категория Гамма', key: '0-0-0-2-0', }, { title: 'Категория Дельта', key: '0-0-0-2-1', }, ], }, ], }, { title: 'Медиа', key: '0-0-1', children: [ { title: 'Фотографии', key: '0-0-1-0', }, ], }, ], }, { title: 'Корзина', key: '0-1', children: [ { title: 'Удалённые файлы', key: '0-1-0', }, ], }, ]; return (
); } ``` ```tsx import React from 'react'; import { Tree } from '@salutejs/plasma-web'; export function App() { const treeData = [ { title: 'Основной каталог', key: '0-0', children: [ { title: 'Документы', key: '0-0-0', children: [ { title: 'Отчёты', key: '0-0-0-0', disabled: true, }, { title: 'Проекты', key: '0-0-0-1', children: [ { title: 'Проект Альфа', key: '0-0-0-1-0', }, { title: 'Проект Бета', key: '0-0-0-1-1', }, ], }, { title: 'Категории', key: '0-0-0-2', children: [ { title: 'Категория Гамма', key: '0-0-0-2-0', }, { title: 'Категория Дельта', key: '0-0-0-2-1', }, ], }, ], }, { title: 'Медиа', key: '0-0-1', children: [ { title: 'Фотографии', key: '0-0-1-0', }, ], }, ], }, { title: 'Корзина', key: '0-1', children: [ { title: 'Удалённые файлы', key: '0-1-0', }, ], }, ]; return (
); } ``` ```tsx import React from 'react'; import { Tree } from '@salutejs/plasma-web'; export function App() { const treeData = [ { title: 'Основной каталог', key: '0-0', children: [ { title: 'Документы', key: '0-0-0', children: [ { title: 'Отчёты', key: '0-0-0-0', disabled: true, }, { title: 'Проекты', key: '0-0-0-1', children: [ { title: 'Проект Альфа', key: '0-0-0-1-0', }, { title: 'Проект Бета', key: '0-0-0-1-1', }, ], }, { title: 'Категории', key: '0-0-0-2', children: [ { title: 'Категория Гамма', key: '0-0-0-2-0', }, { title: 'Категория Дельта', key: '0-0-0-2-1', }, ], }, ], }, { title: 'Медиа', key: '0-0-1', children: [ { title: 'Фотографии', key: '0-0-1-0', }, ], }, ], }, { title: 'Корзина', key: '0-1', children: [ { title: 'Удалённые файлы', key: '0-1-0', }, ], }, ]; const [expanded, setExpanded] = React.useState([]); const [checked, setChecked] = React.useState([]); const [selected, setSelected] = React.useState([]); return (
); } ``` ```tsx import React from 'react'; import { Tree } from '@salutejs/plasma-web'; export function App() { const treeData = [ { title: 'Основной каталог', key: '0-0', children: [ { title: 'Документы', key: '0-0-0', children: [ { title: 'Отчёты', key: '0-0-0-0', disabled: true, }, { title: 'Проекты', key: '0-0-0-1', children: [ { title: 'Проект Альфа', key: '0-0-0-1-0', }, { title: 'Проект Бета', key: '0-0-0-1-1', }, ], }, { title: 'Категории', key: '0-0-0-2', children: [ { title: 'Категория Гамма', key: '0-0-0-2-0', }, { title: 'Категория Дельта', key: '0-0-0-2-1', }, ], }, ], }, { title: 'Медиа', key: '0-0-1', children: [ { title: 'Фотографии', key: '0-0-1-0', }, ], }, ], }, { title: 'Корзина', key: '0-1', children: [ { title: 'Удалённые файлы', key: '0-1-0', }, ], }, ]; return (
); } ``` ```tsx import React from 'react'; import { Tree } from '@salutejs/plasma-web'; export function App() { const treeData = [ { title: 'Основной каталог', key: '0-0', children: [ { title: 'Документы', key: '0-0-0', children: [ { title: 'Отчёты', key: '0-0-0-0', disabled: true, }, { title: 'Проекты', key: '0-0-0-1', children: [ { title: 'Проект Альфа', key: '0-0-0-1-0', }, { title: 'Проект Бета', key: '0-0-0-1-1', }, ], }, { title: 'Категории', key: '0-0-0-2', children: [ { title: 'Категория Гамма', key: '0-0-0-2-0', }, { title: 'Категория Дельта', key: '0-0-0-2-1', }, ], }, ], }, { title: 'Медиа', key: '0-0-1', children: [ { title: 'Фотографии', key: '0-0-1-0', }, ], }, ], }, { title: 'Корзина', key: '0-1', children: [ { title: 'Удалённые файлы', key: '0-1-0', }, ], }, ]; const [expanded, setExpanded] = React.useState([]); const [checked, setChecked] = React.useState([]); const [selected, setSelected] = React.useState([]); return (
); } ``` Для включения виртуализации обязательными являются 2 свойства: `height` и `itemHeight` . Также есть опциональный флаг для явного отключения/включения виртуализации: `virtual` . ```tsx import React from 'react'; import { Tree } from '@salutejs/plasma-web'; export function App() { return (
({ key: i.toString(), title: i.toString() }))} height={400} itemHeight={48} />
); } ``` ## Drag'n'Drop Для включения режима Drag and Drop нужно включить свойство `draggable` . Также имеется ряд обработчиков, однако наиболее важным из них является `onDrop` . Для более индивидуальной настройки логики работы механизма Drag'n'Drop данный обработчик настраивается на стороне клиента. Примеры ниже будут более наглядными: Данный пример базовый, покрывающий наиболее распространенные сценарии использования. Также присутствует возможность создавать из крайних элементов группы, вкладывая в них другие элементы. ```tsx import React from 'react'; import { Tree, TreeProps, TreeItem } from '@salutejs/plasma-web'; export function App() { const treeData = [ { title: 'Основной каталог', key: '0-0', children: [ { title: 'Документы', key: '0-0-0', children: [ { title: 'Отчёты', key: '0-0-0-0', disabled: true, }, { title: 'Проекты', key: '0-0-0-1', children: [ { title: 'Проект Альфа', key: '0-0-0-1-0', }, { title: 'Проект Бета', key: '0-0-0-1-1', }, ], }, { title: 'Категории', key: '0-0-0-2', children: [ { title: 'Категория Гамма', key: '0-0-0-2-0', }, { title: 'Категория Дельта', key: '0-0-0-2-1', }, ], }, ], }, { title: 'Медиа', key: '0-0-1', children: [ { title: 'Фотографии', key: '0-0-1-0', }, ], }, ], }, { title: 'Корзина', key: '0-1', children: [ { title: 'Удалённые файлы', key: '0-1-0', }, ], }, ]; const [items, setItems] = React.useState(treeData); const onDrop: TreeProps['onDrop'] = (info) => { const dropKey = info.node.key; const dragKey = info.dragNode.key; const dropPos = info.node.pos.split('-'); const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]); // Функция-хелпер для прохода по дереву элементов const loop = ( data: TreeItem[], key: React.Key, callback: (node: TreeItem, i: number, data: TreeItem[]) => void, ) => { data.forEach((item, index, arr) => { if (item.key === key) { callback(item, index, arr); return; } if (item.children) { loop(item.children, key, callback); } }); }; const data = [...items]; // Ищем draggable-элемент let dragObj: TreeItem; loop(data, dragKey, (item, index, arr) => { arr.splice(index, 1); dragObj = item; }); if (dropPosition === 0) { // Вставляем элемент внутрь target-элемента loop(data, dropKey, (item) => { item.children = item.children || []; item.children.unshift(dragObj); }); } else { // Вставляем элемент вначале или после target-элемента let ar: TreeItem[] = []; let i: number; loop(data, dropKey, (_item, index, arr) => { ar = arr; i = index; }); if (dropPosition === -1) { ar.splice(i!, 0, dragObj!); } else { ar.splice(i! + 1, 0, dragObj!); } } setItems(data); }; const allowDrop: TreeProps['allowDrop'] = (info) => { return !info.dropNode.disabled; }; return (
); }; ``` ## Drag'n'Drop Для включения режима Drag and Drop нужно включить свойство `draggable` . Также имеется ряд обработчиков, однако наиболее важным из них является `onDrop` . Для более индивидуальной настройки логики работы механизма Drag'n'Drop данный обработчик настраивается на стороне клиента. Примеры ниже будут более наглядными: Данный пример базовый, покрывающий наиболее распространенные сценарии использования. Также присутствует возможность создавать из крайних элементов группы, вкладывая в них другие элементы. ```tsx import React from 'react'; import { Tree, TreeProps, TreeItem } from '@salutejs/plasma-web'; export function App() { const treeData = [ { title: 'Основной каталог', key: '0-0', children: [ { title: 'Документы', key: '0-0-0', children: [ { title: 'Отчёты', key: '0-0-0-0', disabled: true, }, { title: 'Проекты', key: '0-0-0-1', children: [ { title: 'Проект Альфа', key: '0-0-0-1-0', }, { title: 'Проект Бета', key: '0-0-0-1-1', }, ], }, { title: 'Категории', key: '0-0-0-2', children: [ { title: 'Категория Гамма', key: '0-0-0-2-0', }, { title: 'Категория Дельта', key: '0-0-0-2-1', }, ], }, ], }, { title: 'Медиа', key: '0-0-1', children: [ { title: 'Фотографии', key: '0-0-1-0', }, ], }, ], }, { title: 'Корзина', key: '0-1', children: [ { title: 'Удалённые файлы', key: '0-1-0', }, ], }, ]; const [items, setItems] = React.useState(treeData); const onDrop: TreeProps['onDrop'] = (info) => { const dropKey = info.node.key; const dragKey = info.dragNode.key; const dropPos = info.node.pos.split('-'); const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]); // Функция-хелпер для прохода по дереву элементов const loop = ( data: TreeItem[], key: React.Key, callback: (node: TreeItem, i: number, data: TreeItem[]) => void, ) => { data.forEach((item, index, arr) => { if (item.key === key) { callback(item, index, arr); return; } if (item.children) { loop(item.children, key, callback); } }); }; const data = [...items]; // Ищем draggable-элемент let dragObj: TreeItem; loop(data, dragKey, (item, index, arr) => { arr.splice(index, 1); dragObj = item; }); if (dropPosition === 0) { // Вставляем элемент внутрь target-элемента loop(data, dropKey, (item) => { item.children = item.children || []; item.children.unshift(dragObj); }); } else { // Вставляем элемент вначале или после target-элемента let ar: TreeItem[] = []; let i: number; loop(data, dropKey, (_item, index, arr) => { ar = arr; i = index; }); if (dropPosition === -1) { ar.splice(i!, 0, dragObj!); } else { ar.splice(i! + 1, 0, dragObj!); } } setItems(data); }; const allowDrop: TreeProps['allowDrop'] = (info) => { return !info.dropNode.disabled; }; return (
); }; ``` Если нужно запретить создавать группы из крайних элементов, нужно воспользоваться свойством `allowDrop` . ```tsx import React from 'react'; import { Tree, TreeProps, TreeItem } from '@salutejs/plasma-web'; export function App() { const treeData = [ { title: 'Основной каталог', key: '0-0', children: [ { title: 'Документы', key: '0-0-0', children: [ { title: 'Отчёты', key: '0-0-0-0', disabled: true, }, { title: 'Проекты', key: '0-0-0-1', children: [ { title: 'Проект Альфа', key: '0-0-0-1-0', }, { title: 'Проект Бета', key: '0-0-0-1-1', }, ], }, { title: 'Категории', key: '0-0-0-2', children: [ { title: 'Категория Гамма', key: '0-0-0-2-0', }, { title: 'Категория Дельта', key: '0-0-0-2-1', }, ], }, ], }, { title: 'Медиа', key: '0-0-1', children: [ { title: 'Фотографии', key: '0-0-1-0', }, ], }, ], }, { title: 'Корзина', key: '0-1', children: [ { title: 'Удалённые файлы', key: '0-1-0', }, ], }, ]; const [items, setItems] = React.useState(treeData); const onDrop: TreeProps['onDrop'] = (info) => { const dropKey = info.node.key; const dragKey = info.dragNode.key; const dropPos = info.node.pos.split('-'); const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]); // Функция-хелпер для прохода по дереву элементов const loop = ( data: TreeItem[], key: React.Key, callback: (node: TreeItem, i: number, data: TreeItem[]) => void, ) => { data.forEach((item, index, arr) => { if (item.key === key) { callback(item, index, arr); return; } if (item.children) { loop(item.children, key, callback); } }); }; const data = [...items]; // Ищем draggable-элемент let dragObj: TreeItem; loop(data, dragKey, (item, index, arr) => { arr.splice(index, 1); dragObj = item; }); if (dropPosition === 0) { // Вставляем элемент внутрь target-элемента loop(data, dropKey, (item) => { item.children = item.children || []; item.children.unshift(dragObj); }); } else { // Вставляем элемент вначале или после target-элемента let ar: TreeItem[] = []; let i: number; loop(data, dropKey, (_item, index, arr) => { ar = arr; i = index; }); if (dropPosition === -1) { ar.splice(i!, 0, dragObj!); } else { ar.splice(i! + 1, 0, dragObj!); } } setItems(data); }; const allowDrop: TreeProps['allowDrop'] = (info) => { if (info.dropNode.disabled || !info.dropNode.children && info.dropPosition === 0) { return false; } return true; }; return (
); }; ``` ## Пример с autoExpandParent Иногда может возникнуть необходимость раскрыть дерево до нужного ключа пробросив только его в поле `expanded` . В стандартном сценарии ничего не произойдет, т.к. вышестоящие уровни будут закрыты. Поэтому данное поведение можно реализовать с помощью свойства `autoExpandParent` . ```tsx import React from 'react'; import { Tree, Button } from '@salutejs/plasma-web'; export function App() { const [expanded, setExpanded] = React.useState([]); const [autoExpandParent, setAutoExpandParent] = React.useState(true); const treeData = [ { title: 'Основной каталог', key: '0-0', children: [ { title: 'Документы', key: '0-0-0', children: [ { title: 'Отчёты', key: '0-0-0-0', disabled: true, }, { title: 'Проекты', key: '0-0-0-1', children: [ { title: 'Проект Альфа', key: '0-0-0-1-0', }, { title: 'Проект Бета', key: '0-0-0-1-1', }, ], }, { title: 'Категории', key: '0-0-0-2', children: [ { title: 'Категория Гамма', key: '0-0-0-2-0', }, { title: 'Категория Дельта', key: '0-0-0-2-1', }, ], }, ], }, { title: 'Медиа', key: '0-0-1', children: [ { title: 'Фотографии', key: '0-0-1-0', }, ], }, ], }, { title: 'Корзина', key: '0-1', children: [ { title: 'Удалённые файлы', key: '0-1-0', }, ], }, ]; const handleExpand = (expandedValue) => { setAutoExpandParent(false); setExpanded(expandedValue); }; return (
); } ```