diff --git a/app/src/docs/_examples/tables/LazyTable.example.tsx b/app/src/docs/_examples/tables/LazyTable.example.tsx
index 49122d9725..9b25fad479 100644
--- a/app/src/docs/_examples/tables/LazyTable.example.tsx
+++ b/app/src/docs/_examples/tables/LazyTable.example.tsx
@@ -1,6 +1,16 @@
import React, { ReactNode, useCallback, useMemo, useState } from 'react';
import { DataSourceState, DataColumnProps, useUuiContext, useLazyDataSource, DropdownBodyProps } from '@epam/uui-core';
-import { Dropdown, DropdownMenuButton, DropdownMenuSplitter, DropdownMenuBody, Text, DataTable, Panel, IconButton } from '@epam/uui';
+import {
+ Dropdown,
+ DropdownMenuButton,
+ DropdownMenuSplitter,
+ DropdownMenuBody,
+ Text,
+ DataTable,
+ Panel,
+ IconButton,
+ DataTableCell, TextInput,
+} from '@epam/uui';
import { City } from '@epam/uui-docs';
import { ReactComponent as MoreIcon } from '@epam/assets/icons/common/navigation-more_vert-18.svg';
import { ReactComponent as PencilIcon } from '@epam/assets/icons/common/content-edit-18.svg';
@@ -39,11 +49,14 @@ export default function CitiesTable() {
{
key: 'name',
caption: 'Name',
- render: (city) => (
-
- {city.name}
-
+ renderCell: (props) => (
+ }
+ { ...props }
+ />
),
+ canCopy: () => true,
isSortable: true,
width: 162,
grow: 1,
@@ -51,11 +64,14 @@ export default function CitiesTable() {
{
key: 'countryName',
caption: 'Country',
- render: (city) => (
-
- {city.countryName}
-
+ renderCell: (props) => (
+ }
+ { ...props }
+ />
),
+ canAcceptCopy: () => true,
isSortable: true,
width: 128,
isFilterActive: (filter) => filter.country && filter.country.$in && !!filter.country.$in.length,
@@ -123,6 +139,7 @@ export default function CitiesTable() {
// Spread ListProps and provide getRows function from view to DataTable component.
// getRows function will be called every time when table will need more rows.
{ ...view.getListProps() }
+ onCopy={ () => {} }
getRows={ view.getVisibleRows }
showColumnsConfig={ false }
headerTextCase="upper"
diff --git a/app/src/documents/structureComponents.ts b/app/src/documents/structureComponents.ts
index 21193fd951..c666614e31 100644
--- a/app/src/documents/structureComponents.ts
+++ b/app/src/documents/structureComponents.ts
@@ -116,7 +116,7 @@ export const componentsStructure = orderBy(
{ id: 'tables', name: 'Data Tables', parentId: 'components', tags: ['table'] },
{ id: 'tablesOverview', name: 'Overview', component: TablesOverviewDoc, parentId: 'tables', order: 1, tags: ['tables', 'dataTable'] },
{ id: 'tree', name: 'Tree', component: TreeDoc, parentId: 'components', tags: ['tree', 'virtualList', 'dataSources'] },
- { id: 'editableTables', name: 'Editable Tables', component: EditableTablesDoc, parentId: 'tables', order: 2, tags: ['tables', 'dataTable'] },
+ { id: 'editableTables', name: 'Editable', component: EditableTablesDoc, parentId: 'tables', order: 2, tags: ['tables', 'dataTable'] },
{ id: 'advancedTables', name: 'Advanced', component: AdvancedTablesDoc, parentId: 'tables', order: 3, tags: ['tables', 'dataTable'] },
{ id: 'useTableState', name: 'useTableState', component: useTableStateDoc, parentId: 'tables', order: 4, tags: ['tables', 'dataTable'] },
{ id: 'filtersPanel', name: 'Filters Panel', component: FiltersPanelDoc, parentId: 'tables', order: 5, tags: ['tables', 'dataTable'] },
diff --git a/uui-components/src/table/tableCellsSelection/DataTableSelectionProvider.tsx b/uui-components/src/table/tableCellsSelection/DataTableSelectionProvider.tsx
index 37a17a81b3..ebeca8c575 100644
--- a/uui-components/src/table/tableCellsSelection/DataTableSelectionProvider.tsx
+++ b/uui-components/src/table/tableCellsSelection/DataTableSelectionProvider.tsx
@@ -12,9 +12,17 @@ interface DataTableSelectionProviderProps extends React.Pro
export function DataTableSelectionProvider({
onCopy, rows, columns, children,
}: DataTableSelectionProviderProps) {
+ const rowsByIndex = useMemo(() => {
+ const rowsMap = new Map>();
+ rows.forEach((row) => {
+ rowsMap.set(row.index, row);
+ });
+ return rowsMap;
+ }, [rows]);
+
const {
selectionRange, setSelectionRange, getSelectedCells, startCell, getCellSelectionInfo,
- } = useSelectionManager({ rows, columns });
+ } = useSelectionManager({ rowsByIndex, columns });
useEffect(() => {
if (!selectionRange || !onCopy) return;
diff --git a/uui-components/src/table/tableCellsSelection/__tests__/helpers.test.tsx b/uui-components/src/table/tableCellsSelection/__tests__/helpers.test.tsx
index 86288daf2c..289646696f 100644
--- a/uui-components/src/table/tableCellsSelection/__tests__/helpers.test.tsx
+++ b/uui-components/src/table/tableCellsSelection/__tests__/helpers.test.tsx
@@ -1,7 +1,7 @@
import {
getCell, getCellPosition, getStartCell, getNormalizedLimits,
} from '../hooks/helpers';
-import { rowsMock, columnsMock } from '../mocks';
+import { rowsByIndexMock, columnsMock } from '../mocks';
describe('getNormalizedLimits', () => {
it('should return normalized limits', () => {
@@ -13,37 +13,37 @@ describe('getNormalizedLimits', () => {
describe('getCell', () => {
it('should get cell by coordinates', () => {
- const { row, column } = getCell(1, 1, rowsMock, columnsMock);
+ const { row, column } = getCell(1, 1, rowsByIndexMock, columnsMock);
const expectedColumn = columnsMock[1];
- const expectedRow = rowsMock[1];
+ const expectedRow = rowsByIndexMock.get(1);
expect(column).toEqual(expectedColumn);
expect(row).toEqual(expectedRow);
});
it('should return null if out of range', () => {
- expect(getCell(rowsMock.length, 1, rowsMock, columnsMock)).toBeNull();
- expect(getCell(1, columnsMock.length, rowsMock, columnsMock)).toBeNull();
+ expect(getCell(rowsByIndexMock.size, 1, rowsByIndexMock, columnsMock)).toBeNull();
+ expect(getCell(1, columnsMock.length, rowsByIndexMock, columnsMock)).toBeNull();
});
});
describe('getStartCell', () => {
it('should find a cell to copy from by coordinates', () => {
const copyCellColumn = 0;
- const copyCellRow = 1;
+ const copyCellRowIndex = 1;
const expectedColumn = columnsMock[copyCellColumn];
- const expectedRow = rowsMock[copyCellRow];
+ const expectedRow = rowsByIndexMock.get(copyCellRowIndex);
const selectionRange = {
- startColumnIndex: copyCellColumn, startRowIndex: copyCellRow, endColumnIndex: 1, endRowIndex: 2,
+ startColumnIndex: copyCellColumn, startRowIndex: copyCellRowIndex, endColumnIndex: 1, endRowIndex: 2,
};
- const { column, row } = getStartCell(selectionRange, rowsMock, columnsMock);
+ const { column, row } = getStartCell(selectionRange, rowsByIndexMock, columnsMock);
expect(column).toEqual(expectedColumn);
expect(row).toEqual(expectedRow);
});
it('should return null if no cell was selected', () => {
- expect(getStartCell(null, rowsMock, columnsMock)).toBeNull();
+ expect(getStartCell(null, rowsByIndexMock, columnsMock)).toBeNull();
});
});
diff --git a/uui-components/src/table/tableCellsSelection/__tests__/useSelectionManager.test.tsx b/uui-components/src/table/tableCellsSelection/__tests__/useSelectionManager.test.tsx
index 3aa4b0aa67..2db06ed806 100644
--- a/uui-components/src/table/tableCellsSelection/__tests__/useSelectionManager.test.tsx
+++ b/uui-components/src/table/tableCellsSelection/__tests__/useSelectionManager.test.tsx
@@ -1,12 +1,12 @@
import { act } from 'react-dom/test-utils';
import { renderHook } from '@epam/uui-test-utils';
import { useSelectionManager } from '../hooks';
-import { columnsMock, rowsMock } from '../mocks';
+import { columnsMock, rowsByIndexMock } from '../mocks';
describe('useSelectioManager', () => {
describe('selectRange', () => {
it('should select some range', async () => {
- const { result } = renderHook(() => useSelectionManager({ rows: rowsMock, columns: columnsMock }));
+ const { result } = renderHook(() => useSelectionManager({ rowsByIndex: rowsByIndexMock, columns: columnsMock }));
const newSelectionRange = {
startColumnIndex: 0, startRowIndex: 0, endColumnIndex: 1, endRowIndex: 1, isCopying: true,
};
@@ -26,7 +26,7 @@ describe('useSelectioManager', () => {
describe('startCell', () => {
it('should return cell to copy from', async () => {
- const { result } = renderHook(() => useSelectionManager({ rows: rowsMock, columns: columnsMock }));
+ const { result } = renderHook(() => useSelectionManager({ rowsByIndex: rowsByIndexMock, columns: columnsMock }));
const newSelectionRange = {
startColumnIndex: 1, startRowIndex: 1, endColumnIndex: 1, endRowIndex: 5, isCopying: true,
};
@@ -35,7 +35,7 @@ describe('useSelectioManager', () => {
});
const expectedColumn = columnsMock[newSelectionRange.startColumnIndex];
- const expectedRow = rowsMock[newSelectionRange.startRowIndex];
+ const expectedRow = rowsByIndexMock.get(newSelectionRange.startRowIndex);
expect(result.current.selectionRange).toEqual(newSelectionRange);
expect(result.current.startCell).toBeDefined();
@@ -45,7 +45,7 @@ describe('useSelectioManager', () => {
expect(row).toEqual(expectedRow);
});
it('should null if selection range was not set', () => {
- const { result } = renderHook(() => useSelectionManager({ rows: rowsMock, columns: columnsMock }));
+ const { result } = renderHook(() => useSelectionManager({ rowsByIndex: rowsByIndexMock, columns: columnsMock }));
expect(result.current.selectionRange).toBeNull();
expect(result.current.startCell).toBeNull();
@@ -54,7 +54,7 @@ describe('useSelectioManager', () => {
describe('getSelectedCells', () => {
it('should return selected range', async () => {
- const { result } = renderHook(() => useSelectionManager({ rows: rowsMock, columns: columnsMock }));
+ const { result } = renderHook(() => useSelectionManager({ rowsByIndex: rowsByIndexMock, columns: columnsMock }));
const newSelectionRange = {
startColumnIndex: 0, startRowIndex: 0, endColumnIndex: 1, endRowIndex: 3, isCopying: true,
};
@@ -63,17 +63,17 @@ describe('useSelectioManager', () => {
});
expect(result.current.getSelectedCells()).toEqual([
- { column: columnsMock[0], row: rowsMock[0] },
- { column: columnsMock[1], row: rowsMock[0] },
- { column: columnsMock[1], row: rowsMock[1] },
- { column: columnsMock[0], row: rowsMock[2] },
- { column: columnsMock[1], row: rowsMock[2] },
- { column: columnsMock[1], row: rowsMock[3] },
+ { column: columnsMock[0], row: rowsByIndexMock.get(0) },
+ { column: columnsMock[1], row: rowsByIndexMock.get(0) },
+ { column: columnsMock[1], row: rowsByIndexMock.get(1) },
+ { column: columnsMock[0], row: rowsByIndexMock.get(2) },
+ { column: columnsMock[1], row: rowsByIndexMock.get(2) },
+ { column: columnsMock[1], row: rowsByIndexMock.get(3) },
]);
});
it('should return null if selected range', () => {
- const { result } = renderHook(() => useSelectionManager({ rows: rowsMock, columns: columnsMock }));
+ const { result } = renderHook(() => useSelectionManager({ rowsByIndex: rowsByIndexMock, columns: columnsMock }));
expect(result.current.getSelectedCells()).toEqual([]);
});
});
@@ -83,7 +83,7 @@ describe('useSelectioManager', () => {
startColumnIndex: 0, startRowIndex: 0, endColumnIndex: 2, endRowIndex: 3, isCopying: true,
};
it('should render borders for start cell', async () => {
- const { result } = renderHook(() => useSelectionManager({ rows: rowsMock, columns: columnsMock }));
+ const { result } = renderHook(() => useSelectionManager({ rowsByIndex: rowsByIndexMock, columns: columnsMock }));
act(() => {
result.current.setSelectionRange(selectionRange);
});
@@ -101,7 +101,7 @@ describe('useSelectioManager', () => {
});
it('should render border for cell near border', async () => {
- const { result } = renderHook(() => useSelectionManager({ rows: rowsMock, columns: columnsMock }));
+ const { result } = renderHook(() => useSelectionManager({ rowsByIndex: rowsByIndexMock, columns: columnsMock }));
act(() => {
result.current.setSelectionRange(selectionRange);
});
@@ -130,7 +130,7 @@ describe('useSelectioManager', () => {
});
it('should not render borders for cell inside the area of selection', async () => {
- const { result } = renderHook(() => useSelectionManager({ rows: rowsMock, columns: columnsMock }));
+ const { result } = renderHook(() => useSelectionManager({ rowsByIndex: rowsByIndexMock, columns: columnsMock }));
act(() => {
result.current.setSelectionRange(selectionRange);
});
diff --git a/uui-components/src/table/tableCellsSelection/hooks/helpers.ts b/uui-components/src/table/tableCellsSelection/hooks/helpers.ts
index e01e001e4b..764e7de928 100644
--- a/uui-components/src/table/tableCellsSelection/hooks/helpers.ts
+++ b/uui-components/src/table/tableCellsSelection/hooks/helpers.ts
@@ -1,8 +1,14 @@
import { DataColumnProps, DataRowProps, DataTableSelectedCellData } from '@epam/uui-core';
import { DataTableSelectionRange } from '../types';
-export const getCell = (rowIndex: number, columnIndex: number, rows: DataRowProps[], columns: DataColumnProps[]) => {
- const row = rows[rowIndex];
+export const getCell = (
+ rowIndex: number,
+ columnIndex: number,
+ rowsByIndex: Map>,
+ columns: DataColumnProps[],
+) => {
+ const row = rowsByIndex.get(rowIndex);
const column = columns[columnIndex];
if (!row || !column) {
@@ -13,7 +19,7 @@ export const getCell = (rowIndex: number, columnIndex: number, rows:
export const getStartCell = (
selectionRange: DataTableSelectionRange | null,
- rows: DataRowProps[],
+ rowsByIndex: Map>,
columns: DataColumnProps[],
): DataTableSelectedCellData | null => {
if (selectionRange === null) {
@@ -21,7 +27,7 @@ export const getStartCell = (
}
const { startRowIndex, startColumnIndex } = selectionRange;
- return getCell(startRowIndex, startColumnIndex, rows, columns);
+ return getCell(startRowIndex, startColumnIndex, rowsByIndex, columns);
};
export const getNormalizedLimits = (startIndex: number, endIndex: number) => (startIndex < endIndex ? [startIndex, endIndex] : [endIndex, startIndex]);
diff --git a/uui-components/src/table/tableCellsSelection/hooks/useSelectionManager.tsx b/uui-components/src/table/tableCellsSelection/hooks/useSelectionManager.tsx
index 70dd18576b..b5f840d9db 100644
--- a/uui-components/src/table/tableCellsSelection/hooks/useSelectionManager.tsx
+++ b/uui-components/src/table/tableCellsSelection/hooks/useSelectionManager.tsx
@@ -7,27 +7,28 @@ import {
getCell, getCellPosition, getStartCell, getNormalizedLimits,
} from './helpers';
-export const useSelectionManager = ({ rows, columns }: SelectionManagerProps): SelectionManager => {
+export const useSelectionManager = ({ rowsByIndex, columns }: SelectionManagerProps): SelectionManager => {
const [selectionRange, setSelectionRange] = useState(null);
const startCell = useMemo(
- () => getStartCell(selectionRange, rows, columns),
+ () => getStartCell(selectionRange, rowsByIndex, columns),
[
- selectionRange?.startColumnIndex, selectionRange?.startRowIndex, rows, columns,
+ selectionRange?.startColumnIndex, selectionRange?.startRowIndex, rowsByIndex, columns,
],
);
const canBeSelected = useCallback(
(rowIndex: number, columnIndex: number, { copyFrom, copyTo }: CopyOptions) => {
- const cell = getCell(rowIndex, columnIndex, rows, columns);
+ const cell = getCell(rowIndex, columnIndex, rowsByIndex, columns);
+
if (!startCell && copyTo) return false;
- if (copyFrom) return !!cell.column.canCopy?.(cell);
+ if (copyFrom) {
+ return !!cell.column.canCopy?.(cell);
+ }
return !!cell.column.canAcceptCopy?.(startCell, cell);
},
- [
- startCell, columns, rows,
- ],
+ [startCell, columns, rowsByIndex],
);
const shouldSelectCell = useCallback(
@@ -53,7 +54,7 @@ export const useSelectionManager = ({ rows, columns }: Sele
for (let rowIndex = startRow; rowIndex <= endRow; rowIndex++) {
for (let columnIndex = startColumn; columnIndex <= endColumn; columnIndex++) {
if (shouldSelectCell(rowIndex, columnIndex)) {
- const cell = getCell(rowIndex, columnIndex, rows, columns);
+ const cell = getCell(rowIndex, columnIndex, rowsByIndex, columns);
selectedCells.push(cell);
}
}
@@ -61,7 +62,7 @@ export const useSelectionManager = ({ rows, columns }: Sele
return selectedCells;
}, [
- selectionRange, columns, shouldSelectCell, rows,
+ selectionRange, columns, shouldSelectCell, rowsByIndex,
]);
const getCellSelectionInfo = useCallback(
diff --git a/uui-components/src/table/tableCellsSelection/mocks/tables.tsx b/uui-components/src/table/tableCellsSelection/mocks/tables.tsx
index 7ad4c8aae0..cca20555e0 100644
--- a/uui-components/src/table/tableCellsSelection/mocks/tables.tsx
+++ b/uui-components/src/table/tableCellsSelection/mocks/tables.tsx
@@ -2,7 +2,7 @@ import React from 'react';
import { DataColumnProps, DataRowProps } from '@epam/uui-core';
type Row = { salary: number; age: number; name: string; phone: string };
-export const rowsMock: DataRowProps[] = [
+const rowsMock: DataRowProps[] = [
{
id: 1,
rowKey: '1',
@@ -10,21 +10,24 @@ export const rowsMock: DataRowProps[] = [
value: {
age: 10, salary: 1000, name: 'first', phone: 'some phone 1',
},
- }, {
+ },
+ {
id: 2,
rowKey: '2',
index: 1,
value: {
age: 20, salary: 2000, name: 'second', phone: 'some phone 2',
},
- }, {
+ },
+ {
id: 3,
rowKey: '3',
index: 2,
value: {
age: 30, salary: 3000, name: 'third', phone: 'some phone 3',
},
- }, {
+ },
+ {
id: 4,
rowKey: '4',
index: 3,
@@ -34,6 +37,16 @@ export const rowsMock: DataRowProps[] = [
},
];
+const getRowsByIndex = (rows: DataRowProps[]) => {
+ const rowsMap = new Map>();
+ rows.forEach((row) => {
+ rowsMap.set(row.index, row);
+ });
+ return rowsMap;
+};
+
+export const rowsByIndexMock = getRowsByIndex(rowsMock);
+
export const columnsMock: DataColumnProps[] = [
{
key: 'age',
diff --git a/uui-components/src/table/tableCellsSelection/types.ts b/uui-components/src/table/tableCellsSelection/types.ts
index 577ae075a0..c3236baa7c 100644
--- a/uui-components/src/table/tableCellsSelection/types.ts
+++ b/uui-components/src/table/tableCellsSelection/types.ts
@@ -10,7 +10,7 @@ export interface DataTableSelectionRange {
}
export interface SelectionManagerProps {
- rows: DataRowProps[];
+ rowsByIndex: Map>;
columns: DataColumnProps[];
}