From 4280548b3f18a08d6e50b34b4efa706c7e584cc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20L=C3=B3pez=20=C3=9Abeda?= Date: Fri, 27 Sep 2024 16:32:21 +0200 Subject: [PATCH] fix(table): rowHeight override with colDefs --- packages/table/src/core/utils/columns.test.ts | 32 +-------------- packages/table/src/core/utils/columns.ts | 7 ---- .../helpers/definitions/col/getColDef.test.ts | 24 +++++++++++ .../src/helpers/definitions/col/getColDef.ts | 4 ++ .../definitions/col/getColDefByIndex.test.ts | 24 +++++++++++ .../definitions/col/getColDefByIndex.ts | 4 ++ .../col/getRowHeightFromColDefs.test.ts | 40 +++++++++++++++++++ .../col/getRowHeightFromColDefs.ts | 7 ++++ .../src/helpers/definitions/col/index.ts | 3 ++ .../table/src/helpers/definitions/index.ts | 1 + .../row/deletePresetRowDefs.test.ts | 2 +- .../useTableVirtualizationColumn/index.ts | 1 + .../useTableVirtualizationColumn.ts | 2 +- .../src/hooks/useTableVirtualizationRow.ts | 38 ------------------ .../hooks/useTableVirtualizationRow/index.ts | 1 + .../useTableVirtualizationRow.ts | 34 ++++++++++++++++ packages/table/src/presets/column/longText.ts | 15 ------- .../src/presets/column/longText/LongText.mdx | 34 ++++++++++++++++ .../column/longText/LongText.stories.tsx | 40 +++++++++++++++++++ .../src/presets/column/longText/index.ts | 1 + .../src/presets/column/longText/longText.ts | 14 +++++++ .../renderers/TextRenderer/TextRenderer.tsx | 6 ++- 22 files changed, 241 insertions(+), 93 deletions(-) create mode 100644 packages/table/src/helpers/definitions/col/getColDef.test.ts create mode 100644 packages/table/src/helpers/definitions/col/getColDef.ts create mode 100644 packages/table/src/helpers/definitions/col/getColDefByIndex.test.ts create mode 100644 packages/table/src/helpers/definitions/col/getColDefByIndex.ts create mode 100644 packages/table/src/helpers/definitions/col/getRowHeightFromColDefs.test.ts create mode 100644 packages/table/src/helpers/definitions/col/getRowHeightFromColDefs.ts create mode 100644 packages/table/src/helpers/definitions/col/index.ts create mode 100644 packages/table/src/hooks/useTableVirtualizationColumn/index.ts rename packages/table/src/hooks/{ => useTableVirtualizationColumn}/useTableVirtualizationColumn.ts (98%) delete mode 100644 packages/table/src/hooks/useTableVirtualizationRow.ts create mode 100644 packages/table/src/hooks/useTableVirtualizationRow/index.ts create mode 100644 packages/table/src/hooks/useTableVirtualizationRow/useTableVirtualizationRow.ts delete mode 100644 packages/table/src/presets/column/longText.ts create mode 100644 packages/table/src/presets/column/longText/LongText.mdx create mode 100644 packages/table/src/presets/column/longText/LongText.stories.tsx create mode 100644 packages/table/src/presets/column/longText/index.ts create mode 100644 packages/table/src/presets/column/longText/longText.ts diff --git a/packages/table/src/core/utils/columns.test.ts b/packages/table/src/core/utils/columns.test.ts index 09e3faca..b3e666e2 100644 --- a/packages/table/src/core/utils/columns.test.ts +++ b/packages/table/src/core/utils/columns.test.ts @@ -1,28 +1,8 @@ import { describe, test, expect } from 'vitest'; -import { VirtualItem } from '@tanstack/react-virtual'; -import { DEFAULT_VIRTUAL_COLUMN, DEFAULT_COLDEF } from './../../constants'; +import { DEFAULT_COLDEF } from './../../constants'; import { TColDef, TDefaultColDef } from '../../declarations'; -import { getColDefByID, getCollatedColumns } from './columns'; - -const colDefsMock: TColDef[] = [ - { id: 'col0' }, - { id: 'col1' }, - { id: 'example' }, - { id: 'col3' }, -]; - -const getColDefByIDCases: [string, TColDef[], VirtualItem, TColDef][] = [ - ['No column definitions', [], DEFAULT_VIRTUAL_COLUMN, undefined], - ['No virtual column', colDefsMock, null, undefined], - ['Standard case', colDefsMock, DEFAULT_VIRTUAL_COLUMN, colDefsMock[2]], - [ - 'Column not found', - colDefsMock.slice(0, 1), - DEFAULT_VIRTUAL_COLUMN, - undefined, - ], -]; +import { getCollatedColumns } from './columns'; const getCollatedColumnsCases: [ string, @@ -43,14 +23,6 @@ const getCollatedColumnsCases: [ describe('Table', () => { describe('Utils', () => { describe('Columns', () => { - describe('getColDefByID', () => { - test.each(getColDefByIDCases)( - '%s', - (_title, colDefs, virtualColumn, expected) => { - expect(getColDefByID(colDefs, virtualColumn)).toEqual(expected); - }, - ); - }); describe('getCollatedColumns', () => { test.each(getCollatedColumnsCases)( '%s', diff --git a/packages/table/src/core/utils/columns.ts b/packages/table/src/core/utils/columns.ts index 94e9b228..7e4b9d82 100644 --- a/packages/table/src/core/utils/columns.ts +++ b/packages/table/src/core/utils/columns.ts @@ -1,12 +1,5 @@ -import { VirtualItem } from '@tanstack/react-virtual'; import type { TColDef, TDefaultColDef, TColPreset } from '../../declarations'; -export const getColDefByID = ( - colDefs: TColDef[] = [], - virtualColumn: VirtualItem, -): TColDef => - colDefs.find((colDef: TColDef) => colDef.id === virtualColumn?.key); - /** * @returns Column defs mixed with default column def */ diff --git a/packages/table/src/helpers/definitions/col/getColDef.test.ts b/packages/table/src/helpers/definitions/col/getColDef.test.ts new file mode 100644 index 00000000..a98666bd --- /dev/null +++ b/packages/table/src/helpers/definitions/col/getColDef.test.ts @@ -0,0 +1,24 @@ +import { describe, test, expect } from 'vitest'; + +import { TColDef } from '../../../declarations'; +import { getColDef } from './getColDef'; + +describe('helpers', () => { + describe('definitions', () => { + describe('col', () => { + describe('getColDef', () => { + const cases: [string, TColDef[], string, TColDef][] = [ + ['empty col defs return undefined', [], '1', undefined], + ['id null return undefined', [{ id: '1' }], null, undefined], + ['colDef null return undefined', null, '1', undefined], + ['return element colDef', [{ id: '1' }], '1', { id: '1' }], + ['id not find in colDef', [{ id: '1' }], '2', undefined], + ]; + + test.each(cases)('%s', (_title, rowDefs, id, expected) => { + expect(getColDef(rowDefs, id)).toEqual(expected); + }); + }); + }); + }); +}); diff --git a/packages/table/src/helpers/definitions/col/getColDef.ts b/packages/table/src/helpers/definitions/col/getColDef.ts new file mode 100644 index 00000000..ef1aab8b --- /dev/null +++ b/packages/table/src/helpers/definitions/col/getColDef.ts @@ -0,0 +1,4 @@ +import type { TColDef } from '../../../declarations'; + +export const getColDef = (colDefs: TColDef[], id: string) => + colDefs?.find((col) => col.id === id); diff --git a/packages/table/src/helpers/definitions/col/getColDefByIndex.test.ts b/packages/table/src/helpers/definitions/col/getColDefByIndex.test.ts new file mode 100644 index 00000000..d58b23d3 --- /dev/null +++ b/packages/table/src/helpers/definitions/col/getColDefByIndex.test.ts @@ -0,0 +1,24 @@ +import { describe, test, expect } from 'vitest'; + +import { TColDef } from '../../../declarations'; +import { getColDefByIndex } from './getColDefByIndex'; + +describe('helpers', () => { + describe('definitions', () => { + describe('col', () => { + describe('getColDefByIndex', () => { + const cases: [string, TColDef[], number, TColDef][] = [ + ['empty col defs return undefined', [], 1, undefined], + ['id null return undefined', [{ id: '1' }], null, undefined], + ['colDef null return undefined', null, 1, undefined], + ['return element colDef', [{ id: '1' }], 0, { id: '1' }], + ['id not find in colDef', [{ id: '1' }], 2, undefined], + ]; + + test.each(cases)('%s', (_title, rowDefs, id, expected) => { + expect(getColDefByIndex(rowDefs, id)).toEqual(expected); + }); + }); + }); + }); +}); diff --git a/packages/table/src/helpers/definitions/col/getColDefByIndex.ts b/packages/table/src/helpers/definitions/col/getColDefByIndex.ts new file mode 100644 index 00000000..9b5346c1 --- /dev/null +++ b/packages/table/src/helpers/definitions/col/getColDefByIndex.ts @@ -0,0 +1,4 @@ +import type { TColDef } from '../../../declarations'; + +export const getColDefByIndex = (colDefs: TColDef[], index: number) => + colDefs ? colDefs[index] : undefined; diff --git a/packages/table/src/helpers/definitions/col/getRowHeightFromColDefs.test.ts b/packages/table/src/helpers/definitions/col/getRowHeightFromColDefs.test.ts new file mode 100644 index 00000000..ecfd679b --- /dev/null +++ b/packages/table/src/helpers/definitions/col/getRowHeightFromColDefs.test.ts @@ -0,0 +1,40 @@ +import { describe, test, expect } from 'vitest'; + +import { TColDef } from '../../../declarations'; +import { getRowHeightFromColDefs } from './getRowHeightFromColDefs'; + +describe('helpers', () => { + describe('definitions', () => { + describe('col', () => { + describe('getRowHeightFromColDefs', () => { + const cases: [string, TColDef[], number][] = [ + ['empty col defs return 0', [], undefined], + ['col defs without rowHeight', [{ id: '1' }, { id: '2' }], undefined], + ['one col with rowHeight', [{ id: '1', rowHeight: 100 }], 100], + [ + 'several columns with the same rowHeight', + [ + { id: '1', rowHeight: 100 }, + { id: '2', rowHeight: 100 }, + { id: '3', rowHeight: 100 }, + ], + 100, + ], + [ + 'several columns with diferents rowHeight', + [ + { id: '1', rowHeight: 10 }, + { id: '2', rowHeight: 100 }, + { id: '3', rowHeight: 50 }, + ], + 100, + ], + ]; + + test.each(cases)('%s', (_title, rowDefs, expected) => { + expect(getRowHeightFromColDefs(rowDefs)).toEqual(expected); + }); + }); + }); + }); +}); diff --git a/packages/table/src/helpers/definitions/col/getRowHeightFromColDefs.ts b/packages/table/src/helpers/definitions/col/getRowHeightFromColDefs.ts new file mode 100644 index 00000000..645bf1e5 --- /dev/null +++ b/packages/table/src/helpers/definitions/col/getRowHeightFromColDefs.ts @@ -0,0 +1,7 @@ +import type { TColDef } from '../../../declarations'; + +export const getRowHeightFromColDefs = (colDefs: TColDef[]) => + colDefs.reduce( + (prev: number, col) => (col?.rowHeight > prev ? col.rowHeight : prev), + 0, + ) || undefined; diff --git a/packages/table/src/helpers/definitions/col/index.ts b/packages/table/src/helpers/definitions/col/index.ts new file mode 100644 index 00000000..0fdbb733 --- /dev/null +++ b/packages/table/src/helpers/definitions/col/index.ts @@ -0,0 +1,3 @@ +export * from './getColDef'; +export * from './getColDefByIndex'; +export * from './getRowHeightFromColDefs'; diff --git a/packages/table/src/helpers/definitions/index.ts b/packages/table/src/helpers/definitions/index.ts index a4b66ab5..433dda46 100644 --- a/packages/table/src/helpers/definitions/index.ts +++ b/packages/table/src/helpers/definitions/index.ts @@ -1,3 +1,4 @@ export * from './cell'; +export * from './col'; export * from './row'; export * from './data'; diff --git a/packages/table/src/helpers/definitions/row/deletePresetRowDefs.test.ts b/packages/table/src/helpers/definitions/row/deletePresetRowDefs.test.ts index 25a50b62..72c3bf1a 100644 --- a/packages/table/src/helpers/definitions/row/deletePresetRowDefs.test.ts +++ b/packages/table/src/helpers/definitions/row/deletePresetRowDefs.test.ts @@ -1,6 +1,6 @@ import { describe, test, expect } from 'vitest'; -import type { TPresetRow, TRowDef } from '../../../declarations'; +import type { TRowDef } from '../../../declarations'; import { deletePresetRowDefs } from './deletePresetRowDef'; describe('helpers', () => { diff --git a/packages/table/src/hooks/useTableVirtualizationColumn/index.ts b/packages/table/src/hooks/useTableVirtualizationColumn/index.ts new file mode 100644 index 00000000..480201c5 --- /dev/null +++ b/packages/table/src/hooks/useTableVirtualizationColumn/index.ts @@ -0,0 +1 @@ +export * from './useTableVirtualizationColumn'; diff --git a/packages/table/src/hooks/useTableVirtualizationColumn.ts b/packages/table/src/hooks/useTableVirtualizationColumn/useTableVirtualizationColumn.ts similarity index 98% rename from packages/table/src/hooks/useTableVirtualizationColumn.ts rename to packages/table/src/hooks/useTableVirtualizationColumn/useTableVirtualizationColumn.ts index 2fa55c30..3bfd4bea 100644 --- a/packages/table/src/hooks/useTableVirtualizationColumn.ts +++ b/packages/table/src/hooks/useTableVirtualizationColumn/useTableVirtualizationColumn.ts @@ -1,7 +1,7 @@ import * as React from 'react'; import { useVirtualizer } from '@tanstack/react-virtual'; -import { TableContext } from '../context'; +import { TableContext } from '../../context'; type TUseVirtualizationParamsColumn = { ref: React.MutableRefObject; diff --git a/packages/table/src/hooks/useTableVirtualizationRow.ts b/packages/table/src/hooks/useTableVirtualizationRow.ts deleted file mode 100644 index e6bd8b12..00000000 --- a/packages/table/src/hooks/useTableVirtualizationRow.ts +++ /dev/null @@ -1,38 +0,0 @@ -import * as React from 'react'; -import { useVirtualizer } from '@tanstack/react-virtual'; - -import { TableContext } from '../context/TableContext'; -import { ROW_HEIGHT_MD } from '../constants'; -import { getRowDef } from '../helpers'; - -type TUseVirtualizationParamsRow = { - ref: React.MutableRefObject; -}; - -export const useTableVirtualizationRow = ({ - ref, -}: TUseVirtualizationParamsRow) => { - const { rowHeight, colDefs, data, rowDefs } = React.useContext(TableContext); - - const height = React.useMemo(() => { - const maxHeight = - rowHeight ?? - colDefs.reduce( - (prev: number, curr) => - (curr?.rowHeight ?? 0 > prev) ? curr.rowHeight : prev, - 0, - ); - return maxHeight > 0 ? maxHeight : ROW_HEIGHT_MD; - }, [rowHeight, colDefs]); - - return useVirtualizer({ - count: data.length, - getScrollElement: () => ref.current, - estimateSize: (index: number) => { - const rowDef = getRowDef(rowDefs, data[index].id as string); - const rowDefHeight = rowDef?.height ? rowDef.height : height; - return rowDef?.hide ? 0 : rowDefHeight; - }, - overscan: 10, - }); -}; diff --git a/packages/table/src/hooks/useTableVirtualizationRow/index.ts b/packages/table/src/hooks/useTableVirtualizationRow/index.ts new file mode 100644 index 00000000..54e3d323 --- /dev/null +++ b/packages/table/src/hooks/useTableVirtualizationRow/index.ts @@ -0,0 +1 @@ +export * from './useTableVirtualizationRow'; diff --git a/packages/table/src/hooks/useTableVirtualizationRow/useTableVirtualizationRow.ts b/packages/table/src/hooks/useTableVirtualizationRow/useTableVirtualizationRow.ts new file mode 100644 index 00000000..cf60c799 --- /dev/null +++ b/packages/table/src/hooks/useTableVirtualizationRow/useTableVirtualizationRow.ts @@ -0,0 +1,34 @@ +import * as React from 'react'; +import { useVirtualizer } from '@tanstack/react-virtual'; + +import { TableContext } from '../../context'; +import { ROW_HEIGHT_MD } from '../../constants'; +import { getRowDef, getRowHeightFromColDefs } from '../../helpers'; + +export const useTableVirtualizationRow = ({ + ref, +}: { + ref: React.MutableRefObject; +}) => { + const { rowHeight, colDefs, data, rowDefs } = React.useContext(TableContext); + + // The rowHeight from the colDefs is the same for each row + const colDefsRowHeight = React.useMemo( + () => getRowHeightFromColDefs(colDefs), + [colDefs], + ); + + return useVirtualizer({ + count: data.length, + getScrollElement: () => ref.current, + estimateSize: (index: number) => { + const rowDef = getRowDef(rowDefs, data[index].id as string); + // The height is a preference of: rowDef, colDef, table:rowHeight or the + // default size + const height = + rowDef?.height || colDefsRowHeight || rowHeight || ROW_HEIGHT_MD; + return rowDef?.hide ? 0 : height; + }, + overscan: 10, + }); +}; diff --git a/packages/table/src/presets/column/longText.ts b/packages/table/src/presets/column/longText.ts deleted file mode 100644 index 7c978d58..00000000 --- a/packages/table/src/presets/column/longText.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { ROW_HEIGHT_LG } from "../../constants"; - -import { TColDef } from "../../declarations"; -import { TextAreaEditor } from "../../editors"; -import { TextFilter } from "../../filters"; -import { TextRenderer } from "../../renderers"; - - -export const longText: TColDef = { - id: 'longText', - cellRenderer: TextRenderer, - cellEditor: TextAreaEditor, - rowHeight: ROW_HEIGHT_LG, - cellFilter: TextFilter, -}; diff --git a/packages/table/src/presets/column/longText/LongText.mdx b/packages/table/src/presets/column/longText/LongText.mdx new file mode 100644 index 00000000..61160b85 --- /dev/null +++ b/packages/table/src/presets/column/longText/LongText.mdx @@ -0,0 +1,34 @@ +import { Meta, Story, Source } from '@storybook/blocks'; + +import * as Stories from './LongText.stories'; + + + +# Preset `longText` + + + +The preset long text is a variation of the `text` preset that do several things: + +- Use the `TextRenderer` renderer +- Use the `TextAreaEditor` as editor +- Use the `TexFilter` as filter +- Define a height of twice height for rowHeight (defined at column level) + +In the example you are viewing a modified `longText` preset with the next +configuration: + + + +Here the `truncateLine: 0` is telling to the `TextRenderer` to not truncate the +line. And the `rowHeight: 200` is defining the height for each element of the +column. diff --git a/packages/table/src/presets/column/longText/LongText.stories.tsx b/packages/table/src/presets/column/longText/LongText.stories.tsx new file mode 100644 index 00000000..49173121 --- /dev/null +++ b/packages/table/src/presets/column/longText/LongText.stories.tsx @@ -0,0 +1,40 @@ +import { Meta, StoryObj } from '@storybook/react'; + +import { BasicTable } from '../../../recipes'; + +const meta: Meta = { + title: 'Components/Layout/Table/Presets/Column/LongText', + component: BasicTable, + parameters: { + layout: 'fullscreen', + }, +}; + +export default meta; +type Story = StoryObj; + +export const Base: Story = { + args: { + colDefs: [ + { + id: 'id', + headerName: 'id', + preset: 'text', + }, + { + id: 'text', + headerName: 'Long text', + preset: 'longText', + rowHeight: 260, + truncateLine: 0, + }, + ], + data: [ + { id: '1', text: 'short text' }, + { + id: '2', + text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris scelerisque laoreet lectus et vestibulum. Curabitur varius accumsan metus sed interdum. Mauris nec est at eros pharetra congue. Donec malesuada erat eget libero efficitur, nec convallis enim egestas. Mauris vitae ante quis purus ornare iaculis et vitae nibh. Cras pharetra suscipit quam, vel semper eros bibendum eget. Sed felis ipsum, maximus eu elit non, vehicula maximus tortor. Praesent congue ultricies libero ut ultricies. Donec eu elementum lacus. Quisque ac suscipit sem, vitae luctus tellus.', + }, + ], + }, +}; diff --git a/packages/table/src/presets/column/longText/index.ts b/packages/table/src/presets/column/longText/index.ts new file mode 100644 index 00000000..383f7cfb --- /dev/null +++ b/packages/table/src/presets/column/longText/index.ts @@ -0,0 +1 @@ +export * from './longText'; diff --git a/packages/table/src/presets/column/longText/longText.ts b/packages/table/src/presets/column/longText/longText.ts new file mode 100644 index 00000000..98b429dd --- /dev/null +++ b/packages/table/src/presets/column/longText/longText.ts @@ -0,0 +1,14 @@ +import { ROW_HEIGHT_LG } from '../../../constants'; + +import { TColDef } from '../../../declarations'; +import { TextAreaEditor } from '../../../editors'; +import { TextFilter } from '../../../filters'; +import { TextRenderer } from '../../../renderers'; + +export const longText: TColDef = { + id: 'longText', + cellRenderer: TextRenderer, + cellEditor: TextAreaEditor, + rowHeight: ROW_HEIGHT_LG, + cellFilter: TextFilter, +}; diff --git a/packages/table/src/renderers/TextRenderer/TextRenderer.tsx b/packages/table/src/renderers/TextRenderer/TextRenderer.tsx index 2665f6dc..2a6a7152 100644 --- a/packages/table/src/renderers/TextRenderer/TextRenderer.tsx +++ b/packages/table/src/renderers/TextRenderer/TextRenderer.tsx @@ -6,7 +6,11 @@ import type { TCellRenderer } from '../../declarations'; export const TextRenderer: React.FC = ({ colDef, value }) => { const truncateLine = - colDef?.truncateLine || (colDef?.preset === 'longText' ? 2 : 1); + colDef?.truncateLine !== undefined + ? colDef?.truncateLine + : colDef?.preset === 'longText' + ? 2 + : 1; return (