@indico-data/design-system 2.49.0 → 2.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/lib/components/tanstackTable/TankstackTable.types.d.ts +40 -0
  2. package/lib/components/tanstackTable/TanstackTable.stories.d.ts +15 -0
  3. package/lib/components/tanstackTable/TanstakTable.d.ts +4 -0
  4. package/lib/components/tanstackTable/__tests__/TanstackTable.test.d.ts +1 -0
  5. package/lib/components/tanstackTable/__tests__/__mocks__/test-mock-data.d.ts +8 -0
  6. package/lib/components/tanstackTable/components/ActionBar/ActionBar.d.ts +17 -0
  7. package/lib/components/tanstackTable/components/ActionBar/ActionBar.stories.d.ts +10 -0
  8. package/lib/components/tanstackTable/components/ActionBar/__tests__/ActionBar.test.d.ts +1 -0
  9. package/lib/components/tanstackTable/components/ActionBar/index.d.ts +1 -0
  10. package/lib/components/tanstackTable/components/NoResults/NoResults.d.ts +7 -0
  11. package/lib/components/tanstackTable/components/NoResults/__tests__/NoResult.test.d.ts +1 -0
  12. package/lib/components/tanstackTable/components/NoResults/index.d.ts +1 -0
  13. package/lib/components/tanstackTable/components/TableBody/TableBody.d.ts +12 -0
  14. package/lib/components/tanstackTable/components/TableBody/index.d.ts +1 -0
  15. package/lib/components/tanstackTable/components/TableHeader/TableHeader.d.ts +6 -0
  16. package/lib/components/tanstackTable/components/TableHeader/index.d.ts +1 -0
  17. package/lib/components/tanstackTable/components/TablePagination/TablePagination.d.ts +9 -0
  18. package/lib/components/tanstackTable/components/TablePagination/__tests__/TablePagination.test.d.ts +1 -0
  19. package/lib/components/tanstackTable/components/TablePagination/index.d.ts +1 -0
  20. package/lib/components/tanstackTable/docs/pinnedColumns/PinnedColumn.stories.d.ts +7 -0
  21. package/lib/components/tanstackTable/docs/withRowClick/WithRowClick.stories.d.ts +7 -0
  22. package/lib/components/tanstackTable/helpers.d.ts +830 -0
  23. package/lib/components/tanstackTable/index.d.ts +2 -0
  24. package/lib/components/tanstackTable/mock-data/mock-data.d.ts +14 -0
  25. package/lib/components/tanstackTable/mock-data/table-configuration.d.ts +3 -0
  26. package/lib/components/tanstackTable/useTanstackTable.d.ts +16 -0
  27. package/lib/index.css +407 -80
  28. package/lib/index.d.ts +62 -17
  29. package/lib/index.esm.css +407 -80
  30. package/lib/index.esm.js +20455 -56
  31. package/lib/index.esm.js.map +1 -1
  32. package/lib/index.js +20455 -55
  33. package/lib/index.js.map +1 -1
  34. package/lib/stylesAndAnimations/utilityClasses/UtilityClassesData.d.ts +7 -0
  35. package/lib/stylesAndAnimations/utilityClasses/UtilityClassesTable.d.ts +1 -0
  36. package/lib/stylesAndAnimations/utilityClasses/UtilityClassesTable.stories.d.ts +6 -0
  37. package/package.json +2 -1
  38. package/src/components/tanstackTable/TankstackTable.types.ts +39 -0
  39. package/src/components/tanstackTable/TanstackTable.mdx +122 -0
  40. package/src/components/tanstackTable/TanstackTable.stories.tsx +260 -0
  41. package/src/components/tanstackTable/TanstakTable.tsx +157 -0
  42. package/src/components/tanstackTable/__tests__/TanstackTable.test.tsx +87 -0
  43. package/src/components/tanstackTable/__tests__/__mocks__/test-mock-data.tsx +83 -0
  44. package/src/components/tanstackTable/components/ActionBar/ActionBar.mdx +10 -0
  45. package/src/components/tanstackTable/components/ActionBar/ActionBar.scss +30 -0
  46. package/src/components/tanstackTable/components/ActionBar/ActionBar.stories.tsx +98 -0
  47. package/src/components/tanstackTable/components/ActionBar/ActionBar.tsx +51 -0
  48. package/src/components/tanstackTable/components/ActionBar/__tests__/ActionBar.test.tsx +87 -0
  49. package/src/components/tanstackTable/components/ActionBar/index.ts +1 -0
  50. package/src/components/tanstackTable/components/NoResults/NoResults.scss +24 -0
  51. package/src/components/tanstackTable/components/NoResults/NoResults.tsx +22 -0
  52. package/src/components/tanstackTable/components/NoResults/__tests__/NoResult.test.tsx +25 -0
  53. package/src/components/tanstackTable/components/NoResults/index.ts +1 -0
  54. package/src/components/tanstackTable/components/TableBody/TableBody.tsx +87 -0
  55. package/src/components/tanstackTable/components/TableBody/index.ts +1 -0
  56. package/src/components/tanstackTable/components/TableHeader/TableHeader.tsx +49 -0
  57. package/src/components/tanstackTable/components/TableHeader/index.ts +1 -0
  58. package/src/components/tanstackTable/components/TablePagination/TablePagination.tsx +45 -0
  59. package/src/components/tanstackTable/components/TablePagination/__tests__/TablePagination.test.tsx +18 -0
  60. package/src/components/tanstackTable/components/TablePagination/index.ts +1 -0
  61. package/src/components/tanstackTable/docs/pinnedColumns/PinnedColumn.mdx +34 -0
  62. package/src/components/tanstackTable/docs/pinnedColumns/PinnedColumn.stories.tsx +40 -0
  63. package/src/components/tanstackTable/docs/withRowClick/WithRowClick.mdx +48 -0
  64. package/src/components/tanstackTable/docs/withRowClick/WithRowClick.stories.tsx +32 -0
  65. package/src/components/tanstackTable/helpers.ts +45 -0
  66. package/src/components/tanstackTable/index.ts +2 -0
  67. package/src/components/tanstackTable/mock-data/mock-data.ts +256 -0
  68. package/src/components/tanstackTable/mock-data/table-configuration.tsx +219 -0
  69. package/src/components/tanstackTable/styles/_variables.scss +35 -0
  70. package/src/components/tanstackTable/styles/table.scss +204 -0
  71. package/src/components/tanstackTable/styles/test.scss +19 -0
  72. package/src/components/tanstackTable/tanstack-table.d.ts +18 -0
  73. package/src/components/tanstackTable/useTanstackTable.tsx +42 -0
  74. package/src/index.ts +1 -0
  75. package/src/legacy/components/loading-indicators/CirclePulse/CirclePulse.tsx +1 -0
  76. package/src/storybookDocs/Permafrost.mdx +22 -11
  77. package/src/styles/_borders.scss +2 -1
  78. package/src/styles/index.scss +1 -0
  79. package/src/stylesAndAnimations/borders/BorderColor.tsx +14 -6
  80. package/src/stylesAndAnimations/utilityClasses/UtilityClasses.mdx +24 -0
  81. package/src/stylesAndAnimations/utilityClasses/UtilityClassesData.ts +230 -0
  82. package/src/stylesAndAnimations/utilityClasses/UtilityClassesTable.stories.tsx +13 -0
  83. package/src/stylesAndAnimations/utilityClasses/UtilityClassesTable.tsx +146 -0
