@patternfly/react-table 4.44.10 → 4.44.14

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 (69) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/esm/components/Table/Table.d.ts +2 -1
  3. package/dist/esm/components/Table/Table.d.ts.map +1 -1
  4. package/dist/esm/components/Table/Table.js.map +1 -1
  5. package/dist/esm/components/Table/TableTypes.d.ts +2 -1
  6. package/dist/esm/components/Table/TableTypes.d.ts.map +1 -1
  7. package/dist/esm/components/Table/TableTypes.js.map +1 -1
  8. package/dist/esm/components/Table/base/provider.d.ts +2 -2
  9. package/dist/esm/components/Table/base/types.d.ts +2 -2
  10. package/dist/esm/components/TableComposable/TableComposable.d.ts +1 -1
  11. package/dist/esm/components/TableComposable/Td.d.ts +1 -1
  12. package/dist/js/components/Table/Table.d.ts +2 -1
  13. package/dist/js/components/Table/Table.d.ts.map +1 -1
  14. package/dist/js/components/Table/Table.js.map +1 -1
  15. package/dist/js/components/Table/TableTypes.d.ts +2 -1
  16. package/dist/js/components/Table/TableTypes.d.ts.map +1 -1
  17. package/dist/js/components/Table/TableTypes.js.map +1 -1
  18. package/dist/js/components/Table/base/provider.d.ts +2 -2
  19. package/dist/js/components/Table/base/types.d.ts +2 -2
  20. package/dist/js/components/TableComposable/TableComposable.d.ts +1 -1
  21. package/dist/js/components/TableComposable/Td.d.ts +1 -1
  22. package/dist/umd/react-table.css +5 -3
  23. package/dist/umd/react-table.min.css +17 -15
  24. package/package.json +6 -6
  25. package/src/components/Table/Table.tsx +2 -1
  26. package/src/components/Table/TableTypes.tsx +2 -1
  27. package/src/components/Table/examples/LegacyTableActions.tsx +218 -0
  28. package/src/components/Table/examples/LegacyTableBasic.tsx +90 -0
  29. package/src/components/Table/examples/LegacyTableCellWidth.tsx +66 -0
  30. package/src/components/Table/examples/LegacyTableCompoundExpandable.tsx +175 -0
  31. package/src/components/Table/examples/LegacyTableControllingText.tsx +51 -0
  32. package/src/components/Table/examples/LegacyTableEmptyState.tsx +48 -0
  33. package/src/components/Table/examples/LegacyTableExpandable.tsx +172 -0
  34. package/src/components/Table/examples/LegacyTableFavoritable.tsx +157 -0
  35. package/src/components/Table/examples/LegacyTableHoverable.tsx +125 -0
  36. package/src/components/Table/examples/LegacyTableMisc.tsx +56 -0
  37. package/src/components/Table/examples/LegacyTableSelectable.tsx +124 -0
  38. package/src/components/Table/examples/LegacyTableSelectableRadio.tsx +54 -0
  39. package/src/components/Table/examples/LegacyTableSortable.tsx +120 -0
  40. package/src/components/Table/examples/LegacyTableSortableCustom.tsx +189 -0
  41. package/src/components/Table/examples/LegacyTableTextModifiers.tsx +31 -0
  42. package/src/components/Table/examples/LegacyTableTree.tsx +213 -0
  43. package/src/components/Table/examples/Table.md +83 -1848
  44. package/src/components/TableComposable/examples/ComposableTable.md +31 -2805
  45. package/src/components/TableComposable/examples/ComposableTableActions.tsx +163 -0
  46. package/src/components/TableComposable/examples/ComposableTableBasic.tsx +89 -0
  47. package/src/components/TableComposable/examples/ComposableTableCellWidth.tsx +56 -0
  48. package/src/components/TableComposable/examples/ComposableTableCompoundExpandable.tsx +103 -0
  49. package/src/components/TableComposable/examples/ComposableTableControllingText.tsx +51 -0
  50. package/src/components/TableComposable/examples/ComposableTableDraggable.tsx +170 -0
  51. package/src/components/TableComposable/examples/ComposableTableEmptyState.tsx +45 -0
  52. package/src/components/TableComposable/examples/ComposableTableExpandable.tsx +195 -0
  53. package/src/components/TableComposable/examples/ComposableTableFavoritable.tsx +118 -0
  54. package/src/components/TableComposable/examples/ComposableTableHoverable.tsx +67 -0
  55. package/src/components/TableComposable/examples/ComposableTableMisc.tsx +92 -0
  56. package/src/components/TableComposable/examples/ComposableTableMultipleStickyColumns.tsx +153 -0
  57. package/src/components/TableComposable/examples/ComposableTableNestedExpandable.tsx +127 -0
  58. package/src/components/TableComposable/examples/ComposableTableNestedHeaders.tsx +202 -0
  59. package/src/components/TableComposable/examples/ComposableTableSelectable.tsx +125 -0
  60. package/src/components/TableComposable/examples/ComposableTableSelectableRadio.tsx +68 -0
  61. package/src/components/TableComposable/examples/ComposableTableSortable.tsx +107 -0
  62. package/src/components/TableComposable/examples/ComposableTableSortableCustom.tsx +175 -0
  63. package/src/components/TableComposable/examples/ComposableTableStickyColumn.tsx +144 -0
  64. package/src/components/TableComposable/examples/ComposableTableStickyColumnsAndHeader.tsx +167 -0
  65. package/src/components/TableComposable/examples/ComposableTableTextModifiers.tsx +33 -0
  66. package/src/components/TableComposable/examples/ComposableTableTree.tsx +201 -0
  67. package/src/demos/Table.md +7 -6
  68. package/src/components/Table/examples/DemoSortableTable.js +0 -65
  69. package/src/components/TableComposable/examples/DemoSortableTable.js +0 -65
