/
sdds
/
plasma
Обзор
Документация
Войти
/
sdds
/
plasma
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
dev
website/sdds-serv-docs/docs/components/Table.mdx
1 063 строки
52 KB
Dima Shugaev
feat(*): add pagination and loading in Table
22 дек 2025, 12:47
22 дек 2025, 12:47
f4c0842
Код
Авторство
О чём код?
--- id: table title: Table --- import { PropsTable, Description } from '@site/src/components'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; # Table Компонент предназначен для визуализации табличных данных с поддержкой сортировки, фильтрации, редактирования ячеек и других интерактивных возможностей. Он позволяет настраивать внешний вид колонок, включая их ширину, возможность изменения размера, фильтрацию значений и другие функции. Таблица поддерживает выделение строк, а также предоставляет методы для управления состоянием таблицы через API. ## Быстрый старт ```tsx live export function App() { const data = [ { id: '0', country: 'Канада', capital: 'Оттава', population: 38, }, { id: '1', country: 'Бразилия', capital: 'Бразилиа', population: 213, }, { id: '2', country: 'Германия', capital: 'Берлин', population: 83, }, ]; const columns = [ { id: 'country', label: 'Страна', }, { id: 'capital', label: 'Столица', }, { id: 'population', label: 'Население, млн', }, ]; return ( <Table data={data} columns={columns} /> ); } ``` ## Примеры <Tabs> <TabItem value="renderCell" label="Render Cell" default> Свойство `renderCell` нужно для настройки кастомного отображения ячейки. \ Это render-prop, который в параметрах принимает значение ячейки `value`, объект строки, к которой принадлежит ячейка `row` и индекс этой строки `rowIndex`. ```tsx live export function App() { const data = [ { id: '0', country: 'Канада', capital: 'Оттава', population: 38, }, { id: '1', country: 'Бразилия', capital: 'Бразилиа', population: 213, }, { id: '2', country: 'Германия', capital: 'Берлин', population: 83, }, ]; const columns = [ { id: 'country', label: 'Страна', renderCell: (value, { id }) => { return <div style={{ background: 'lightblue' }}>{value}</div> }, }, { id: 'capital', label: 'Столица', renderCell: () => { return <LineSkeleton /> }, }, { id: 'population', label: 'Население, млн', }, ]; return ( <Table data={data} columns={columns} /> ); } ``` </TabItem> <TabItem value="allInOne" label="All in one"> ```tsx live export function App() { const rows = [ { id: '0', country: 'Канада', capital: 'Оттава', population: 38, continent: 'Северная Америка', currency: 'Канадский доллар', officialLanguage: 'Английский, Французский', area: 9984, }, { id: '1', country: 'Бразилия', capital: 'Бразилиа', population: 213, continent: 'Южная Америка', currency: 'Бразильский реал', officialLanguage: 'Португальский', area: 8515, }, { id: '2', country: 'Германия', capital: 'Берлин', population: 83, continent: 'Европа', currency: 'Евро', officialLanguage: 'Немецкий', area: 357, }, { id: '3', country: 'Япония', capital: 'Токио', population: 126, continent: 'Азия', currency: 'Йена', officialLanguage: 'Японский', area: 377, }, { id: '4', country: 'Австралия', capital: 'Канберра', population: 26, continent: 'Океания', currency: 'Австралийский доллар', officialLanguage: 'Английский', area: 7692, }, { id: '5', country: 'Нигерия', capital: 'Абуджа', population: 206, continent: 'Африка', currency: 'Найра', officialLanguage: 'Английский', area: 923, }, { id: '6', country: 'Индия', capital: 'Нью-Дели', population: 1400, continent: 'Азия', currency: 'Индийская рупия', officialLanguage: 'Хинди, Английский', area: 3287, }, { id: '7', country: 'Франция', capital: 'Париж', population: 67, continent: 'Европа', currency: 'Евро', officialLanguage: 'Французский', area: 643, }, { id: '8', country: 'Россия', capital: 'Москва', population: 143, continent: 'Европа/Азия', currency: 'Российский рубль', officialLanguage: 'Русский', area: 17098, }, { id: '9', country: 'Южная Африка', capital: 'Претория', population: 59, continent: 'Африка', currency: 'Южноафриканский ранд', officialLanguage: 'Зулу, Коса, Африкаанс, Английский', area: 1221, }, ]; const filterHelper: (rows: DataRow[], filtered: { id: string; value: string[] }[]) => DataRow[] = (rows, filtered) => { let newData = [...rows]; filtered.forEach(({ id, value }) => { if (value.length === 0) return; switch (id) { case 'population': { newData = newData.filter(({ population }) => { for (const val of value) { switch (val) { case 'small': { if (population < 50) return true; break; } case 'big': { if (population > 100) return true; break; } default: { return false; } } } return false; }); break; } case 'officialLanguage': { newData = newData.filter(({ officialLanguage }) => { for (const val of value) { switch (val) { case 'en': { if (officialLanguage.toLowerCase().includes('английский')) return true; break; } case 'ru': { if (officialLanguage.toLowerCase().includes('русский')) return true; break; } case 'it': { if (officialLanguage.toLowerCase().includes('итальянский')) return true; break; } default: { return false; } } } return false; }); break; } default: { break; } } }); return newData; }; const sortedHelper: (rows: DataRow[], sorted: { id: string; desc: boolean }[]) => DataRow[] = (rows, sorted) => { const newData = [...rows]; if (sorted.length === 0) return newData; const sortColumn = sorted[0].id; const descOrder = sorted[0].desc; newData.sort((a, b) => { if (descOrder) { return b[sortColumn] - a[sortColumn]; } return a[sortColumn] - b[sortColumn]; }); return newData; }; const useBackendImitation: ( rows: DataRow[], ) => { data: DataRow[]; selected: Record<string, boolean>; filtered: any[]; sorted: any[]; onChange: ({ selected, sorted, filtered }) => void; deleteItem: (rowId: string) => void; updateRow: (rowId, columnId, value) => void; clearSelected: () => void; clearFiltered: () => void; clearSorted: () => void; clearAll: () => void; addRow: () => void; selectRow: (rowId: string) => void; } = () => { const [data, setData] = useState(rows); const [selected, setSelected] = useState<Record<string, boolean>>({}); const [filtered, setFiltered] = useState([]); const [sorted, setSorted] = useState([]); console.log(selected); const onChange = ({ selected, sorted, filtered }) => { setSelected(selected); setFiltered(filtered); setSorted(sorted); }; const deleteItem = (rowId: string) => { setData(data.filter(({ id }) => id !== rowId)); }; const updateRow = (rowId, columnId, value) => { setData( data.map((item) => { if (item.id === rowId) { return { ...item, [columnId]: value, }; } return item; }), ); }; const clearSelected = () => setSelected({}); const clearFiltered = () => setFiltered([]); const clearSorted = () => setSorted([]); const clearAll = () => { clearSelected(); clearFiltered(); clearSorted(); }; const addRow = () => { setData([ ...data, { id: (Math.floor(Math.random() * (10000 - 100 + 1)) + 100).toString(), country: '', capital: '', population: null, continent: '', currency: '', officialLanguage: '', area: null, }, ]); }; const selectRow = (rowId: string) => { setSelected({ ...selected, [rowId]: true }); }; return { data: sortedHelper(filterHelper(data, filtered), sorted), selected, filtered, sorted, onChange, deleteItem, updateRow, clearSelected, clearFiltered, clearSorted, clearAll, addRow, selectRow, }; }; const { data, selected, filtered, sorted, onChange, deleteItem, updateRow, clearSelected, clearFiltered, clearSorted, clearAll, addRow, selectRow, } = useBackendImitation(rows); const ref = useRef(null); const columns = [ { id: 'country', label: 'Страна', enableResizing: true, enableEditing: true, }, { id: 'capital', label: 'Столица', enableResizing: true, enableEditing: true, }, { id: 'population', label: 'Население, млн', enableSorting: true, enableResizing: true, filters: [ { value: 'small', label: '< 50' }, { value: 'big', label: '> 100' }, ], enableEditing: true, }, { id: 'continent', label: 'Континент', enableResizing: true, enableEditing: true, }, { id: 'currency', label: 'Валюта', enableResizing: true, enableEditing: true, }, { id: 'officialLanguage', label: 'Язык', enableResizing: true, filters: [ { value: 'en', label: 'Английский' }, { value: 'ru', label: 'Русский' }, { value: 'it', label: 'Итальянский' }, ], enableEditing: true, }, { id: 'area', label: 'Площадь, тыс. км²', enableSorting: true, enableResizing: true, enableEditing: true, }, { id: 'control', label: '', width: 0, renderCell: (_, row) => ( <Dropdown portal={ref} items={[ { value: 'choose', label: 'Выбрать' }, { value: 'delete', label: 'Удалить' }, ]} onItemSelect={({ value }) => { switch (value) { case 'choose': { selectRow(row.id); break; } case 'delete': { deleteItem(row.id); break; } default: { break; } } }} > <IconButton view="clear" size="xs"> <IconEditOutline /> </IconButton> </Dropdown> ), }, ]; return ( <div style={{ display: "block" }}> <ButtonGroup size="xs" isCommonButtonStyles={false}> <Button text="Очистить выбранные" view="warning" size="xs" onClick={clearSelected} /> <Button text="Убрать сортировку" view="warning" size="xs" onClick={clearSorted} /> <Button text="Очистить фильтры" view="warning" size="xs" onClick={clearFiltered} /> <Button text="Очистить все" view="critical" size="xs" onClick={clearAll} /> <Button text="Добавить строку" view="success" size="xs" onClick={addRow} /> </ButtonGroup> <br /> <br /> <div style={{ overflow: "scroll" }}> <Table data={data} columns={columns} onChange={onChange} selected={selected} sorted={sorted} filtered={filtered} onCellUpdate={updateRow} maxHeight="400px" stickyHeader={true} enableSelection={true} ref={ref} /> </div> </div> ); } ``` </TabItem> <TabItem value="pagination" label="Pagination"> Для реализации постраничной навигации воспользуемся другим нашим компонентом - `Pagination`. Его следует поместить в слот `bottomContent`, который находится под таблицей. ```tsx live export function App() { const columnsPagination = [ { id: 'number', label: 'Номер', }, { id: 'country', label: 'Страна', }, { id: 'capital', label: 'Столица', }, { id: 'population', label: 'Население, млн', }, ]; const rowsPagination: any[] = [ { id: '1', number: 1, country: 'Россия', capital: 'Москва', population: 146 }, { id: '2', number: 2, country: 'Франция', capital: 'Париж', population: 67 }, { id: '3', number: 3, country: 'Германия', capital: 'Берлин', population: 83 }, { id: '4', number: 4, country: 'Италия', capital: 'Рим', population: 59 }, { id: '5', number: 5, country: 'Испания', capital: 'Мадрид', population: 47 }, { id: '6', number: 6, country: 'Португалия', capital: 'Лиссабон', population: 10 }, { id: '7', number: 7, country: 'Польша', capital: 'Варшава', population: 38 }, { id: '8', number: 8, country: 'Чехия', capital: 'Прага', population: 10.7 }, { id: '9', number: 9, country: 'Словакия', capital: 'Братислава', population: 5.4 }, { id: '10', number: 10, country: 'Венгрия', capital: 'Будапешт', population: 9.7 }, { id: '11', number: 11, country: 'Австрия', capital: 'Вена', population: 8.9 }, { id: '12', number: 12, country: 'Швейцария', capital: 'Берн', population: 8.6 }, { id: '13', number: 13, country: 'Бельгия', capital: 'Брюссель', population: 11.5 }, { id: '14', number: 14, country: 'Нидерланды', capital: 'Амстердам', population: 17.5 }, { id: '15', number: 15, country: 'Дания', capital: 'Копенгаген', population: 5.8 }, { id: '16', number: 16, country: 'Швеция', capital: 'Стокгольм', population: 10.3 }, { id: '17', number: 17, country: 'Норвегия', capital: 'Осло', population: 5.4 }, { id: '18', number: 18, country: 'Финляндия', capital: 'Хельсинки', population: 5.5 }, { id: '19', number: 19, country: 'Исландия', capital: 'Рейкьявик', population: 0.37 }, { id: '20', number: 20, country: 'Ирландия', capital: 'Дублин', population: 5 }, { id: '21', number: 21, country: 'Великобритания', capital: 'Лондон', population: 67 }, { id: '22', number: 22, country: 'Канада', capital: 'Оттава', population: 38 }, { id: '23', number: 23, country: 'США', capital: 'Вашингтон', population: 331 }, { id: '24', number: 24, country: 'Мексика', capital: 'Мехико', population: 128 }, { id: '25', number: 25, country: 'Бразилия', capital: 'Бразилиа', population: 213 }, { id: '26', number: 26, country: 'Аргентина', capital: 'Буэнос-Айрес', population: 45 }, { id: '27', number: 27, country: 'Чили', capital: 'Сантьяго', population: 19 }, { id: '28', number: 28, country: 'Перу', capital: 'Лима', population: 33 }, { id: '29', number: 29, country: 'Колумбия', capital: 'Богота', population: 51 }, { id: '30', number: 30, country: 'Венесуэла', capital: 'Каракас', population: 28 }, { id: '31', number: 31, country: 'Китай', capital: 'Пекин', population: 1410 }, { id: '32', number: 32, country: 'Япония', capital: 'Токио', population: 125 }, { id: '33', number: 33, country: 'Южная Корея', capital: 'Сеул', population: 52 }, { id: '34', number: 34, country: 'Северная Корея', capital: 'Пхеньян', population: 26 }, { id: '35', number: 35, country: 'Индия', capital: 'Нью-Дели', population: 1400 }, { id: '36', number: 36, country: 'Пакистан', capital: 'Исламабад', population: 230 }, { id: '37', number: 37, country: 'Бангладеш', capital: 'Дакка', population: 170 }, { id: '38', number: 38, country: 'Шри-Ланка', capital: 'Котте', population: 22 }, { id: '39', number: 39, country: 'Непал', capital: 'Катманду', population: 30 }, { id: '40', number: 40, country: 'Таиланд', capital: 'Бангкок', population: 70 }, { id: '41', number: 41, country: 'Вьетнам', capital: 'Ханой', population: 98 }, { id: '42', number: 42, country: 'Малайзия', capital: 'Куала-Лумпур', population: 33 }, { id: '43', number: 43, country: 'Сингапур', capital: 'Сингапур', population: 5.7 }, { id: '44', number: 44, country: 'Индонезия', capital: 'Джакарта', population: 275 }, { id: '45', number: 45, country: 'Филиппины', capital: 'Манила', population: 113 }, { id: '46', number: 46, country: 'Австралия', capital: 'Канберра', population: 26 }, { id: '47', number: 47, country: 'Новая Зеландия', capital: 'Веллингтон', population: 5 }, { id: '48', number: 48, country: 'Египет', capital: 'Каир', population: 110 }, { id: '49', number: 49, country: 'Марокко', capital: 'Рабат', population: 37 }, { id: '50', number: 50, country: 'Алжир', capital: 'Алжир', population: 45 }, { id: '51', number: 51, country: 'ЮАР', capital: 'Претория', population: 60 }, { id: '52', number: 52, country: 'Нигерия', capital: 'Абуджа', population: 227 }, { id: '53', number: 53, country: 'Кения', capital: 'Найроби', population: 55 }, { id: '54', number: 54, country: 'Эфиопия', capital: 'Аддис-Абеба', population: 126 }, { id: '55', number: 55, country: 'Гана', capital: 'Аккра', population: 34 }, { id: '56', number: 56, country: 'Турция', capital: 'Анкара', population: 85 }, { id: '57', number: 57, country: 'Иран', capital: 'Тегеран', population: 89 }, { id: '58', number: 58, country: 'Ирак', capital: 'Багдад', population: 43 }, { id: '59', number: 59, country: 'Саудовская Аравия', capital: 'Эр-Рияд', population: 36 }, { id: '60', number: 60, country: 'ОАЭ', capital: 'Абу-Даби', population: 10 }, { id: '61', number: 61, country: 'Израиль', capital: 'Иерусалим', population: 9.8 }, { id: '62', number: 62, country: 'Иордания', capital: 'Амман', population: 11 }, { id: '63', number: 63, country: 'Греция', capital: 'Афины', population: 10.3 }, { id: '64', number: 64, country: 'Болгария', capital: 'София', population: 6.8 }, { id: '65', number: 65, country: 'Румыния', capital: 'Бухарест', population: 19 }, { id: '66', number: 66, country: 'Хорватия', capital: 'Загреб', population: 4 }, { id: '67', number: 67, country: 'Сербия', capital: 'Белград', population: 6.7 }, { id: '68', number: 68, country: 'Словения', capital: 'Любляна', population: 2.1 }, { id: '69', number: 69, country: 'Литва', capital: 'Вильнюс', population: 2.8 }, { id: '70', number: 70, country: 'Латвия', capital: 'Рига', population: 1.9 }, { id: '71', number: 71, country: 'Эстония', capital: 'Таллин', population: 1.3 }, { id: '72', number: 72, country: 'Беларусь', capital: 'Минск', population: 9.2 }, { id: '73', number: 73, country: 'Украина', capital: 'Киев', population: 36 }, { id: '74', number: 74, country: 'Молдова', capital: 'Кишинёв', population: 2.6 }, { id: '75', number: 75, country: 'Грузия', capital: 'Тбилиси', population: 3.7 }, { id: '76', number: 76, country: 'Армения', capital: 'Ереван', population: 2.8 }, { id: '77', number: 77, country: 'Азербайджан', capital: 'Баку', population: 10.2 }, { id: '78', number: 78, country: 'Казахстан', capital: 'Астана', population: 20 }, { id: '79', number: 79, country: 'Узбекистан', capital: 'Ташкент', population: 36 }, { id: '80', number: 80, country: 'Туркменистан', capital: 'Ашхабад', population: 6 }, { id: '81', number: 81, country: 'Кыргызстан', capital: 'Бишкек', population: 7 }, { id: '82', number: 82, country: 'Таджикистан', capital: 'Душанбе', population: 10 }, { id: '83', number: 83, country: 'Монголия', capital: 'Улан-Батор', population: 3.4 }, { id: '84', number: 84, country: 'Афганистан', capital: 'Кабул', population: 41 }, { id: '85', number: 85, country: 'Сирия', capital: 'Дамаск', population: 22 }, { id: '86', number: 86, country: 'Ливан', capital: 'Бейрут', population: 5.5 }, { id: '87', number: 87, country: 'Катар', capital: 'Доха', population: 3 }, { id: '88', number: 88, country: 'Кувейт', capital: 'Эль-Кувейт', population: 4.5 }, { id: '89', number: 89, country: 'Оман', capital: 'Маскат', population: 4.6 }, { id: '90', number: 90, country: 'Йемен', capital: 'Сана', population: 34 }, { id: '91', number: 91, country: 'Чили', capital: 'Сантьяго', population: 19 }, { id: '92', number: 92, country: 'Парагвай', capital: 'Асунсьон', population: 7.5 }, { id: '93', number: 93, country: 'Уругвай', capital: 'Монтевидео', population: 3.5 }, { id: '94', number: 94, country: 'Боливия', capital: 'Сукре', population: 12 }, { id: '95', number: 95, country: 'Эквадор', capital: 'Кито', population: 18 }, { id: '96', number: 96, country: 'Куба', capital: 'Гавана', population: 11 }, { id: '97', number: 97, country: 'Доминикана', capital: 'Санто-Доминго', population: 11 }, { id: '98', number: 98, country: 'Гаити', capital: 'Порт-о-Пренс', population: 11.5 }, { id: '99', number: 99, country: 'Ямайка', capital: 'Кингстон', population: 3 }, { id: '100', number: 100, country: 'Панама', capital: 'Панама', population: 4.4 }, ]; const [perPage, setPerPage] = useState(10); const [page, setPage] = useState(1); const [data, setData] = useState([]); const handleChange = (newPage: number, newPerPage: number) => { setPage(newPerPage === perPage ? newPage : 1); setPerPage(newPerPage); }; useEffect(() => { setData(rowsPagination.slice((page - 1) * perPage, page * perPage)); }, [page, perPage]); return ( <div style={{ display: "block" }}> <Table data={data} columns={columnsPagination} bottomContent={ <div style={{ padding: '10px', width: '100%', display: 'flex', justifyContent: 'center' }}> <Pagination size="s" value={page} onChange={handleChange} hasQuickJump={false} count={rowsPagination.length} perPage={perPage} perPageList={[10, 20, 30]} /> </div> } /> </div> ); } ``` </TabItem> <TabItem value="infiniteLoading" label="Infinite Loading"> Пример иллюстрирует имитацию бесконечной подгрузки данных в таблицу. Для визуального отображения загрузки поместим `LineSkeleton` в ячейку `loadingSlot`. ```tsx live export function App() { const columnsPagination = [ { id: 'number', label: 'Номер', }, { id: 'country', label: 'Страна', }, { id: 'capital', label: 'Столица', }, { id: 'population', label: 'Население, млн', }, ]; const rowsPagination: any[] = [ { id: '1', number: 1, country: 'Россия', capital: 'Москва', population: 146 }, { id: '2', number: 2, country: 'Франция', capital: 'Париж', population: 67 }, { id: '3', number: 3, country: 'Германия', capital: 'Берлин', population: 83 }, { id: '4', number: 4, country: 'Италия', capital: 'Рим', population: 59 }, { id: '5', number: 5, country: 'Испания', capital: 'Мадрид', population: 47 }, { id: '6', number: 6, country: 'Португалия', capital: 'Лиссабон', population: 10 }, { id: '7', number: 7, country: 'Польша', capital: 'Варшава', population: 38 }, { id: '8', number: 8, country: 'Чехия', capital: 'Прага', population: 10.7 }, { id: '9', number: 9, country: 'Словакия', capital: 'Братислава', population: 5.4 }, { id: '10', number: 10, country: 'Венгрия', capital: 'Будапешт', population: 9.7 }, { id: '11', number: 11, country: 'Австрия', capital: 'Вена', population: 8.9 }, { id: '12', number: 12, country: 'Швейцария', capital: 'Берн', population: 8.6 }, { id: '13', number: 13, country: 'Бельгия', capital: 'Брюссель', population: 11.5 }, { id: '14', number: 14, country: 'Нидерланды', capital: 'Амстердам', population: 17.5 }, { id: '15', number: 15, country: 'Дания', capital: 'Копенгаген', population: 5.8 }, { id: '16', number: 16, country: 'Швеция', capital: 'Стокгольм', population: 10.3 }, { id: '17', number: 17, country: 'Норвегия', capital: 'Осло', population: 5.4 }, { id: '18', number: 18, country: 'Финляндия', capital: 'Хельсинки', population: 5.5 }, { id: '19', number: 19, country: 'Исландия', capital: 'Рейкьявик', population: 0.37 }, { id: '20', number: 20, country: 'Ирландия', capital: 'Дублин', population: 5 }, { id: '21', number: 21, country: 'Великобритания', capital: 'Лондон', population: 67 }, { id: '22', number: 22, country: 'Канада', capital: 'Оттава', population: 38 }, { id: '23', number: 23, country: 'США', capital: 'Вашингтон', population: 331 }, { id: '24', number: 24, country: 'Мексика', capital: 'Мехико', population: 128 }, { id: '25', number: 25, country: 'Бразилия', capital: 'Бразилиа', population: 213 }, { id: '26', number: 26, country: 'Аргентина', capital: 'Буэнос-Айрес', population: 45 }, { id: '27', number: 27, country: 'Чили', capital: 'Сантьяго', population: 19 }, { id: '28', number: 28, country: 'Перу', capital: 'Лима', population: 33 }, { id: '29', number: 29, country: 'Колумбия', capital: 'Богота', population: 51 }, { id: '30', number: 30, country: 'Венесуэла', capital: 'Каракас', population: 28 }, { id: '31', number: 31, country: 'Китай', capital: 'Пекин', population: 1410 }, { id: '32', number: 32, country: 'Япония', capital: 'Токио', population: 125 }, { id: '33', number: 33, country: 'Южная Корея', capital: 'Сеул', population: 52 }, { id: '34', number: 34, country: 'Северная Корея', capital: 'Пхеньян', population: 26 }, { id: '35', number: 35, country: 'Индия', capital: 'Нью-Дели', population: 1400 }, { id: '36', number: 36, country: 'Пакистан', capital: 'Исламабад', population: 230 }, { id: '37', number: 37, country: 'Бангладеш', capital: 'Дакка', population: 170 }, { id: '38', number: 38, country: 'Шри-Ланка', capital: 'Котте', population: 22 }, { id: '39', number: 39, country: 'Непал', capital: 'Катманду', population: 30 }, { id: '40', number: 40, country: 'Таиланд', capital: 'Бангкок', population: 70 }, { id: '41', number: 41, country: 'Вьетнам', capital: 'Ханой', population: 98 }, { id: '42', number: 42, country: 'Малайзия', capital: 'Куала-Лумпур', population: 33 }, { id: '43', number: 43, country: 'Сингапур', capital: 'Сингапур', population: 5.7 }, { id: '44', number: 44, country: 'Индонезия', capital: 'Джакарта', population: 275 }, { id: '45', number: 45, country: 'Филиппины', capital: 'Манила', population: 113 }, { id: '46', number: 46, country: 'Австралия', capital: 'Канберра', population: 26 }, { id: '47', number: 47, country: 'Новая Зеландия', capital: 'Веллингтон', population: 5 }, { id: '48', number: 48, country: 'Египет', capital: 'Каир', population: 110 }, { id: '49', number: 49, country: 'Марокко', capital: 'Рабат', population: 37 }, { id: '50', number: 50, country: 'Алжир', capital: 'Алжир', population: 45 }, { id: '51', number: 51, country: 'ЮАР', capital: 'Претория', population: 60 }, { id: '52', number: 52, country: 'Нигерия', capital: 'Абуджа', population: 227 }, { id: '53', number: 53, country: 'Кения', capital: 'Найроби', population: 55 }, { id: '54', number: 54, country: 'Эфиопия', capital: 'Аддис-Абеба', population: 126 }, { id: '55', number: 55, country: 'Гана', capital: 'Аккра', population: 34 }, { id: '56', number: 56, country: 'Турция', capital: 'Анкара', population: 85 }, { id: '57', number: 57, country: 'Иран', capital: 'Тегеран', population: 89 }, { id: '58', number: 58, country: 'Ирак', capital: 'Багдад', population: 43 }, { id: '59', number: 59, country: 'Саудовская Аравия', capital: 'Эр-Рияд', population: 36 }, { id: '60', number: 60, country: 'ОАЭ', capital: 'Абу-Даби', population: 10 }, { id: '61', number: 61, country: 'Израиль', capital: 'Иерусалим', population: 9.8 }, { id: '62', number: 62, country: 'Иордания', capital: 'Амман', population: 11 }, { id: '63', number: 63, country: 'Греция', capital: 'Афины', population: 10.3 }, { id: '64', number: 64, country: 'Болгария', capital: 'София', population: 6.8 }, { id: '65', number: 65, country: 'Румыния', capital: 'Бухарест', population: 19 }, { id: '66', number: 66, country: 'Хорватия', capital: 'Загреб', population: 4 }, { id: '67', number: 67, country: 'Сербия', capital: 'Белград', population: 6.7 }, { id: '68', number: 68, country: 'Словения', capital: 'Любляна', population: 2.1 }, { id: '69', number: 69, country: 'Литва', capital: 'Вильнюс', population: 2.8 }, { id: '70', number: 70, country: 'Латвия', capital: 'Рига', population: 1.9 }, { id: '71', number: 71, country: 'Эстония', capital: 'Таллин', population: 1.3 }, { id: '72', number: 72, country: 'Беларусь', capital: 'Минск', population: 9.2 }, { id: '73', number: 73, country: 'Украина', capital: 'Киев', population: 36 }, { id: '74', number: 74, country: 'Молдова', capital: 'Кишинёв', population: 2.6 }, { id: '75', number: 75, country: 'Грузия', capital: 'Тбилиси', population: 3.7 }, { id: '76', number: 76, country: 'Армения', capital: 'Ереван', population: 2.8 }, { id: '77', number: 77, country: 'Азербайджан', capital: 'Баку', population: 10.2 }, { id: '78', number: 78, country: 'Казахстан', capital: 'Астана', population: 20 }, { id: '79', number: 79, country: 'Узбекистан', capital: 'Ташкент', population: 36 }, { id: '80', number: 80, country: 'Туркменистан', capital: 'Ашхабад', population: 6 }, { id: '81', number: 81, country: 'Кыргызстан', capital: 'Бишкек', population: 7 }, { id: '82', number: 82, country: 'Таджикистан', capital: 'Душанбе', population: 10 }, { id: '83', number: 83, country: 'Монголия', capital: 'Улан-Батор', population: 3.4 }, { id: '84', number: 84, country: 'Афганистан', capital: 'Кабул', population: 41 }, { id: '85', number: 85, country: 'Сирия', capital: 'Дамаск', population: 22 }, { id: '86', number: 86, country: 'Ливан', capital: 'Бейрут', population: 5.5 }, { id: '87', number: 87, country: 'Катар', capital: 'Доха', population: 3 }, { id: '88', number: 88, country: 'Кувейт', capital: 'Эль-Кувейт', population: 4.5 }, { id: '89', number: 89, country: 'Оман', capital: 'Маскат', population: 4.6 }, { id: '90', number: 90, country: 'Йемен', capital: 'Сана', population: 34 }, { id: '91', number: 91, country: 'Чили', capital: 'Сантьяго', population: 19 }, { id: '92', number: 92, country: 'Парагвай', capital: 'Асунсьон', population: 7.5 }, { id: '93', number: 93, country: 'Уругвай', capital: 'Монтевидео', population: 3.5 }, { id: '94', number: 94, country: 'Боливия', capital: 'Сукре', population: 12 }, { id: '95', number: 95, country: 'Эквадор', capital: 'Кито', population: 18 }, { id: '96', number: 96, country: 'Куба', capital: 'Гавана', population: 11 }, { id: '97', number: 97, country: 'Доминикана', capital: 'Санто-Доминго', population: 11 }, { id: '98', number: 98, country: 'Гаити', capital: 'Порт-о-Пренс', population: 11.5 }, { id: '99', number: 99, country: 'Ямайка', capital: 'Кингстон', population: 3 }, { id: '100', number: 100, country: 'Панама', capital: 'Панама', population: 4.4 }, ]; const [data, setData] = useState([...rowsPagination.slice(0, 10)]); const [loading, setLoading] = useState(false); const itemsPerLoad = 10; const handleScroll = (e: React.UIEvent<HTMLElement>) => { const element = e.currentTarget; const { scrollTop } = element; const { clientHeight } = element; const { scrollHeight } = element; if (data.length < 100 && loading === false && scrollTop + clientHeight >= scrollHeight - 20) { setLoading(true); setTimeout(() => { setData([...data, ...rowsPagination.slice(data.length, data.length + itemsPerLoad)]); setLoading(false); }, 1000); } }; return ( <div style={{ display: "block" }}> <Table data={data} columns={columnsPagination} loadingSlot={ loading ? ( <div style={{ padding: '10px' }}> <LineSkeleton /> </div> ) : null } onScroll={handleScroll} maxHeight="400px" /> </div> ); } ``` </TabItem> </Tabs> ## Сценарии использования ### Выделение строки по нажатию Для осуществления этой цели существует свойство `setRowProps`. Это функция, которая принимает объект строки `row` и возвращает объект атрибутов, которые будут прокинуты в тег `<tr>`. ```tsx live export function App() { const data = [ { id: '0', country: 'Канада', capital: 'Оттава', population: 38, }, { id: '1', country: 'Бразилия', capital: 'Бразилиа', population: 213, }, { id: '2', country: 'Германия', capital: 'Берлин', population: 83, }, ]; const columns = [ { id: 'country', label: 'Страна', }, { id: 'capital', label: 'Столица', }, { id: 'population', label: 'Население, млн', }, ]; const [rowHighlighted, setRowHighlighted] = React.useState(null); const setRowProps = (row: any) => { return { onClick: () => setRowHighlighted(row.id), style: rowHighlighted === row.id ? { background: 'lightgray' } : undefined }; }; return ( <Table data={data} columns={columns} setRowProps={setRowProps} /> ); } ``` ### Выделение строки по наведению Это можно осуществить или с помощью css, либо использовать свойство `setRowProps` для более гибкой настройки и сложных сценариев. ```tsx live export function App() { const data = [ { id: '0', country: 'Канада', capital: 'Оттава', population: 38, }, { id: '1', country: 'Бразилия', capital: 'Бразилиа', population: 213, }, { id: '2', country: 'Германия', capital: 'Берлин', population: 83, }, ]; const columns = [ { id: 'country', label: 'Страна', }, { id: 'capital', label: 'Столица', }, { id: 'population', label: 'Население, млн', }, ]; const Wrapper = styled.div` & tr:hover { background: lightgray; } ` return ( <Wrapper> <Table data={data} columns={columns} /> </Wrapper> ); } ``` ## API <PropsTable name="Table" /> Обязательными полями являются `data` и `columns`. Формат следующий: ```tsx export type TableRowData = { /** * Уникальный идентификатор строки */ id: string; /** * Неограниченный список пар ключ:значение, составляющих контент таблицы. * Должен совпадать с ключами из TableColumnData */ [key: string]: string | number | object; }; export type TableColumnData = { /** * Уникальный идентификатор колонки */ id: string; /** * Label колонки */ label: string; /** * Ширина колонки */ width?: number; /** * Включение сортировки */ enableSorting?: boolean; /** * Включение ресайза */ enableResizing?: boolean; /** * Включение изменения ячеек */ enableEditing?: boolean; /** * Набор опций для фильтрации строк */ filters?: { value: string; label: string }[]; /** * Кастомный обработчик для фильтрации строк */ filterFn?: (filteredValue: string, cellValue: unknown) => boolean; /** * Рендер-пропс для ячейки */ renderCell?: (value: unknown, row: TableRowData, rowIndex: number) => ReactNode; /** * Сеттер свойств для ячейки */ setCellProps?: (record: TableRowData, cellId: string) => HTMLAttributes<any> & TdHTMLAttributes<any>; }; ```