@indico-data/design-system 2.50.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 (73) 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 +247 -0
  28. package/lib/index.d.ts +62 -17
  29. package/lib/index.esm.css +247 -0
  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/package.json +2 -1
  35. package/src/components/tanstackTable/TankstackTable.types.ts +39 -0
  36. package/src/components/tanstackTable/TanstackTable.mdx +122 -0
  37. package/src/components/tanstackTable/TanstackTable.stories.tsx +260 -0
  38. package/src/components/tanstackTable/TanstakTable.tsx +157 -0
  39. package/src/components/tanstackTable/__tests__/TanstackTable.test.tsx +87 -0
  40. package/src/components/tanstackTable/__tests__/__mocks__/test-mock-data.tsx +83 -0
  41. package/src/components/tanstackTable/components/ActionBar/ActionBar.mdx +10 -0
  42. package/src/components/tanstackTable/components/ActionBar/ActionBar.scss +30 -0
  43. package/src/components/tanstackTable/components/ActionBar/ActionBar.stories.tsx +98 -0
  44. package/src/components/tanstackTable/components/ActionBar/ActionBar.tsx +51 -0
  45. package/src/components/tanstackTable/components/ActionBar/__tests__/ActionBar.test.tsx +87 -0
  46. package/src/components/tanstackTable/components/ActionBar/index.ts +1 -0
  47. package/src/components/tanstackTable/components/NoResults/NoResults.scss +24 -0
  48. package/src/components/tanstackTable/components/NoResults/NoResults.tsx +22 -0
  49. package/src/components/tanstackTable/components/NoResults/__tests__/NoResult.test.tsx +25 -0
  50. package/src/components/tanstackTable/components/NoResults/index.ts +1 -0
  51. package/src/components/tanstackTable/components/TableBody/TableBody.tsx +87 -0
  52. package/src/components/tanstackTable/components/TableBody/index.ts +1 -0
  53. package/src/components/tanstackTable/components/TableHeader/TableHeader.tsx +49 -0
  54. package/src/components/tanstackTable/components/TableHeader/index.ts +1 -0
  55. package/src/components/tanstackTable/components/TablePagination/TablePagination.tsx +45 -0
  56. package/src/components/tanstackTable/components/TablePagination/__tests__/TablePagination.test.tsx +18 -0
  57. package/src/components/tanstackTable/components/TablePagination/index.ts +1 -0
  58. package/src/components/tanstackTable/docs/pinnedColumns/PinnedColumn.mdx +34 -0
  59. package/src/components/tanstackTable/docs/pinnedColumns/PinnedColumn.stories.tsx +40 -0
  60. package/src/components/tanstackTable/docs/withRowClick/WithRowClick.mdx +48 -0
  61. package/src/components/tanstackTable/docs/withRowClick/WithRowClick.stories.tsx +32 -0
  62. package/src/components/tanstackTable/helpers.ts +45 -0
  63. package/src/components/tanstackTable/index.ts +2 -0
  64. package/src/components/tanstackTable/mock-data/mock-data.ts +256 -0
  65. package/src/components/tanstackTable/mock-data/table-configuration.tsx +219 -0
  66. package/src/components/tanstackTable/styles/_variables.scss +35 -0
  67. package/src/components/tanstackTable/styles/table.scss +204 -0
  68. package/src/components/tanstackTable/styles/test.scss +19 -0
  69. package/src/components/tanstackTable/tanstack-table.d.ts +18 -0
  70. package/src/components/tanstackTable/useTanstackTable.tsx +42 -0
  71. package/src/index.ts +1 -0
  72. package/src/legacy/components/loading-indicators/CirclePulse/CirclePulse.tsx +1 -0
  73. package/src/styles/index.scss +1 -0