@@ -0,0 +1,195 @@
1
+ import React from 'react';
2
+ import { TableComposable, Thead, Tr, Th, Tbody, Td, ExpandableRowContent } from '@patternfly/react-table';
3
+ import { Checkbox } from '@patternfly/react-core';
4
+
5
+ interface Repository {
6
+ name: string;
7
+ branches: string;
8
+ prs: string;
9
+ workspaces: string;
10
+ lastCommit: string;
11
+ details?: {
12
+ detail1?: string;
13
+ detail2?: string;
14
+ detail3?: string;
15
+ detailFormat: 0 | 1 | 2 | 3;
16
+ };
17
+ }
18
+
19
+ export const ComposableTableExpandable: React.FunctionComponent = () => {
20
+ // In real usage, this data would come from some external source like an API via props.
21
+ const repositories: Repository[] = [
22
+ { name: 'one', branches: 'two', prs: 'a', workspaces: 'four', lastCommit: 'five' },
23
+ {
24
+ name: 'parent 1',
25
+ branches: 'two',
26
+ prs: 'k',
27
+ workspaces: 'four',
28
+ lastCommit: 'five',
29
+ // This `details` structure is just for this example. You can drive expanded content from any kind of data.
30
+ details: { detailFormat: 0, detail1: 'single cell' }
31
+ },
32
+ {
33
+ name: 'parent 2',
34
+ branches: 'two',
35
+ prs: 'b',
36
+ workspaces: 'four',
37
+ lastCommit: 'five',
38
+ details: { detailFormat: 1, detail1: 'single cell - fullWidth' }
39
+ },
40
+ {
41
+ name: 'parent 3',
42
+ branches: '2',
43
+ prs: 'b',
44
+ workspaces: 'four',
45
+ lastCommit: 'five',
46
+ details: { detailFormat: 2, detail1: 'single cell - noPadding' }
47
+ },
48
+ {
49
+ name: 'parent 4',
50
+ branches: '2',
51
+ prs: 'b',
52
+ workspaces: 'four',
53
+ lastCommit: 'five',
54
+ details: { detailFormat: 3, detail1: 'single cell - fullWidth & noPadding' }
55
+ },
56
+ {
57
+ name: 'parent 5',
58
+ branches: '2',
59
+ prs: 'b',
60
+ workspaces: 'four',
61
+ lastCommit: 'five',
62
+ details: {
63
+ detailFormat: 0,
64
+ detail1: "spans 'Repositories and 'Branches'",
65
+ detail2: "spans 'Pull requests' and 'Workspaces', and 'Last commit'"
66
+ }
67
+ },
68
+ {
69
+ name: 'parent 6',
70
+ branches: '2',
71
+ prs: 'b',
72
+ workspaces: 'four',
73
+ lastCommit: 'five',
74
+ details: {
75
+ detailFormat: 1,
76
+ detail1: "fullWidth, spans the collapsible column and 'Repositories'",
77
+ detail2: "fullWidth, spans 'Branches' and 'Pull requests'",
78
+ detail3: "fullWidth, spans 'Workspaces' and 'Last commit'"
79
+ }
80
+ }
81
+ ];
82
+
83
+ const columnNames = {
84
+ name: 'Repositories',
85
+ branches: 'Branches',
86
+ prs: 'Pull requests',
87
+ workspaces: 'Workspaces',
88
+ lastCommit: 'Last commit'
89
+ };
90
+
91
+ // In this example, expanded rows are tracked by the repo names from each row. This could be any unique identifier.
92
+ // This is to prevent state from being based on row order index in case we later add sorting.
93
+ // Note that this behavior is very similar to selection state.
94
+ const initialExpandedRepoNames = repositories.filter(repo => !!repo.details).map(repo => repo.name); // Default to all expanded
95
+ const [expandedRepoNames, setExpandedRepoNames] = React.useState<string[]>(initialExpandedRepoNames);
96
+ const setRepoExpanded = (repo: Repository, isExpanding = true) =>
97
+ setExpandedRepoNames(prevExpanded => {
98
+ const otherExpandedRepoNames = prevExpanded.filter(r => r !== repo.name);
99
+ return isExpanding ? [...otherExpandedRepoNames, repo.name] : otherExpandedRepoNames;
100
+ });
101
+ const isRepoExpanded = (repo: Repository) => expandedRepoNames.includes(repo.name);
102
+
103
+ const [isExampleCompact, setIsExampleCompact] = React.useState(true);
104
+
105
+ return (
106
+ <React.Fragment>
107
+ <Checkbox
108
+ label="Compact"
109
+ isChecked={isExampleCompact}
110
+ onChange={checked => setIsExampleCompact(checked)}
111
+ aria-label="toggle compact variation"
112
+ id="toggle-compact"
113
+ name="toggle-compact"
114
+ />
115
+ <TableComposable aria-label="Expandable table" variant={isExampleCompact ? 'compact' : undefined}>
116
+ <Thead>
117
+ <Tr>
118
+ <Th />
119
+ <Th>{columnNames.name}</Th>
120
+ <Th>{columnNames.branches}</Th>
121
+ <Th>{columnNames.prs}</Th>
122
+ <Th>{columnNames.workspaces}</Th>
123
+ <Th>{columnNames.lastCommit}</Th>
124
+ </Tr>
125
+ </Thead>
126
+ {repositories.map((repo, rowIndex) => {
127
+ // Some arbitrary examples of how you could customize the child row based on your needs
128
+ let childIsFullWidth = false;
129
+ let childHasNoPadding = false;
130
+ let detail1Colspan = 1;
131
+ let detail2Colspan = 1;
132
+ let detail3Colspan = 1;
133
+ if (repo.details) {
134
+ const { detail1, detail2, detail3, detailFormat } = repo.details;
135
+ const numColumns = 5;
136
+ childIsFullWidth = [1, 3].includes(detailFormat);
137
+ childHasNoPadding = [2, 3].includes(detailFormat);
138
+ if (detail1 && !detail2 && !detail3) {
139
+ detail1Colspan = childIsFullWidth ? numColumns : numColumns + 1; // Account for toggle column
140
+ } else if (detail1 && detail2 && !detail3) {
141
+ detail1Colspan = 2;
142
+ detail2Colspan = childIsFullWidth ? 3 : 4;
143
+ } else if (detail1 && detail2 && detail3) {
144
+ detail1Colspan = 2;
145
+ detail2Colspan = 2;
146
+ detail3Colspan = childIsFullWidth ? 1 : 2;
147
+ }
148
+ }
149
+ return (
150
+ <Tbody key={repo.name} isExpanded={isRepoExpanded(repo)}>
151
+ <Tr>
152
+ <Td
153
+ expand={
154
+ repo.details
155
+ ? {
156
+ rowIndex,
157
+ isExpanded: isRepoExpanded(repo),
158
+ onToggle: () => setRepoExpanded(repo, !isRepoExpanded(repo))
159
+ }
160
+ : undefined
161
+ }
162
+ />
163
+ <Td dataLabel={columnNames.name}>{repo.name}</Td>
164
+ <Td dataLabel={columnNames.branches}>{repo.branches}</Td>
165
+ <Td dataLabel={columnNames.prs}>{repo.prs}</Td>
166
+ <Td dataLabel={columnNames.workspaces}>{repo.workspaces}</Td>
167
+ <Td dataLabel={columnNames.lastCommit}>{repo.lastCommit}</Td>
168
+ </Tr>
169
+ {repo.details ? (
170
+ <Tr isExpanded={isRepoExpanded(repo)}>
171
+ {!childIsFullWidth ? <Td /> : null}
172
+ {repo.details.detail1 ? (
173
+ <Td dataLabel="Repo detail 1" noPadding={childHasNoPadding} colSpan={detail1Colspan}>
174
+ <ExpandableRowContent>{repo.details.detail1}</ExpandableRowContent>
175
+ </Td>
176
+ ) : null}
177
+ {repo.details.detail2 ? (
178
+ <Td dataLabel="Repo detail 2" noPadding={childHasNoPadding} colSpan={detail2Colspan}>
179
+ <ExpandableRowContent>{repo.details.detail2}</ExpandableRowContent>
180
+ </Td>
181
+ ) : null}
182
+ {repo.details.detail3 ? (
183
+ <Td dataLabel="Repo detail 3" noPadding={childHasNoPadding} colSpan={detail3Colspan}>
184
+ <ExpandableRowContent>{repo.details.detail3}</ExpandableRowContent>
185
+ </Td>
186
+ ) : null}
187
+ </Tr>
188
+ ) : null}
189
+ </Tbody>
190
+ );
191
+ })}
192
+ </TableComposable>
193
+ </React.Fragment>
194
+ );
195
+ };
@@ -0,0 +1,118 @@
1
+ import React from 'react';
2
+ import { TableComposable, Thead, Tr, Th, Tbody, Td, ThProps } from '@patternfly/react-table';
3
+
4
+ interface Repository {
5
+ name: string;
6
+ branches: string;
7
+ prs: string;
8
+ workspaces: string;
9
+ lastCommit: string;
10
+ }
11
+
12
+ export const ComposableTableFavoritable: React.FunctionComponent = () => {
13
+ // In real usage, this data would come from some external source like an API via props.
14
+ const repositories: Repository[] = [
15
+ { name: 'one', branches: 'two', prs: 'a', workspaces: 'four', lastCommit: 'five' },
16
+ { name: 'a', branches: 'two', prs: 'k', workspaces: 'four', lastCommit: 'five' },
17
+ { name: 'p', branches: 'two', prs: 'b', workspaces: 'four', lastCommit: 'five' }
18
+ ];
19
+
20
+ const columnNames = {
21
+ name: 'Repositories',
22
+ branches: 'Branches',
23
+ prs: 'Pull requests',
24
+ workspaces: 'Workspaces',
25
+ lastCommit: 'Last commit'
26
+ };
27
+
28
+ // Index of the currently sorted column
29
+ // Note: if you intend to make columns reorderable, you may instead want to use a non-numeric key
30
+ // as the identifier of the sorted column. See the "Compound expandable" example.
31
+ const [activeSortIndex, setActiveSortIndex] = React.useState<number | null>(null);
32
+
33
+ // Sort direction of the currently sorted column
34
+ const [activeSortDirection, setActiveSortDirection] = React.useState<'asc' | 'desc' | null>(null);
35
+
36
+ // Favorite state is similar to selection state, see Composable: Selectable with checkbox.
37
+ const [favoriteRepoNames, setFavoriteRepoNames] = React.useState<string[]>([]);
38
+ const setRepoFavorited = (repo: Repository, isFavoriting = true) =>
39
+ setFavoriteRepoNames(prevFavorites => {
40
+ const otherFavorites = prevFavorites.filter(r => r !== repo.name);
41
+ return isFavoriting ? [...otherFavorites, repo.name] : otherFavorites;
42
+ });
43
+ const isRepoFavorited = (repo: Repository) => favoriteRepoNames.includes(repo.name);
44
+
45
+ // Since OnSort specifies sorted columns by index, we need sortable values for our object by column index.
46
+ // In this example we only deal with booleans here because we only sort on the favorites column.
47
+ // For more complex sorting, see Composable: Sortable.
48
+ // Note: We also memoize the sortable values with useCallback to prevent rows jumping around when you change
49
+ // the favorites while sorting on that column. Only updating the sort state will reorder the rows.
50
+ const getSortableRowValues = React.useCallback((repo: Repository): boolean[] => [isRepoFavorited(repo)], [
51
+ activeSortIndex,
52
+ activeSortDirection
53
+ ]);
54
+
55
+ // Note that we perform the sort as part of the component's render logic and not in onSort.
56
+ // We shouldn't store the list of data in state because we don't want to have to sync that with props.
57
+ let sortedRepositories = repositories;
58
+ if (activeSortIndex !== null) {
59
+ sortedRepositories = repositories.sort((a, b) => {
60
+ const aValue = getSortableRowValues(a)[activeSortIndex];
61
+ const bValue = getSortableRowValues(b)[activeSortIndex];
62
+ if (aValue === bValue) {
63
+ return 0;
64
+ }
65
+ if (activeSortDirection === 'asc') {
66
+ return aValue > bValue ? 1 : -1;
67
+ } else {
68
+ return bValue > aValue ? 1 : -1;
69
+ }
70
+ });
71
+ }
72
+
73
+ const getSortParams = (columnIndex: number): ThProps['sort'] => ({
74
+ isFavorites: columnIndex === 0, // Not just statically true in case we add sorting on other columns later
75
+ sortBy: {
76
+ index: activeSortIndex,
77
+ direction: activeSortDirection
78
+ },
79
+ onSort: (_event, index, direction) => {
80
+ setActiveSortIndex(index);
81
+ setActiveSortDirection(direction);
82
+ },
83
+ columnIndex
84
+ });
85
+
86
+ return (
87
+ <TableComposable aria-label="Favoritable table" variant="compact">
88
+ <Thead>
89
+ <Tr>
90
+ <Th sort={getSortParams(0)} />
91
+ <Th>{columnNames.name}</Th>
92
+ <Th>{columnNames.branches}</Th>
93
+ <Th>{columnNames.prs}</Th>
94
+ <Th>{columnNames.workspaces}</Th>
95
+ <Th>{columnNames.lastCommit}</Th>
96
+ </Tr>
97
+ </Thead>
98
+ <Tbody>
99
+ {sortedRepositories.map((repo, rowIndex) => (
100
+ <Tr key={rowIndex}>
101
+ <Td
102
+ favorites={{
103
+ isFavorited: isRepoFavorited(repo),
104
+ onFavorite: (_event, isFavoriting) => setRepoFavorited(repo, isFavoriting),
105
+ rowIndex
106
+ }}
107
+ />
108
+ <Td dataLabel={columnNames.name}>{repo.name}</Td>
109
+ <Td dataLabel={columnNames.branches}>{repo.branches}</Td>
110
+ <Td dataLabel={columnNames.prs}>{repo.prs}</Td>
111
+ <Td dataLabel={columnNames.workspaces}>{repo.workspaces}</Td>
112
+ <Td dataLabel={columnNames.lastCommit}>{repo.lastCommit}</Td>
113
+ </Tr>
114
+ ))}
115
+ </Tbody>
116
+ </TableComposable>
117
+ );
118
+ };
@@ -0,0 +1,67 @@
1
+ import React from 'react';
2
+ import { TableComposable, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
3
+
4
+ interface Repository {
5
+ name: string;
6
+ branches: string | null;
7
+ prs: string | null;
8
+ workspaces: string;
9
+ lastCommit: string;
10
+ }
11
+
12
+ export const ComposableTableHoverable: React.FunctionComponent = () => {
13
+ // In real usage, this data would come from some external source like an API via props.
14
+ const repositories: Repository[] = [
15
+ { name: 'one', branches: 'two', prs: 'three', workspaces: 'four', lastCommit: 'five' },
16
+ { name: 'one - 2', branches: null, prs: null, workspaces: 'four - 2', lastCommit: 'five - 2' },
17
+ { name: 'one - 3', branches: 'two - 3', prs: 'three - 3', workspaces: 'four - 3', lastCommit: 'five - 3' }
18
+ ];
19
+
20
+ const columnNames = {
21
+ name: 'Repositories',
22
+ branches: 'Branches',
23
+ prs: 'Pull requests',
24
+ workspaces: 'Workspaces',
25
+ lastCommit: 'Last commit'
26
+ };
27
+
28
+ // In this example, selected rows are tracked by the repo names from each row. This could be any unique identifier.
29
+ // This is to prevent state from being based on row order index in case we later add sorting.
30
+ const [selectedRepoNames, setSelectedRepoNames] = React.useState<string[]>([]);
31
+ const setRepoSelected = (repo: Repository, isSelecting = true) =>
32
+ setSelectedRepoNames(prevSelected => {
33
+ const otherSelectedRepoNames = prevSelected.filter(r => r !== repo.name);
34
+ return isSelecting ? [...otherSelectedRepoNames, repo.name] : otherSelectedRepoNames;
35
+ });
36
+ const isRepoSelected = (repo: Repository) => selectedRepoNames.includes(repo.name);
37
+
38
+ return (
39
+ <TableComposable aria-label="Hoverable table">
40
+ <Thead>
41
+ <Tr>
42
+ <Th>{columnNames.name}</Th>
43
+ <Th>{columnNames.branches}</Th>
44
+ <Th>{columnNames.prs}</Th>
45
+ <Th>{columnNames.workspaces}</Th>
46
+ <Th>{columnNames.lastCommit}</Th>
47
+ </Tr>
48
+ </Thead>
49
+ <Tbody>
50
+ {repositories.map(repo => (
51
+ <Tr
52
+ key={repo.name}
53
+ onRowClick={() => setRepoSelected(repo, !isRepoSelected(repo))}
54
+ isHoverable
55
+ isRowSelected={isRepoSelected(repo)}
56
+ >
57
+ <Td dataLabel={columnNames.name}>{repo.name}</Td>
58
+ <Td dataLabel={columnNames.branches}>{repo.branches}</Td>
59
+ <Td dataLabel={columnNames.prs}>{repo.prs}</Td>
60
+ <Td dataLabel={columnNames.workspaces}>{repo.workspaces}</Td>
61
+ <Td dataLabel={columnNames.lastCommit}>{repo.lastCommit}</Td>
62
+ </Tr>
63
+ ))}
64
+ </Tbody>
65
+ </TableComposable>
66
+ );
67
+ };
@@ -0,0 +1,92 @@
1
+ import React from 'react';
2
+ import { TableComposable, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
3
+
4
+ interface Repository {
5
+ name: string;
6
+ branches: string | null;
7
+ prs: string | null;
8
+ workspaces: string;
9
+ lastCommit: string;
10
+ }
11
+
12
+ export const ComposableTableMisc: React.FunctionComponent = () => {
13
+ // In real usage, this data would come from some external source like an API via props.
14
+ const repositories: Repository[] = [
15
+ { name: 'one', branches: 'two', prs: 'three', workspaces: 'four', lastCommit: 'five' },
16
+ { name: 'one - 2', branches: null, prs: null, workspaces: 'four - 2', lastCommit: 'five - 2' },
17
+ { name: 'one - 3', branches: 'two - 3', prs: 'three - 3', workspaces: 'four - 3', lastCommit: 'five - 3' }
18
+ ];
19
+
20
+ const columnNames = {
21
+ name: 'Repositories',
22
+ branches: 'Branches',
23
+ prs: 'Pull requests',
24
+ workspaces: 'Workspaces',
25
+ lastCommit: 'Last commit'
26
+ };
27
+
28
+ return (
29
+ <TableComposable aria-label="Misc table">
30
+ <Thead noWrap>
31
+ <Tr>
32
+ <Th
33
+ info={{
34
+ tooltip: 'More information about repositories',
35
+ className: 'repositories-info-tip',
36
+ tooltipProps: {
37
+ isContentLeftAligned: true
38
+ }
39
+ }}
40
+ >
41
+ {columnNames.name}
42
+ </Th>
43
+ <Th>{columnNames.branches}</Th>
44
+ <Th
45
+ info={{
46
+ popover: (
47
+ <div>
48
+ More <strong>information</strong> on pull requests
49
+ </div>
50
+ ),
51
+ ariaLabel: 'More information on pull requests',
52
+ popoverProps: {
53
+ headerContent: columnNames.prs,
54
+ footerContent: <a href="#">Click here for even more info</a>
55
+ }
56
+ }}
57
+ >
58
+ {columnNames.prs}
59
+ </Th>
60
+ <Th>{columnNames.workspaces}</Th>
61
+ <Th textCenter>{columnNames.lastCommit}</Th>
62
+ </Tr>
63
+ </Thead>
64
+ <Tbody>
65
+ {repositories.map((repo, rowIndex) => {
66
+ const isOddRow = (rowIndex + 1) % 2;
67
+ const customStyle = {
68
+ borderLeft: '3px solid var(--pf-global--primary-color--100)'
69
+ };
70
+ // Some arbitrary logic to demonstrate that cell styles can be based on anything
71
+ const nameColSpan = repo.branches === null && repo.prs === null ? 3 : 1;
72
+ const lastCommitTextCenter = rowIndex !== 2;
73
+ return (
74
+ <Tr
75
+ key={repo.name}
76
+ className={isOddRow ? 'odd-row-class' : 'even-row-class'}
77
+ style={isOddRow ? customStyle : {}}
78
+ >
79
+ <Td dataLabel={columnNames.name} colSpan={nameColSpan}>
80
+ {repo.name}
81
+ </Td>
82
+ <Td dataLabel={columnNames.branches}>{repo.branches}</Td>
83
+ <Td dataLabel={columnNames.prs}></Td>
84
+ <Td dataLabel={columnNames.workspaces}></Td>
85
+ <Td dataLabel={columnNames.lastCommit} textCenter={lastCommitTextCenter}></Td>
86
+ </Tr>
87
+ );
88
+ })}
89
+ </Tbody>
90
+ </TableComposable>
91
+ );
92
+ };
@@ -0,0 +1,153 @@
1
+ import React from 'react';
2
+ import { TableComposable, Thead, Tr, Th, Tbody, Td, InnerScrollContainer, ThProps } from '@patternfly/react-table';
3
+ import BlueprintIcon from '@patternfly/react-icons/dist/esm/icons/blueprint-icon';
4
+
5
+ interface Fact {
6
+ name: string;
7
+ state: string;
8
+ detail1: string;
9
+ detail2: string;
10
+ detail3: string;
11
+ detail4: string;
12
+ detail5: string;
13
+ detail6: string;
14
+ detail7: string;
15
+ }
16
+
17
+ export const ComposableTableMultipleStickyColumns: React.FunctionComponent = () => {
18
+ // In real usage, this data would come from some external source like an API via props.
19
+ const facts: Fact[] = Array.from({ length: 9 }, (_, index) => ({
20
+ name: `Fact ${index + 1}`,
21
+ state: `State ${index + 1}`,
22
+ detail1: `Test cell ${index + 1}-3`,
23
+ detail2: `Test cell ${index + 1}-4`,
24
+ detail3: `Test cell ${index + 1}-5`,
25
+ detail4: `Test cell ${index + 1}-6`,
26
+ detail5: `Test cell ${index + 1}-7`,
27
+ detail6: `Test cell ${index + 1}-8`,
28
+ detail7: `Test cell ${index + 1}-9`
29
+ }));
30
+
31
+ const columnNames = {
32
+ name: 'Fact',
33
+ state: 'State',
34
+ header3: 'Header 3',
35
+ header4: 'Header 4',
36
+ header5: 'Header 5',
37
+ header6: 'Header 6',
38
+ header7: 'Header 7',
39
+ header8: 'Header 8',
40
+ header9: 'Header 9'
41
+ };
42
+
43
+ // Index of the currently sorted column
44
+ // Note: if you intend to make columns reorderable, you may instead want to use a non-numeric key
45
+ // as the identifier of the sorted column. See the "Compound expandable" example.
46
+ const [activeSortIndex, setActiveSortIndex] = React.useState<number | null>(null);
47
+
48
+ // Sort direction of the currently sorted column
49
+ const [activeSortDirection, setActiveSortDirection] = React.useState<'asc' | 'desc' | null>(null);
50
+
51
+ // Since OnSort specifies sorted columns by index, we need sortable values for our object by column index.
52
+ // This example is trivial since our data objects just contain strings, but if the data was more complex
53
+ // this would be a place to return simplified string or number versions of each column to sort by.
54
+ const getSortableRowValues = (fact: Fact): (string | number)[] => {
55
+ const { name, state, detail1, detail2, detail3, detail4, detail5, detail6, detail7 } = fact;
56
+ return [name, state, detail1, detail2, detail3, detail4, detail5, detail6, detail7];
57
+ };
58
+
59
+ // Note that we perform the sort as part of the component's render logic and not in onSort.
60
+ // We shouldn't store the list of data in state because we don't want to have to sync that with props.
61
+ let sortedFacts = facts;
62
+ if (activeSortIndex !== null) {
63
+ sortedFacts = facts.sort((a, b) => {
64
+ const aValue = getSortableRowValues(a)[activeSortIndex];
65
+ const bValue = getSortableRowValues(b)[activeSortIndex];
66
+ if (aValue === bValue) {
67
+ return 0;
68
+ }
69
+ if (activeSortDirection === 'asc') {
70
+ return aValue > bValue ? 1 : -1;
71
+ } else {
72
+ return bValue > aValue ? 1 : -1;
73
+ }
74
+ });
75
+ }
76
+
77
+ const getSortParams = (columnIndex: number): ThProps['sort'] => ({
78
+ sortBy: {
79
+ index: activeSortIndex,
80
+ direction: activeSortDirection
81
+ },
82
+ onSort: (_event, index, direction) => {
83
+ setActiveSortIndex(index);
84
+ setActiveSortDirection(direction);
85
+ },
86
+ columnIndex
87
+ });
88
+
89
+ return (
90
+ <InnerScrollContainer>
91
+ <TableComposable aria-label="Multiple sticky column table" gridBreakPoint="">
92
+ <Thead>
93
+ <Tr>
94
+ <Th isStickyColumn modifier="truncate" sort={getSortParams(0)}>
95
+ {columnNames.name}
96
+ </Th>
97
+ <Th
98
+ isStickyColumn
99
+ stickyMinWidth="120px"
100
+ stickyLeftOffset="120px"
101
+ hasRightBorder
102
+ modifier="truncate"
103
+ sort={getSortParams(1)}
104
+ >
105
+ {columnNames.state}
106
+ </Th>
107
+ <Th modifier="truncate">{columnNames.header3}</Th>
108
+ <Th modifier="truncate">{columnNames.header4}</Th>
109
+ <Th modifier="truncate">{columnNames.header5}</Th>
110
+ <Th modifier="truncate">{columnNames.header6}</Th>
111
+ <Th modifier="truncate">{columnNames.header7}</Th>
112
+ <Th modifier="truncate">{columnNames.header8}</Th>
113
+ <Th modifier="truncate">{columnNames.header9}</Th>
114
+ </Tr>
115
+ </Thead>
116
+ <Tbody>
117
+ {sortedFacts.map(fact => (
118
+ <Tr key={fact.name}>
119
+ <Th isStickyColumn modifier="truncate">
120
+ {fact.name}
121
+ </Th>
122
+ <Th isStickyColumn stickyMinWidth="120px" stickyLeftOffset="120px" modifier="truncate" hasRightBorder>
123
+ <BlueprintIcon />
124
+ {` ${fact.state}`}
125
+ </Th>
126
+ <Td modifier="nowrap" dataLabel={columnNames.header3}>
127
+ {fact.detail1}
128
+ </Td>
129
+ <Td modifier="nowrap" dataLabel={columnNames.header4}>
130
+ {fact.detail2}
131
+ </Td>
132
+ <Td modifier="nowrap" dataLabel={columnNames.header5}>
133
+ {fact.detail3}
134
+ </Td>
135
+ <Td modifier="nowrap" dataLabel={columnNames.header6}>
136
+ {fact.detail4}
137
+ </Td>
138
+ <Td modifier="nowrap" dataLabel={columnNames.header7}>
139
+ {fact.detail5}
140
+ </Td>
141
+ <Td modifier="nowrap" dataLabel={columnNames.header8}>
142
+ {fact.detail6}
143
+ </Td>
144
+ <Td modifier="nowrap" dataLabel={columnNames.header9}>
145
+ {fact.detail7}
146
+ </Td>
147
+ </Tr>
148
+ ))}
149
+ </Tbody>
150
+ </TableComposable>
151
+ </InnerScrollContainer>
152
+ );
153
+ };