@@ -0,0 +1,7 @@
1
+ export type UtilityClassData = {
2
+ className: string;
3
+ css: string;
4
+ category: string;
5
+ resolvedCss?: string;
6
+ };
7
+ export declare const utilityClassesData: UtilityClassData[];
@@ -0,0 +1 @@
1
+ export declare const UtilityClassesTable: () => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { Meta, StoryObj } from '@storybook/react';
2
+ import { UtilityClassesTable } from './UtilityClassesTable';
3
+ declare const meta: Meta<typeof UtilityClassesTable>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof UtilityClassesTable>;
6
+ export declare const Default: Story;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indico-data/design-system",
3
- "version": "2.49.0",
3
+ "version": "2.51.0",
4
4
  "description": "",
5
5
  "author": "",
6
6
  "main": "lib/index.js",
@@ -39,6 +39,7 @@
39
39
  "@react-types/button": "^3.9.3",
40
40
  "@react-types/checkbox": "^3.8.1",
41
41
  "@react-types/radio": "^3.8.0",
42
+ "@tanstack/react-table": "^8.21.2",
42
43
  "@testing-library/react": "^16.0.0",
43
44
  "classnames": "^2.5.1",
44
45
  "date-fns": "^3.6.0",
@@ -0,0 +1,39 @@
1
+ import { Row, ColumnDef } from '@tanstack/react-table';
2
+
3
+ export type WithPaginationProps = {
4
+ rowsPerPage: number;
5
+ rowCount: number;
6
+ onChangePage: (page: number, perPage: number) => void;
7
+ currentPage: number;
8
+ totalEntriesText?: string;
9
+ showPagination: true;
10
+ };
11
+
12
+ export type WithoutPaginationProps = {
13
+ rowsPerPage?: number;
14
+ rowCount?: number;
15
+ onChangePage?: (page: number, perPage: number) => void;
16
+ currentPage?: number;
17
+ totalEntriesText?: string;
18
+ showPagination?: false;
19
+ };
20
+
21
+ export type PaginationProps = WithPaginationProps | WithoutPaginationProps;
22
+
23
+ export type Props<T extends object> = {
24
+ data: T[];
25
+ columns: ColumnDef<T & { id: string }>[];
26
+ className?: string;
27
+ actionBarClassName?: string;
28
+ TableActions?: React.ComponentType<{ selectedItems: Row<any>[]; unselectRows: () => void }>;
29
+ error?: {
30
+ hasError: boolean;
31
+ errorMessage?: string;
32
+ };
33
+ enableRowSelection?: boolean | ((row: Row<T>) => boolean);
34
+ clearFilters?: () => void;
35
+ hasFilters?: boolean;
36
+ isLoading?: boolean;
37
+ defaultPinnedColumns?: string[];
38
+ onClickRow?: ((row: Row<T>) => void) | null;
39
+ } & PaginationProps;
@@ -0,0 +1,122 @@
1
+ import { Canvas, Meta, Controls } from '@storybook/blocks';
2
+ import * as TableStories from './TanstackTable.stories';
3
+
4
+ <Meta title="Layout/Tanstack Table" name="TanstackTable" />
5
+
6
+ # Table
7
+
8
+ This component facilitates the rapid creation of responsive and paginated tables. It was built using the React TanStack Table library as a foundation. For more details on additional configuration options and features that are not covered in this documentation, please refer to the official TanStack Table documentation at this [link](https://tanstack.com/table/latest/docs/introduction).
9
+
10
+ <Canvas of={TableStories.Default} />
11
+
12
+ <Controls of={TableStories.Default} />
13
+
14
+ # Data Structure
15
+ These are some examples of how we would set up data for our table.
16
+
17
+ ## Data
18
+ You can define your data for your columns the following way.
19
+ ```tsx
20
+ const data = [
21
+ {
22
+ firstName: 'John',
23
+ lastName: 'Doe',
24
+ age: 28,
25
+ visits: 10,
26
+ progress: 75,
27
+ status: 'single',
28
+ id: '1',
29
+ country: 'USA',
30
+ city: 'New York',
31
+ civility: 'Mr.',
32
+ },
33
+ {
34
+ firstName: 'Jane',
35
+ lastName: 'Smith',
36
+ age: 32,
37
+ visits: 15,
38
+ progress: 50,
39
+ status: 'relationship',
40
+ id: '2',
41
+ country: 'USA',
42
+ city: 'Los Angeles',
43
+ civility: 'Ms.',
44
+ },
45
+ ];
46
+ ```
47
+
48
+ ## Headers/Columns
49
+ You can define your structure for your headers and columns in the following way.
50
+ ```tsx
51
+ const columns = [
52
+ {
53
+ id: 'select',
54
+ size: 48,
55
+ meta: {
56
+ styles: {
57
+ definedColumnSize: true,
58
+ header: {
59
+ hasNoPadding: true,
60
+ },
61
+ cell: {
62
+ hasNoPadding: true,
63
+ },
64
+ },
65
+ },
66
+ header: ({ table }) => (
67
+ <CheckboxContainer>
68
+ <Checkbox
69
+ name="select-all"
70
+ id="select-all"
71
+ label=""
72
+ isChecked={table.getIsAllPageRowsSelected()}
73
+ onChange={() => {
74
+ table
75
+ .getRowModel()
76
+ .rows.forEach((row) =>
77
+ row.toggleSelected(!table.getRowModel().rows[0].getIsSelected()),
78
+ );
79
+ }}
80
+ isDisabled={false}
81
+ aria-label="select-rows-header"
82
+ />
83
+ </CheckboxContainer>
84
+ ),
85
+ cell: ({ row }) => (
86
+ <CheckboxContainer>
87
+ <Checkbox
88
+ name="select"
89
+ id={row.id}
90
+ label=""
91
+ aria-label={`checkbox-${row.id}`}
92
+ isChecked={row.getIsSelected()}
93
+ isDisabled={!row.getCanSelect()}
94
+ onChange={row.getToggleSelectedHandler()}
95
+ />
96
+ </CheckboxContainer>
97
+ ),
98
+ },
99
+ {
100
+ id: 'firstName',
101
+ accessorKey: 'firstName',
102
+ header: ({ header }) => (
103
+ <PinHeaderColumns
104
+ content="First Name"
105
+ onPinClick={() => header.column.pin(header.column.getIsPinned() ? false : 'left')}
106
+ isPinned={header.column.getIsPinned() === 'left' ? true : false}
107
+ />
108
+ ),
109
+ cell: (info) => info.getValue(),
110
+ footer: (props) => props.column.id,
111
+ },
112
+ ...
113
+ ];
114
+
115
+ ```
116
+
117
+ # Future Upgrades
118
+ - Only pin checkboxes by defaultif the table is responsive (or has a scrollbar that requires pinning)
119
+ - More examples of table setups with code previews.
120
+ - Visual Testing.
121
+ - Prebuilt filter components for the header that follow our universal design for tables.
122
+ - Items per Page Dropdown
@@ -0,0 +1,260 @@
1
+ import { Meta, StoryObj } from '@storybook/react';
2
+
3
+ import { TanstackTable } from './TanstakTable';
4
+ import { people, Person } from './mock-data/mock-data';
5
+ import { columns } from './mock-data/table-configuration';
6
+ import { ColumnDef, Row } from '@tanstack/react-table';
7
+ import { Button } from '../button';
8
+
9
+ const meta: Meta = {
10
+ title: 'Layout/Tanstack Table',
11
+ component: TanstackTable,
12
+ args: {
13
+ data: people as (Person & { id: string })[],
14
+ columns: columns as ColumnDef<Person & { id: string }>[],
15
+ rowCount: people.length,
16
+ currentPage: 0,
17
+ rowsPerPage: 1000,
18
+ defaultPinnedColumns: ['select'],
19
+ clearFilters: () => {},
20
+ hasFilters: false,
21
+ isLoading: false,
22
+ enableRowSelection: true,
23
+ showPagination: false,
24
+ onClickRow: null,
25
+ },
26
+ argTypes: {
27
+ data: {
28
+ description:
29
+ 'Array of data items. These are the items that will be displayed in the table cell.',
30
+ control: false,
31
+ table: {
32
+ category: 'Props',
33
+ type: { summary: 'T[{}]' },
34
+ },
35
+ },
36
+ columns: {
37
+ description:
38
+ 'Column definitions including an `id` field. This is how you define your table structure.',
39
+ control: false,
40
+ table: {
41
+ category: 'Props',
42
+ type: { summary: 'ColumnDef<T & { id: string }>[]' },
43
+ },
44
+ },
45
+ className: {
46
+ description: 'Additional option for class names.',
47
+ control: false,
48
+ table: {
49
+ category: 'Props',
50
+ type: { summary: 'string' },
51
+ },
52
+ },
53
+ actionBarClassName: {
54
+ description: 'class name for styling the action bar.',
55
+ control: false,
56
+ table: {
57
+ category: 'Props',
58
+ type: { summary: 'string' },
59
+ },
60
+ },
61
+ TableActions: {
62
+ description: 'Component for table actions with selected items.',
63
+ control: false,
64
+ table: {
65
+ category: 'Props',
66
+ type: {
67
+ summary: 'React.ComponentType<{ selectedItems: Row<any>[]; unselectRows: () => void }>',
68
+ },
69
+ },
70
+ },
71
+ error: {
72
+ description: 'Error state of the table.',
73
+ control: false,
74
+ table: {
75
+ category: 'Props',
76
+ type: { summary: '{ hasError: boolean; errorMessage?: string }' },
77
+ },
78
+ },
79
+ enableRowSelection: {
80
+ description: 'Enables row selection or defines selection conditions.',
81
+ control: { type: 'boolean' },
82
+ table: {
83
+ category: 'Props',
84
+ type: { summary: 'boolean | ((row: Row<T>) => boolean)' },
85
+ },
86
+ },
87
+ clearFilters: {
88
+ description: 'Function to clear applied filters.',
89
+ action: 'clearFilters',
90
+ control: false,
91
+ table: {
92
+ category: 'Callbacks',
93
+ type: { summary: '() => void' },
94
+ },
95
+ },
96
+ hasFilters: {
97
+ description: 'Indicates if filters are applied.',
98
+ control: { type: 'boolean' },
99
+ table: {
100
+ category: 'Props',
101
+ type: { summary: 'boolean' },
102
+ defaultValue: { summary: 'false' },
103
+ },
104
+ },
105
+ isLoading: {
106
+ description: 'When this is true, the table is considered to be in a loading state.',
107
+ control: { type: 'boolean' },
108
+ table: {
109
+ category: 'Props',
110
+ type: { summary: 'boolean' },
111
+ defaultValue: { summary: 'false' },
112
+ },
113
+ },
114
+ defaultPinnedColumns: {
115
+ description: 'Columns that are pinned by default.',
116
+ control: false,
117
+ table: {
118
+ category: 'Props',
119
+ type: { summary: 'string[]' },
120
+ },
121
+ },
122
+ onClickRow: {
123
+ description: 'Callback when a row is clicked.',
124
+ action: 'onClickRow',
125
+ control: false,
126
+ table: {
127
+ category: 'Callbacks',
128
+ type: { summary: '(row: Row<T>) => void' },
129
+ },
130
+ },
131
+ showPagination: {
132
+ description: 'Toggles pagination display.',
133
+ control: { type: 'boolean' },
134
+ table: {
135
+ category: 'Props',
136
+ type: { summary: 'boolean' },
137
+ defaultValue: { summary: 'true' },
138
+ },
139
+ },
140
+ rowsPerPage: {
141
+ description: 'Number of rows to display per pagination page.',
142
+ control: { type: 'number' },
143
+ table: {
144
+ category: 'Props',
145
+ type: { summary: 'number' },
146
+ defaultValue: { summary: '1000' },
147
+ },
148
+ },
149
+ rowCount: {
150
+ description: 'Total number of rows in the table.',
151
+ control: { type: 'number' },
152
+ table: {
153
+ category: 'Props',
154
+ type: { summary: 'number' },
155
+ defaultValue: { summary: '1000' },
156
+ },
157
+ },
158
+ onChangePage: {
159
+ description: 'Callback when the page changes.',
160
+ action: 'onChangePage',
161
+ control: false,
162
+ table: {
163
+ category: 'Callbacks',
164
+ type: { summary: '(page: number, perPage: number) => void' },
165
+ },
166
+ },
167
+ currentPage: {
168
+ description: 'Current page number.',
169
+ control: { type: 'number' },
170
+ table: {
171
+ category: 'Props',
172
+ type: { summary: 'number' },
173
+ defaultValue: { summary: '1' },
174
+ },
175
+ },
176
+ totalEntriesText: {
177
+ description: 'Text to display for the total number of entries.',
178
+ control: false,
179
+ table: {
180
+ category: 'Props',
181
+ type: { summary: 'string' },
182
+ },
183
+ },
184
+ },
185
+ decorators: [
186
+ (Story) => (
187
+ <div style={{ width: '100%', height: '500px', overflow: 'hidden' }}>
188
+ <Story />
189
+ </div>
190
+ ),
191
+ ],
192
+ };
193
+
194
+ export default meta;
195
+
196
+ type Story = StoryObj<typeof TanstackTable<Person>>;
197
+
198
+ export const Default: Story = {};
199
+
200
+ export const WithRowClick: Story = {
201
+ args: {
202
+ onClickRow: (row: Row<Person>) => {
203
+ console.log(row);
204
+ },
205
+ },
206
+ };
207
+
208
+ export const PinnedColumns: Story = {
209
+ args: {
210
+ defaultPinnedColumns: ['select', 'firstName', 'lastName'],
211
+ actionBarClassName: 'tanstack-table__action-bar-test',
212
+ },
213
+ render: (args) => (
214
+ <div style={{ width: '700px', height: '500px', overflow: 'hidden' }}>
215
+ <TanstackTable<Person> {...args} />
216
+ </div>
217
+ ),
218
+ };
219
+
220
+ export const WithTableActions: Story = {
221
+ args: {
222
+ TableActions: () => <Button ariaLabel="Actions">Actions</Button>,
223
+ },
224
+ };
225
+
226
+ export const NoResults: Story = {
227
+ args: {
228
+ data: [],
229
+ },
230
+ };
231
+
232
+ export const NoResultsWithFilters: Story = {
233
+ args: {
234
+ data: [],
235
+ hasFilters: true,
236
+ },
237
+ };
238
+
239
+ export const IsLoading: Story = {
240
+ args: {
241
+ isLoading: true,
242
+ data: [],
243
+ },
244
+ };
245
+
246
+ export const IsLoadingWithData: Story = {
247
+ args: {
248
+ isLoading: true,
249
+ },
250
+ };
251
+
252
+ export const WithPagination: Story = {
253
+ args: {
254
+ showPagination: true,
255
+ rowCount: people.length,
256
+ currentPage: 1,
257
+ rowsPerPage: 20,
258
+ onChangePage: () => {},
259
+ },
260
+ };
@@ -0,0 +1,157 @@
1
+ import { useEffect, useRef } from 'react';
2
+
3
+ import { useReactTable, getCoreRowModel, ColumnDef } from '@tanstack/react-table';
4
+ import classNames from 'classnames';
5
+
6
+ import { ActionBar } from './components/ActionBar';
7
+ import { NoResults } from './components/NoResults';
8
+ import { isNil } from 'lodash';
9
+ import { TablePagination } from './components/TablePagination';
10
+ import { Props } from './TankstackTable.types';
11
+ import { useTanstackTable } from './useTanstackTable';
12
+ import { TableHeader } from './components/TableHeader';
13
+ import { TableBody } from './components/TableBody';
14
+
15
+ export function TanstackTable<T extends object>({
16
+ columns: defaultColumns,
17
+ data,
18
+ className,
19
+ currentPage,
20
+ rowCount,
21
+ rowsPerPage = 1000,
22
+ onChangePage,
23
+ totalEntriesText,
24
+ TableActions,
25
+ error,
26
+ enableRowSelection = true,
27
+ clearFilters,
28
+ hasFilters,
29
+ showPagination = true,
30
+ isLoading = false,
31
+ defaultPinnedColumns,
32
+ onClickRow = null,
33
+ actionBarClassName,
34
+ }: Props<T & { id: string }>) {
35
+ const {
36
+ columns,
37
+ defaultData,
38
+ windowWidth,
39
+ rowSelection,
40
+ setRowSelection,
41
+ formattedColumns,
42
+ setFormattedColumns,
43
+ isClickedRow,
44
+ setIsClickedRow,
45
+ } = useTanstackTable({
46
+ defaultColumns,
47
+ });
48
+
49
+ const thRefs = useRef<Record<string, HTMLTableCellElement | null>>({});
50
+
51
+ // Sets formattedColumns with correct column widths
52
+ useEffect(() => {
53
+ const updatedColumns: ColumnDef<T & { id: string }>[] = [];
54
+
55
+ formattedColumns.forEach((column) => {
56
+ const columnWidth = thRefs.current[column.id as keyof typeof thRefs.current]!.offsetWidth;
57
+
58
+ updatedColumns.push({
59
+ ...column,
60
+ size: columnWidth,
61
+ });
62
+ });
63
+ setFormattedColumns(updatedColumns);
64
+ }, [data, columns, windowWidth]);
65
+
66
+ const table = useReactTable({
67
+ data: data ?? defaultData,
68
+ columns: formattedColumns,
69
+ state: {
70
+ rowSelection,
71
+ },
72
+ enableRowSelection,
73
+ onRowSelectionChange: setRowSelection,
74
+ getCoreRowModel: getCoreRowModel(),
75
+ manualPagination: true,
76
+ debugTable: true,
77
+ initialState: {
78
+ columnPinning: {
79
+ left: defaultPinnedColumns,
80
+ },
81
+ },
82
+ });
83
+
84
+ const totalRowsOnPage = table.getRowModel().rows.length;
85
+ const hasPaginationProps =
86
+ !isNil(currentPage) &&
87
+ !isNil(rowCount) &&
88
+ !isNil(totalRowsOnPage) &&
89
+ onChangePage !== undefined;
90
+
91
+ const hasSelectedRows = Object.keys(rowSelection).length > 0;
92
+
93
+ const hasErrorAndIsNotLoading = error?.hasError && !isLoading;
94
+ const hasNoResults = data.length === 0 && !isLoading;
95
+ const shouldRenderPagination = showPagination && hasPaginationProps;
96
+
97
+ const renderBody = () => {
98
+ if (hasErrorAndIsNotLoading || hasNoResults) {
99
+ return (
100
+ <tr className="tanstack-table__tbody__tr">
101
+ <td className="tanstack-table__centered-row" colSpan={columns.length}>
102
+ <NoResults
103
+ clearFilters={clearFilters}
104
+ hasFilters={hasFilters}
105
+ message={
106
+ hasErrorAndIsNotLoading
107
+ ? error?.errorMessage ?? 'There was an error isLoading the data.'
108
+ : 'No results found.'
109
+ }
110
+ />
111
+ </td>
112
+ </tr>
113
+ );
114
+ }
115
+
116
+ return (
117
+ <TableBody<T & { id: string }>
118
+ table={table}
119
+ onClickRow={onClickRow}
120
+ isLoading={isLoading}
121
+ columnsLength={columns.length}
122
+ isClickedRow={isClickedRow}
123
+ setIsClickedRow={setIsClickedRow}
124
+ />
125
+ );
126
+ };
127
+
128
+ return (
129
+ <div className="tanstack-table__outer-container">
130
+ <div className="tanstack-table__container">
131
+ <table
132
+ className={classNames('tanstack-table', className, {
133
+ 'is-Loading': isLoading,
134
+ })}
135
+ >
136
+ <thead className="tanstack-table__thead">
137
+ <TableHeader table={table} ref={thRefs} />
138
+ </thead>
139
+ <tbody className="tanstack-table__tbody">{renderBody()}</tbody>
140
+ </table>
141
+
142
+ {hasSelectedRows && (
143
+ <ActionBar table={table} TableActions={TableActions} className={actionBarClassName} />
144
+ )}
145
+ </div>
146
+ {shouldRenderPagination ? (
147
+ <TablePagination
148
+ currentPage={currentPage}
149
+ rowCount={rowCount}
150
+ onChangePage={onChangePage}
151
+ rowsPerPage={rowsPerPage}
152
+ totalEntriesText={totalEntriesText ?? `${totalRowsOnPage} of ${rowCount} entries`}
153
+ />
154
+ ) : null}
155
+ </div>
156
+ );
157
+ }
@@ -0,0 +1,87 @@
1
+ import { render, screen, fireEvent } from '@testing-library/react';
2
+ import '@testing-library/jest-dom';
3
+ import { TanstackTable } from '../TanstakTable';
4
+ import { data, columns } from './__mocks__/test-mock-data';
5
+
6
+ describe('Tanstack Table Component', () => {
7
+ test('renders the table with provided data', () => {
8
+ render(<TanstackTable columns={columns} data={data} />);
9
+ expect(screen.getByText('Name')).toBeInTheDocument();
10
+ expect(screen.getByText('Age')).toBeInTheDocument();
11
+ expect(screen.getByText('Alice')).toBeInTheDocument();
12
+ expect(screen.getByText('Bob')).toBeInTheDocument();
13
+ });
14
+
15
+ test('displays loading state when loading is true', () => {
16
+ render(<TanstackTable columns={columns} data={[]} isLoading={true} />);
17
+ expect(screen.getByTestId('loading-indicator')).toBeInTheDocument();
18
+ });
19
+
20
+ test('shows error message when error exists', () => {
21
+ render(
22
+ <TanstackTable
23
+ columns={columns}
24
+ data={[]}
25
+ error={{ hasError: true, errorMessage: 'Failed to load data' }}
26
+ />,
27
+ );
28
+ expect(screen.getByText('Failed to load data')).toBeInTheDocument();
29
+ });
30
+
31
+ test('handles click on checkbox to select row', () => {
32
+ render(<TanstackTable columns={columns} data={data} enableRowSelection={true} />);
33
+ const indexRow = 0;
34
+ const firstCheckbox = screen.getByTestId(`checkbox-${indexRow}`);
35
+ fireEvent.click(firstCheckbox);
36
+ const firstRow = screen.getByText(data[indexRow].name).closest('tr');
37
+ expect(firstRow).toHaveClass('is-selected');
38
+ });
39
+
40
+ test('handles click on a row with onClickRow property', () => {
41
+ const onClickRow = jest.fn();
42
+ render(
43
+ <TanstackTable
44
+ columns={columns}
45
+ data={data}
46
+ enableRowSelection={true}
47
+ onClickRow={onClickRow}
48
+ />,
49
+ );
50
+ const firstRow = screen.getByText(data[0].name);
51
+ fireEvent.click(firstRow);
52
+ expect(onClickRow).toHaveBeenCalled();
53
+ });
54
+
55
+ test('renders pagination when showPagination is true', () => {
56
+ render(
57
+ <TanstackTable
58
+ columns={columns}
59
+ data={data}
60
+ currentPage={1}
61
+ rowCount={10}
62
+ rowsPerPage={5}
63
+ onChangePage={jest.fn()}
64
+ showPagination={true}
65
+ />,
66
+ );
67
+ expect(screen.getByTestId('tanstack-table-pagination')).toBeInTheDocument();
68
+ });
69
+
70
+ test('renders No Result when data is empty', () => {
71
+ render(
72
+ <TanstackTable
73
+ columns={columns}
74
+ data={[]}
75
+ currentPage={1}
76
+ rowCount={10}
77
+ rowsPerPage={5}
78
+ onChangePage={jest.fn()}
79
+ showPagination={true}
80
+ />,
81
+ );
82
+ expect(screen.getByTestId('tanstack-table-no-results')).toBeInTheDocument();
83
+ });
84
+ });
85
+
86
+ // may require visual testing
87
+ it.todo('Test pinned columns');