@@ -0,0 +1,83 @@
1
+ import { Checkbox } from "@/components/forms/checkbox";
2
+ import { ColumnDef } from "@tanstack/react-table";
3
+
4
+ export interface TestData {
5
+ id: string;
6
+ name: string;
7
+ age: number;
8
+ }
9
+
10
+ export const columns: ColumnDef<TestData>[] = [
11
+ {
12
+ id: 'select',
13
+ size: 48,
14
+ meta: {
15
+ styles: {
16
+ definedColumnSize: true,
17
+ header: {
18
+ hasNoPadding: true,
19
+ },
20
+ cell: {
21
+ hasNoPadding: true,
22
+ },
23
+ },
24
+ },
25
+ header: ({ table }) => (
26
+ <div className="p-3">
27
+ <Checkbox
28
+ name="select-all"
29
+ id="select-all"
30
+ label=""
31
+ isChecked={table.getIsAllPageRowsSelected()}
32
+ onChange={() => {
33
+ table
34
+ .getRowModel()
35
+ .rows.forEach((row) =>
36
+ row.toggleSelected(!table.getRowModel().rows[0].getIsSelected()),
37
+ );
38
+ }}
39
+ isDisabled={false}
40
+ aria-label="select-rows-header"
41
+ />
42
+ </div>
43
+ ),
44
+ cell: ({ row }) => (
45
+ <div className="p-3">
46
+ <Checkbox
47
+ name="select"
48
+ id={row.id}
49
+ label=""
50
+ data-testid={`checkbox-${row.id}`}
51
+ aria-label={`checkbox-${row.id}`}
52
+ isChecked={row.getIsSelected()}
53
+ isDisabled={!row.getCanSelect()}
54
+ onChange={row.getToggleSelectedHandler()}
55
+ />
56
+ </div>
57
+ ),
58
+ },
59
+ {
60
+ id: 'firstName',
61
+ accessorKey: 'firstName',
62
+ header: () => 'First Name',
63
+ cell: (info) => info.getValue(),
64
+ footer: (props) => props.column.id,
65
+ },
66
+ {
67
+ id: 'name',
68
+ accessorKey: 'name',
69
+ header: 'Name',
70
+ cell: ({ getValue }) => getValue(),
71
+ },
72
+ {
73
+ id: 'age',
74
+ accessorKey: 'age',
75
+ header: 'Age',
76
+ cell: ({ getValue }) => getValue(),
77
+ },
78
+ ];
79
+
80
+ export const data: TestData[] = [
81
+ { id: '1', name: 'Alice', age: 30 },
82
+ { id: '2', name: 'Bob', age: 25 },
83
+ ];
@@ -0,0 +1,10 @@
1
+ import { Canvas, Meta, Controls } from '@storybook/blocks';
2
+ import * as ActionBarStories from './ActionBar.stories';
3
+
4
+ <Meta title="Layout/Tanstack Table/Action Bar" name="ActionBar" />
5
+
6
+ # Table
7
+
8
+ <Canvas of={ActionBarStories.Default} />
9
+
10
+ <Controls of={ActionBarStories.Default} />
@@ -0,0 +1,30 @@
1
+ .tanstack-table__action-bar {
2
+ position: fixed;
3
+ bottom: 170px;
4
+ left: 50%;
5
+ transform: translateX(-50%);
6
+ z-index: 90;
7
+
8
+ &__container {
9
+ display: flex;
10
+ align-items: center;
11
+ gap: var(--pf-size-2);
12
+ }
13
+
14
+ &__text-container {
15
+ padding: var(--pf-padding-2);
16
+
17
+ span {
18
+ font-size: var(--pf-font-size-base);
19
+ font-weight: var(--pf-font-weight-medium);
20
+ line-height: var(--pf-line-height-lg);
21
+ color: var(--pf-white-color);
22
+ }
23
+ }
24
+
25
+ &__button-container {
26
+ display: flex;
27
+ align-items: center;
28
+ gap: var(--pf-size-4);
29
+ }
30
+ }
@@ -0,0 +1,98 @@
1
+ import { Meta, StoryObj } from '@storybook/react';
2
+ import { ActionBar } from './ActionBar';
3
+ import { Table } from '@tanstack/react-table';
4
+ import { Button } from '@/components/button';
5
+
6
+ type DummyRow = {
7
+ id: string;
8
+ isSelected: boolean;
9
+ getIsSelected: () => boolean;
10
+ toggleSelected: (value: boolean) => void;
11
+ };
12
+
13
+ const createDummyRow = (id: string, isSelected = false): DummyRow => ({
14
+ id,
15
+ isSelected,
16
+ getIsSelected() {
17
+ return this.isSelected;
18
+ },
19
+ toggleSelected(value: boolean) {
20
+ this.isSelected = value;
21
+ },
22
+ });
23
+
24
+ const dummyTable = {
25
+ getRowModel: () => ({
26
+ rows: [createDummyRow('1', true), createDummyRow('2', false), createDummyRow('3', true)],
27
+ }),
28
+ } as unknown as Table<{ id: string }>;
29
+
30
+ const meta: Meta = {
31
+ title: 'Layout/Tanstack Table/Action Bar',
32
+ component: ActionBar,
33
+ args: {
34
+ className: 'tanstack-table__action-bar-docs',
35
+ table: dummyTable,
36
+ },
37
+ argTypes: {
38
+ table: {
39
+ description: 'Table instance.',
40
+ control: false,
41
+ table: {
42
+ category: 'Props',
43
+ type: { summary: 'Table<any>' },
44
+ },
45
+ },
46
+ className: {
47
+ description: 'class name for styling.',
48
+ control: false,
49
+ table: {
50
+ category: 'Props',
51
+ type: { summary: 'string' },
52
+ },
53
+ },
54
+ children: {
55
+ description: 'React node to display in the action bar.',
56
+ control: false,
57
+ table: {
58
+ category: 'Props',
59
+ type: { summary: 'React.ReactNode' },
60
+ },
61
+ },
62
+ TableActions: {
63
+ description: 'Component for table actions with selected items.',
64
+ control: false,
65
+ table: {
66
+ category: 'Props',
67
+ type: {
68
+ summary: 'React.ComponentType<{ selectedItems: Row<any>[]; unselectRows: () => void }>',
69
+ },
70
+ },
71
+ },
72
+ },
73
+ decorators: [
74
+ (Story) => (
75
+ <div style={{ width: '100%', height: '500px', overflow: 'hidden' }}>
76
+ <Story />
77
+ </div>
78
+ ),
79
+ ],
80
+ };
81
+
82
+ export default meta;
83
+
84
+ type Story = StoryObj<typeof ActionBar<{ id: string }>>;
85
+
86
+ export const Default: Story = {};
87
+
88
+ export const WithCustomTableActions: Story = {
89
+ args: {
90
+ TableActions: () => <Button ariaLabel="Clear">Clear</Button>,
91
+ },
92
+ };
93
+
94
+ export const WithChildren: Story = {
95
+ args: {
96
+ children: <p>test</p>,
97
+ },
98
+ };
@@ -0,0 +1,51 @@
1
+ import React from 'react';
2
+ import { Row, Table } from '@tanstack/react-table';
3
+ import { Card } from '@/components/card';
4
+ import classNames from 'classnames';
5
+
6
+ type Props<T extends object> = {
7
+ table: Table<T & { id: string }>;
8
+ TableActions?: React.ComponentType<{
9
+ selectedItems: Row<T & { id: string }>[];
10
+ unselectRows: () => void;
11
+ }>;
12
+ className?: string;
13
+ children?: React.ReactNode;
14
+ };
15
+
16
+ export function ActionBar<T extends object>({
17
+ table,
18
+ TableActions,
19
+ className,
20
+ children,
21
+ }: Props<T>) {
22
+ const selectedItems = table.getRowModel().rows.filter((row) => row.getIsSelected());
23
+
24
+ const unselectRows = () => {
25
+ table.getRowModel().rows.forEach((row) => {
26
+ row.toggleSelected(false);
27
+ });
28
+ };
29
+
30
+ const getSelectedItemsText = () => {
31
+ if (selectedItems.length === 1) return '1 item selected';
32
+ return `${selectedItems.length} items selected`;
33
+ };
34
+
35
+ return (
36
+ <Card className={classNames('tanstack-table__action-bar', className)}>
37
+ {children ?? (
38
+ <div className="tanstack-table__action-bar__container">
39
+ <div className="tanstack-table__action-bar__text-container">
40
+ <span>{getSelectedItemsText()}</span>
41
+ </div>
42
+ {TableActions && (
43
+ <div className="tanstack-table__action-bar__button-container">
44
+ <TableActions selectedItems={selectedItems} unselectRows={unselectRows} />
45
+ </div>
46
+ )}
47
+ </div>
48
+ )}
49
+ </Card>
50
+ );
51
+ }
@@ -0,0 +1,87 @@
1
+ import React from 'react';
2
+ import { render, screen, fireEvent } from '@testing-library/react';
3
+ import { ActionBar } from '../ActionBar';
4
+ import type { Table } from '@tanstack/react-table';
5
+
6
+ type DummyRow = {
7
+ getIsSelected: () => boolean;
8
+ toggleSelected: (value: boolean) => void;
9
+ };
10
+
11
+ const createDummyTable = (rows: DummyRow[]): Table<any> =>
12
+ ({
13
+ getRowModel: () => ({ rows }),
14
+ }) as Table<any>;
15
+
16
+ describe('ActionBar', () => {
17
+ it('renders correct text for one selected row', () => {
18
+ const dummyRows: DummyRow[] = [
19
+ { getIsSelected: () => true, toggleSelected: jest.fn() },
20
+ { getIsSelected: () => false, toggleSelected: jest.fn() },
21
+ ];
22
+ const dummyTable = createDummyTable(dummyRows);
23
+
24
+ render(<ActionBar table={dummyTable} />);
25
+ expect(screen.getByText('1 item selected')).toBeDefined();
26
+ });
27
+
28
+ it('renders correct text for multiple selected rows', () => {
29
+ const dummyRows: DummyRow[] = [
30
+ { getIsSelected: () => true, toggleSelected: jest.fn() },
31
+ { getIsSelected: () => true, toggleSelected: jest.fn() },
32
+ ];
33
+ const dummyTable = createDummyTable(dummyRows);
34
+
35
+ render(<ActionBar table={dummyTable} />);
36
+ expect(screen.getByText('2 items selected')).toBeDefined();
37
+ });
38
+
39
+ it('renders correct when use a children prop', () => {
40
+ const dummyRows: DummyRow[] = [
41
+ { getIsSelected: () => true, toggleSelected: jest.fn() },
42
+ { getIsSelected: () => true, toggleSelected: jest.fn() },
43
+ ];
44
+ const dummyTable = createDummyTable(dummyRows);
45
+
46
+ render(
47
+ <ActionBar table={dummyTable}>
48
+ <div>
49
+ <p>Hello</p>
50
+ </div>
51
+ </ActionBar>,
52
+ );
53
+ expect(screen.getByText('Hello')).toBeDefined();
54
+ });
55
+
56
+ it('renders TableActions component when provided and calls unselectRows', () => {
57
+ const toggleRow1 = jest.fn();
58
+ const toggleRow2 = jest.fn();
59
+ const dummyRows: DummyRow[] = [
60
+ { getIsSelected: () => true, toggleSelected: toggleRow1 },
61
+ { getIsSelected: () => true, toggleSelected: toggleRow2 },
62
+ ];
63
+ const dummyTable = createDummyTable(dummyRows);
64
+
65
+ // Dummy TableActions component which calls unselectRows on button click
66
+ const DummyTableActions: React.FC<{
67
+ selectedItems: DummyRow[];
68
+ unselectRows: () => void;
69
+ }> = ({ selectedItems, unselectRows }) => (
70
+ <button onClick={unselectRows} data-testid="dummy-actions">
71
+ Clear Selection ({selectedItems.length})
72
+ </button>
73
+ );
74
+
75
+ render(<ActionBar table={dummyTable} TableActions={DummyTableActions as any} />);
76
+ const button = screen.getByTestId('dummy-actions');
77
+ expect(button).toBeDefined();
78
+ expect(button.textContent).toContain('2');
79
+
80
+ // Simulate click on the TableActions button
81
+ fireEvent.click(button);
82
+
83
+ // Verify unselectRows toggles all selected rows to false
84
+ expect(toggleRow1).toHaveBeenCalledWith(false);
85
+ expect(toggleRow2).toHaveBeenCalledWith(false);
86
+ });
87
+ });
@@ -0,0 +1 @@
1
+ export { ActionBar } from './ActionBar';
@@ -0,0 +1,24 @@
1
+ .tanstack-table__no-results {
2
+ display: flex;
3
+ justify-content: center;
4
+ flex-direction: column;
5
+ align-items: center;
6
+
7
+ position: sticky;
8
+ left: 0;
9
+ margin: var(--pf-margin-8) auto;
10
+
11
+ &__text {
12
+ font-size: var(--pf-line-height-md);
13
+ font-weight: var(--pf-font-weight-medium);
14
+ color: var(--pf-primary-color-50);
15
+
16
+ span {
17
+ color: var(--pf-white-color);
18
+ cursor: pointer;
19
+ &:hover {
20
+ text-decoration: underline;
21
+ }
22
+ }
23
+ }
24
+ }
@@ -0,0 +1,22 @@
1
+ import { Button } from '@/components/button/Button';
2
+
3
+ type Props = {
4
+ clearFilters?: () => void;
5
+ hasFilters?: boolean;
6
+ message: string;
7
+ };
8
+
9
+ export function NoResults({ clearFilters, hasFilters, message }: Props) {
10
+ return (
11
+ <div className="tanstack-table__no-results" data-testid="tanstack-table-no-results">
12
+ <p className="tanstack-table__no-results__text">{message}</p>
13
+ {hasFilters && (
14
+ <p className="tanstack-table__no-results__text">
15
+ <Button ariaLabel="Reset filters" variant="link" onClick={clearFilters}>
16
+ Reset filters
17
+ </Button>
18
+ </p>
19
+ )}
20
+ </div>
21
+ );
22
+ }
@@ -0,0 +1,25 @@
1
+ import { render, screen, fireEvent } from '@testing-library/react';
2
+ import { NoResults } from '../NoResults';
3
+
4
+ describe('NoResults Component', () => {
5
+ it('renders the message without filters applied', () => {
6
+ render(<NoResults message="No results found." />);
7
+ expect(screen.getByText('No results found.')).toBeInTheDocument();
8
+ expect(screen.queryByText('Reset filters')).not.toBeInTheDocument();
9
+ });
10
+
11
+ it('renders the clear filters option when filters are applied', () => {
12
+ render(<NoResults message="No results found." hasFilters />);
13
+ expect(screen.getByText('No results found.')).toBeInTheDocument();
14
+ const clearFiltersElement = screen.getByText('Reset filters');
15
+ expect(clearFiltersElement).toBeInTheDocument();
16
+ });
17
+
18
+ it('calls clearFilters when "Click here" is clicked', () => {
19
+ const mockClearFilters = jest.fn();
20
+ render(<NoResults message="No results found." hasFilters clearFilters={mockClearFilters} />);
21
+ const clearFiltersElement = screen.getByText('Reset filters');
22
+ fireEvent.click(clearFiltersElement);
23
+ expect(mockClearFilters).toHaveBeenCalled();
24
+ });
25
+ });
@@ -0,0 +1 @@
1
+ export { NoResults } from './NoResults';
@@ -0,0 +1,87 @@
1
+ import { flexRender, Table } from '@tanstack/react-table';
2
+ import { Row } from '@tanstack/react-table';
3
+ import classNames from 'classnames';
4
+ import { getTdStyles } from '../../helpers';
5
+ import { CirclePulse } from '@/legacy/components/loading-indicators/CirclePulse';
6
+ import { Dispatch, SetStateAction } from 'react';
7
+
8
+ export type Props<T> = {
9
+ table: Table<T>;
10
+ onClickRow?: ((row: Row<T>) => void) | null;
11
+ isLoading: boolean;
12
+ columnsLength: number;
13
+ isClickedRow: string[];
14
+ setIsClickedRow: Dispatch<SetStateAction<string[]>>;
15
+ };
16
+
17
+ export const TableBody = <T,>({
18
+ table,
19
+ onClickRow,
20
+ isLoading,
21
+ columnsLength,
22
+ isClickedRow,
23
+ setIsClickedRow,
24
+ }: Props<T>) => {
25
+ const toggleRow = (id: string) => {
26
+ if (isClickedRow.includes(id)) {
27
+ setIsClickedRow((state) => state.filter((item) => item !== id));
28
+ } else {
29
+ setIsClickedRow((state) => [...state, id]);
30
+ }
31
+ };
32
+
33
+ return (
34
+ <>
35
+ {table.getRowModel().rows.map((row) => (
36
+ <tr
37
+ className={classNames('tanstack-table__tbody__tr', {
38
+ 'is-selected': row.getIsSelected(),
39
+ 'show-hover': !!onClickRow,
40
+ 'is-clicked': isClickedRow.includes(row.id),
41
+ })}
42
+ key={row.id}
43
+ onClick={() => {
44
+ if (!!onClickRow) {
45
+ toggleRow(row.id);
46
+ onClickRow(row);
47
+ }
48
+ }}
49
+ >
50
+ {row.getVisibleCells().map((cell) => {
51
+ const { columnDef } = cell.column;
52
+ return (
53
+ <td
54
+ className={classNames('tanstack-table__tbody__td', {
55
+ 'pa-0': !!columnDef.meta?.styles?.cell?.hasNoPadding,
56
+ })}
57
+ key={cell.id}
58
+ style={{
59
+ ...getTdStyles(
60
+ cell.column,
61
+ columnDef.meta?.styles?.cell?.textAlign,
62
+ columnDef.meta?.styles?.definedColumnSize,
63
+ cell.column.getSize(),
64
+ ),
65
+ }}
66
+ >
67
+ {flexRender(columnDef.cell, cell.getContext())}
68
+ </td>
69
+ );
70
+ })}
71
+ </tr>
72
+ ))}
73
+ {isLoading && (
74
+ <tr className="tanstack-table__tbody__tr">
75
+ <td
76
+ className={classNames('tanstack-table__centered-row', {
77
+ 'is-Loading': isLoading,
78
+ })}
79
+ colSpan={columnsLength}
80
+ >
81
+ <CirclePulse data-testid="loading-indicator" />
82
+ </td>
83
+ </tr>
84
+ )}
85
+ </>
86
+ );
87
+ };
@@ -0,0 +1 @@
1
+ export { TableBody } from './TableBody';
@@ -0,0 +1,49 @@
1
+ import { forwardRef } from 'react';
2
+ import { Column, flexRender, Header, Table } from '@tanstack/react-table';
3
+ import classNames from 'classnames';
4
+ import { getThStyles } from '../../helpers';
5
+
6
+ interface Props {
7
+ table: Table<any>;
8
+ }
9
+
10
+ export const TableHeader = forwardRef(({ table }: Props, ref: any) => {
11
+ const getStyles = (column: Column<any>, header: Header<any, any>) => {
12
+ return {
13
+ ...getThStyles(column),
14
+ ...(header.column.columnDef.meta?.styles?.header?.textAlign
15
+ ? { textAlign: header.column.columnDef.meta?.styles?.header?.textAlign }
16
+ : {}),
17
+ };
18
+ };
19
+
20
+ return (
21
+ <>
22
+ {table.getHeaderGroups().map((headerGroup) => (
23
+ <tr key={headerGroup.id}>
24
+ {headerGroup.headers.map((header) => {
25
+ const { column } = header;
26
+
27
+ return (
28
+ <th
29
+ className={classNames('tanstack-table__thead__th', {
30
+ 'pa-0': !!header.column.columnDef.meta?.styles?.header?.hasNoPadding,
31
+ })}
32
+ key={header.id}
33
+ ref={(el: any) => {
34
+ if (el) ref.current[column.id] = el;
35
+ }}
36
+ colSpan={header.colSpan}
37
+ style={{
38
+ ...getStyles(column, header),
39
+ }}
40
+ >
41
+ {flexRender(header.column.columnDef.header, header.getContext())}
42
+ </th>
43
+ );
44
+ })}
45
+ </tr>
46
+ ))}
47
+ </>
48
+ );
49
+ });
@@ -0,0 +1 @@
1
+ export { TableHeader } from './TableHeader';
@@ -0,0 +1,45 @@
1
+ import { Pagination as PaginationComponent } from '../../../pagination';
2
+ import { Row, Col } from '../../../grid';
3
+
4
+ interface TablePaginationProps {
5
+ rowsPerPage: number;
6
+ rowCount: number;
7
+ onChangePage: (page: number, perPage: number) => void;
8
+ currentPage: number;
9
+ totalEntriesText?: string;
10
+ }
11
+
12
+ export const TablePagination = ({
13
+ rowsPerPage,
14
+ rowCount,
15
+ onChangePage,
16
+ currentPage,
17
+ totalEntriesText,
18
+ }: TablePaginationProps) => {
19
+ const totalPages = Math.ceil(rowCount / rowsPerPage);
20
+
21
+ return (
22
+ <div className="table__pagination" data-testid="tanstack-table-pagination">
23
+ <Row align="center" justify="between">
24
+ <Col xs="content">
25
+ {totalEntriesText && (
26
+ <span
27
+ data-testid="table-pagination-total-entries"
28
+ className="table__pagination-total-entries"
29
+ >
30
+ {totalEntriesText}
31
+ </span>
32
+ )}
33
+ </Col>
34
+ <Col xs="content">
35
+ <PaginationComponent
36
+ data-testid="table-pagination-component"
37
+ totalPages={totalPages}
38
+ currentPage={currentPage}
39
+ onChange={(page) => onChangePage(page, rowsPerPage)}
40
+ />
41
+ </Col>
42
+ </Row>
43
+ </div>
44
+ );
45
+ };
@@ -0,0 +1,18 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import { TablePagination } from '../TablePagination';
3
+
4
+ describe('TablePagination', () => {
5
+ it('renders total entries text', () => {
6
+ render(
7
+ <TablePagination
8
+ rowsPerPage={10}
9
+ rowCount={100}
10
+ onChangePage={() => {}}
11
+ currentPage={1}
12
+ totalEntriesText="100 entries"
13
+ />,
14
+ );
15
+ expect(screen.getByTestId('table-pagination-total-entries')).toBeInTheDocument();
16
+ expect(screen.getByTestId('tanstack-table-pagination')).toBeInTheDocument();
17
+ });
18
+ });
@@ -0,0 +1 @@
1
+ export * from './TablePagination';