@patternfly/react-table 4.41.0 → 4.43.2
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.
- package/CHANGELOG.md +38 -0
- package/dist/esm/components/Table/base/provider.d.ts +5 -5
- package/dist/esm/components/Table/base/types.d.ts +5 -5
- package/dist/esm/components/TableComposable/InnerScrollContainer.d.ts +9 -0
- package/dist/esm/components/TableComposable/InnerScrollContainer.d.ts.map +1 -0
- package/dist/esm/components/TableComposable/InnerScrollContainer.js +10 -0
- package/dist/esm/components/TableComposable/InnerScrollContainer.js.map +1 -0
- package/dist/esm/components/TableComposable/OuterScrollContainer.d.ts +9 -0
- package/dist/esm/components/TableComposable/OuterScrollContainer.d.ts.map +1 -0
- package/dist/esm/components/TableComposable/OuterScrollContainer.js +10 -0
- package/dist/esm/components/TableComposable/OuterScrollContainer.js.map +1 -0
- package/dist/esm/components/TableComposable/TableComposable.d.ts +3 -1
- package/dist/esm/components/TableComposable/TableComposable.d.ts.map +1 -1
- package/dist/esm/components/TableComposable/TableComposable.js +12 -2
- package/dist/esm/components/TableComposable/TableComposable.js.map +1 -1
- package/dist/esm/components/TableComposable/Th.d.ts +11 -1
- package/dist/esm/components/TableComposable/Th.d.ts.map +1 -1
- package/dist/esm/components/TableComposable/Th.js +5 -2
- package/dist/esm/components/TableComposable/Th.js.map +1 -1
- package/dist/esm/components/TableComposable/Thead.d.ts +3 -1
- package/dist/esm/components/TableComposable/Thead.d.ts.map +1 -1
- package/dist/esm/components/TableComposable/Thead.js +2 -2
- package/dist/esm/components/TableComposable/Thead.js.map +1 -1
- package/dist/esm/components/TableComposable/Tr.d.ts +3 -1
- package/dist/esm/components/TableComposable/Tr.d.ts.map +1 -1
- package/dist/esm/components/TableComposable/Tr.js +2 -2
- package/dist/esm/components/TableComposable/Tr.js.map +1 -1
- package/dist/esm/components/TableComposable/index.d.ts +2 -0
- package/dist/esm/components/TableComposable/index.d.ts.map +1 -1
- package/dist/esm/components/TableComposable/index.js +2 -0
- package/dist/esm/components/TableComposable/index.js.map +1 -1
- package/dist/js/components/Table/base/provider.d.ts +5 -5
- package/dist/js/components/Table/base/types.d.ts +5 -5
- package/dist/js/components/TableComposable/InnerScrollContainer.d.ts +9 -0
- package/dist/js/components/TableComposable/InnerScrollContainer.d.ts.map +1 -0
- package/dist/js/components/TableComposable/InnerScrollContainer.js +14 -0
- package/dist/js/components/TableComposable/InnerScrollContainer.js.map +1 -0
- package/dist/js/components/TableComposable/OuterScrollContainer.d.ts +9 -0
- package/dist/js/components/TableComposable/OuterScrollContainer.d.ts.map +1 -0
- package/dist/js/components/TableComposable/OuterScrollContainer.js +14 -0
- package/dist/js/components/TableComposable/OuterScrollContainer.js.map +1 -0
- package/dist/js/components/TableComposable/TableComposable.d.ts +3 -1
- package/dist/js/components/TableComposable/TableComposable.d.ts.map +1 -1
- package/dist/js/components/TableComposable/TableComposable.js +12 -2
- package/dist/js/components/TableComposable/TableComposable.js.map +1 -1
- package/dist/js/components/TableComposable/Th.d.ts +11 -1
- package/dist/js/components/TableComposable/Th.d.ts.map +1 -1
- package/dist/js/components/TableComposable/Th.js +5 -2
- package/dist/js/components/TableComposable/Th.js.map +1 -1
- package/dist/js/components/TableComposable/Thead.d.ts +3 -1
- package/dist/js/components/TableComposable/Thead.d.ts.map +1 -1
- package/dist/js/components/TableComposable/Thead.js +2 -2
- package/dist/js/components/TableComposable/Thead.js.map +1 -1
- package/dist/js/components/TableComposable/Tr.d.ts +3 -1
- package/dist/js/components/TableComposable/Tr.d.ts.map +1 -1
- package/dist/js/components/TableComposable/Tr.js +2 -2
- package/dist/js/components/TableComposable/Tr.js.map +1 -1
- package/dist/js/components/TableComposable/index.d.ts +2 -0
- package/dist/js/components/TableComposable/index.d.ts.map +1 -1
- package/dist/js/components/TableComposable/index.js +2 -0
- package/dist/js/components/TableComposable/index.js.map +1 -1
- package/dist/umd/react-table.css +497 -90
- package/dist/umd/react-table.js +247 -208
- package/dist/umd/react-table.min.css +497 -90
- package/dist/umd/react-table.min.js +3 -3
- package/package.json +6 -6
- package/src/components/TableComposable/InnerScrollContainer.tsx +22 -0
- package/src/components/TableComposable/OuterScrollContainer.tsx +22 -0
- package/src/components/TableComposable/TableComposable.tsx +11 -0
- package/src/components/TableComposable/Th.tsx +26 -0
- package/src/components/TableComposable/Thead.tsx +12 -1
- package/src/components/TableComposable/Tr.tsx +5 -1
- package/src/components/TableComposable/examples/ComposableTable.md +1106 -0
- package/src/components/TableComposable/index.ts +2 -0
|
@@ -28,6 +28,8 @@ propComponents:
|
|
|
28
28
|
'EditableTextCellProps',
|
|
29
29
|
'ThSortType',
|
|
30
30
|
'ISortBy',
|
|
31
|
+
'InnerScrollContainer',
|
|
32
|
+
'OuterScrollContainer',
|
|
31
33
|
]
|
|
32
34
|
ouia: true
|
|
33
35
|
---
|
|
@@ -52,6 +54,7 @@ import LeafIcon from '@patternfly/react-icons/dist/esm/icons/leaf-icon';
|
|
|
52
54
|
import FolderIcon from '@patternfly/react-icons/dist/esm/icons/folder-icon';
|
|
53
55
|
import FolderOpenIcon from '@patternfly/react-icons/dist/esm/icons/folder-open-icon';
|
|
54
56
|
import SortAmountDownIcon from '@patternfly/react-icons/dist/esm/icons/sort-amount-down-icon';
|
|
57
|
+
import BlueprintIcon from '@patternfly/react-icons/dist/esm/icons/blueprint-icon';
|
|
55
58
|
|
|
56
59
|
import { css } from '@patternfly/react-styles';
|
|
57
60
|
import styles from '@patternfly/react-styles/css/components/Table/table';
|
|
@@ -2012,3 +2015,1106 @@ class DraggableTable extends React.Component {
|
|
|
2012
2015
|
}
|
|
2013
2016
|
}
|
|
2014
2017
|
```
|
|
2018
|
+
|
|
2019
|
+
### Composable: Sticky column
|
|
2020
|
+
|
|
2021
|
+
To make a column sticky, wrap `TableComposable` with `InnerScrollContainer` and add the following properties to the `Th` that should be sticky: `isStickyColumn` and `hasRightBorder`. To prevent the default text wrapping behavior and allow horizontal scrolling, all `Th` should also have the `modifier="nowrap"` property. To set the minimum width of the sticky column, use the `stickyMinWidth` property.
|
|
2022
|
+
|
|
2023
|
+
```js
|
|
2024
|
+
import React from 'react';
|
|
2025
|
+
import {
|
|
2026
|
+
TableComposable,
|
|
2027
|
+
Thead,
|
|
2028
|
+
Tbody,
|
|
2029
|
+
Tr,
|
|
2030
|
+
Th,
|
|
2031
|
+
Td,
|
|
2032
|
+
Caption,
|
|
2033
|
+
TableText,
|
|
2034
|
+
InnerScrollContainer
|
|
2035
|
+
} from '@patternfly/react-table';
|
|
2036
|
+
import { Flex, FlexItem } from '@patternfly/react-core';
|
|
2037
|
+
import BlueprintIcon from '@patternfly/react-icons/dist/esm/icons/blueprint-icon';
|
|
2038
|
+
|
|
2039
|
+
ComposableTableStickyColumn = () => {
|
|
2040
|
+
const columns = ['Fact', 'State', 'Header 3', 'Header 4', 'Header 5', 'Header 6', 'Header 7', 'Header 8', 'Header 9'];
|
|
2041
|
+
const [rows, setRows] = React.useState([
|
|
2042
|
+
[
|
|
2043
|
+
'Fact 1',
|
|
2044
|
+
'State 1',
|
|
2045
|
+
'Test cell 1-3',
|
|
2046
|
+
'Test cell 1-4',
|
|
2047
|
+
'Test cell 1-5',
|
|
2048
|
+
'Test cell 1-6',
|
|
2049
|
+
'Test cell 1-7',
|
|
2050
|
+
'Test cell 1-8',
|
|
2051
|
+
'Test cell 1-9'
|
|
2052
|
+
],
|
|
2053
|
+
[
|
|
2054
|
+
'Fact 2',
|
|
2055
|
+
'State 2',
|
|
2056
|
+
'Test cell 2-3',
|
|
2057
|
+
'Test cell 2-4',
|
|
2058
|
+
'Test cell 2-5',
|
|
2059
|
+
'Test cell 2-6',
|
|
2060
|
+
'Test cell 2-7',
|
|
2061
|
+
'Test cell 2-8',
|
|
2062
|
+
'Test cell 2-9'
|
|
2063
|
+
],
|
|
2064
|
+
[
|
|
2065
|
+
'Fact 3',
|
|
2066
|
+
'State 3',
|
|
2067
|
+
'Test cell 3-3',
|
|
2068
|
+
'Test cell 3-4',
|
|
2069
|
+
'Test cell 3-5',
|
|
2070
|
+
'Test cell 3-6',
|
|
2071
|
+
'Test cell 3-7',
|
|
2072
|
+
'Test cell 3-8',
|
|
2073
|
+
'Test cell 3-9'
|
|
2074
|
+
],
|
|
2075
|
+
[
|
|
2076
|
+
'Fact 4',
|
|
2077
|
+
'State 4',
|
|
2078
|
+
'Test cell 4-3',
|
|
2079
|
+
'Test cell 4-4',
|
|
2080
|
+
'Test cell 4-5',
|
|
2081
|
+
'Test cell 4-6',
|
|
2082
|
+
'Test cell 4-7',
|
|
2083
|
+
'Test cell 4-8',
|
|
2084
|
+
'Test cell 4-9'
|
|
2085
|
+
],
|
|
2086
|
+
[
|
|
2087
|
+
'Fact 5',
|
|
2088
|
+
'State 5',
|
|
2089
|
+
'Test cell 5-3',
|
|
2090
|
+
'Test cell 5-4',
|
|
2091
|
+
'Test cell 5-5',
|
|
2092
|
+
'Test cell 5-6',
|
|
2093
|
+
'Test cell 5-7',
|
|
2094
|
+
'Test cell 5-8',
|
|
2095
|
+
'Test cell 5-9'
|
|
2096
|
+
],
|
|
2097
|
+
[
|
|
2098
|
+
'Fact 6',
|
|
2099
|
+
'State 6',
|
|
2100
|
+
'Test cell 6-3',
|
|
2101
|
+
'Test cell 6-4',
|
|
2102
|
+
'Test cell 6-5',
|
|
2103
|
+
'Test cell 6-6',
|
|
2104
|
+
'Test cell 6-7',
|
|
2105
|
+
'Test cell 6-8',
|
|
2106
|
+
'Test cell 6-9'
|
|
2107
|
+
],
|
|
2108
|
+
[
|
|
2109
|
+
'Fact 7',
|
|
2110
|
+
'State 7',
|
|
2111
|
+
'Test cell 7-3',
|
|
2112
|
+
'Test cell 7-4',
|
|
2113
|
+
'Test cell 7-5',
|
|
2114
|
+
'Test cell 7-6',
|
|
2115
|
+
'Test cell 7-7',
|
|
2116
|
+
'Test cell 7-8',
|
|
2117
|
+
'Test cell 7-9'
|
|
2118
|
+
],
|
|
2119
|
+
[
|
|
2120
|
+
'Fact 8',
|
|
2121
|
+
'State 8',
|
|
2122
|
+
'Test cell 8-3',
|
|
2123
|
+
'Test cell 8-4',
|
|
2124
|
+
'Test cell 8-5',
|
|
2125
|
+
'Test cell 8-6',
|
|
2126
|
+
'Test cell 8-7',
|
|
2127
|
+
'Test cell 8-8',
|
|
2128
|
+
'Test cell 8-9'
|
|
2129
|
+
],
|
|
2130
|
+
[
|
|
2131
|
+
'Fact 9',
|
|
2132
|
+
'State 9',
|
|
2133
|
+
'Test cell 9-3',
|
|
2134
|
+
'Test cell 9-4',
|
|
2135
|
+
'Test cell 9-5',
|
|
2136
|
+
'Test cell 9-6',
|
|
2137
|
+
'Test cell 9-7',
|
|
2138
|
+
'Test cell 9-8',
|
|
2139
|
+
'Test cell 9-9'
|
|
2140
|
+
]
|
|
2141
|
+
]);
|
|
2142
|
+
// index of the currently active column
|
|
2143
|
+
const [activeSortIndex, setActiveSortIndex] = React.useState(-1);
|
|
2144
|
+
// sort direction of the currently active column
|
|
2145
|
+
const [activeSortDirection, setActiveSortDirection] = React.useState('none');
|
|
2146
|
+
const onSort = (event, index, direction) => {
|
|
2147
|
+
setActiveSortIndex(index);
|
|
2148
|
+
setActiveSortDirection(direction);
|
|
2149
|
+
// sorts the rows
|
|
2150
|
+
const updatedRows = rows.sort((a, b) => {
|
|
2151
|
+
if (typeof a[index] === 'number') {
|
|
2152
|
+
// numeric sort
|
|
2153
|
+
if (direction === 'asc') {
|
|
2154
|
+
return a[index] - b[index];
|
|
2155
|
+
}
|
|
2156
|
+
return b[index] - a[index];
|
|
2157
|
+
} else {
|
|
2158
|
+
// string sort
|
|
2159
|
+
if (direction === 'asc') {
|
|
2160
|
+
return a[index].localeCompare(b[index]);
|
|
2161
|
+
}
|
|
2162
|
+
return b[index].localeCompare(a[index]);
|
|
2163
|
+
}
|
|
2164
|
+
});
|
|
2165
|
+
setRows(updatedRows);
|
|
2166
|
+
};
|
|
2167
|
+
return (
|
|
2168
|
+
<React.Fragment>
|
|
2169
|
+
<InnerScrollContainer>
|
|
2170
|
+
<TableComposable aria-label="Sticky column table" gridBreakPoint="">
|
|
2171
|
+
<Thead>
|
|
2172
|
+
<Tr>
|
|
2173
|
+
{columns.map((column, columnIndex) => {
|
|
2174
|
+
const sortParams =
|
|
2175
|
+
columnIndex === 0 || columnIndex === 1
|
|
2176
|
+
? {
|
|
2177
|
+
sort: {
|
|
2178
|
+
sortBy: {
|
|
2179
|
+
index: activeSortIndex,
|
|
2180
|
+
direction: activeSortDirection
|
|
2181
|
+
},
|
|
2182
|
+
onSort,
|
|
2183
|
+
columnIndex
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
: {};
|
|
2187
|
+
|
|
2188
|
+
if (columnIndex === 0) {
|
|
2189
|
+
return (
|
|
2190
|
+
<Th key={columnIndex} isStickyColumn hasRightBorder modifier="truncate" {...sortParams}>
|
|
2191
|
+
{column}
|
|
2192
|
+
</Th>
|
|
2193
|
+
);
|
|
2194
|
+
} else if (columnIndex === 1) {
|
|
2195
|
+
return (
|
|
2196
|
+
<Th key={columnIndex} modifier="truncate" {...sortParams}>
|
|
2197
|
+
{column}
|
|
2198
|
+
</Th>
|
|
2199
|
+
);
|
|
2200
|
+
} else {
|
|
2201
|
+
return (
|
|
2202
|
+
<Th key={columnIndex} modifier="truncate">
|
|
2203
|
+
{column}
|
|
2204
|
+
</Th>
|
|
2205
|
+
);
|
|
2206
|
+
}
|
|
2207
|
+
})}
|
|
2208
|
+
</Tr>
|
|
2209
|
+
</Thead>
|
|
2210
|
+
<Tbody>
|
|
2211
|
+
{rows.map((row, rowIndex) => (
|
|
2212
|
+
<Tr key={rowIndex}>
|
|
2213
|
+
{row.map((cell, cellIndex) => {
|
|
2214
|
+
if (cellIndex === 0) {
|
|
2215
|
+
return (
|
|
2216
|
+
<Th key={cellIndex} isStickyColumn hasRightBorder modifier="truncate">
|
|
2217
|
+
{cell}
|
|
2218
|
+
</Th>
|
|
2219
|
+
);
|
|
2220
|
+
} else {
|
|
2221
|
+
return (
|
|
2222
|
+
<Td key={`${rowIndex}_${cellIndex}`} modifier="nowrap" dataLabel={columns[cellIndex]}>
|
|
2223
|
+
{cell}
|
|
2224
|
+
</Td>
|
|
2225
|
+
);
|
|
2226
|
+
}
|
|
2227
|
+
})}
|
|
2228
|
+
</Tr>
|
|
2229
|
+
))}
|
|
2230
|
+
</Tbody>
|
|
2231
|
+
</TableComposable>
|
|
2232
|
+
</InnerScrollContainer>
|
|
2233
|
+
</React.Fragment>
|
|
2234
|
+
);
|
|
2235
|
+
};
|
|
2236
|
+
```
|
|
2237
|
+
|
|
2238
|
+
### Composable: Multiple sticky columns
|
|
2239
|
+
|
|
2240
|
+
To make multiple columns sticky, wrap `TableComposable` with `InnerScrollContainer` and add `isStickyColumn` to all columns that should be sticky. The rightmost column should also have the `hasRightBorder` property, and each sticky column after the first must define a `stickyLeftOffset` property that equals the combined width of the previous sticky columns - set by `stickyMinWidth`. To prevent the default text wrapping behavior and allow horizontal scrolling, all `Th` should also have the `modifier="nowrap"` property.
|
|
2241
|
+
|
|
2242
|
+
```js
|
|
2243
|
+
import React from 'react';
|
|
2244
|
+
import {
|
|
2245
|
+
TableComposable,
|
|
2246
|
+
Thead,
|
|
2247
|
+
Tbody,
|
|
2248
|
+
Tr,
|
|
2249
|
+
Th,
|
|
2250
|
+
Td,
|
|
2251
|
+
Caption,
|
|
2252
|
+
TableText,
|
|
2253
|
+
InnerScrollContainer
|
|
2254
|
+
} from '@patternfly/react-table';
|
|
2255
|
+
import { Flex, FlexItem } from '@patternfly/react-core';
|
|
2256
|
+
import BlueprintIcon from '@patternfly/react-icons/dist/esm/icons/blueprint-icon';
|
|
2257
|
+
|
|
2258
|
+
ComposableTableMultipleStickyColumn = () => {
|
|
2259
|
+
const columns = ['Fact', 'State', 'Header 3', 'Header 4', 'Header 5', 'Header 6', 'Header 7', 'Header 8', 'Header 9'];
|
|
2260
|
+
const [rows, setRows] = React.useState([
|
|
2261
|
+
[
|
|
2262
|
+
'Fact 1',
|
|
2263
|
+
'State 1',
|
|
2264
|
+
'Test cell 1-3',
|
|
2265
|
+
'Test cell 1-4',
|
|
2266
|
+
'Test cell 1-5',
|
|
2267
|
+
'Test cell 1-6',
|
|
2268
|
+
'Test cell 1-7',
|
|
2269
|
+
'Test cell 1-8',
|
|
2270
|
+
'Test cell 1-9'
|
|
2271
|
+
],
|
|
2272
|
+
[
|
|
2273
|
+
'Fact 2',
|
|
2274
|
+
'State 2',
|
|
2275
|
+
'Test cell 2-3',
|
|
2276
|
+
'Test cell 2-4',
|
|
2277
|
+
'Test cell 2-5',
|
|
2278
|
+
'Test cell 2-6',
|
|
2279
|
+
'Test cell 2-7',
|
|
2280
|
+
'Test cell 2-8',
|
|
2281
|
+
'Test cell 2-9'
|
|
2282
|
+
],
|
|
2283
|
+
[
|
|
2284
|
+
'Fact 3',
|
|
2285
|
+
'State 3',
|
|
2286
|
+
'Test cell 3-3',
|
|
2287
|
+
'Test cell 3-4',
|
|
2288
|
+
'Test cell 3-5',
|
|
2289
|
+
'Test cell 3-6',
|
|
2290
|
+
'Test cell 3-7',
|
|
2291
|
+
'Test cell 3-8',
|
|
2292
|
+
'Test cell 3-9'
|
|
2293
|
+
],
|
|
2294
|
+
[
|
|
2295
|
+
'Fact 4',
|
|
2296
|
+
'State 4',
|
|
2297
|
+
'Test cell 4-3',
|
|
2298
|
+
'Test cell 4-4',
|
|
2299
|
+
'Test cell 4-5',
|
|
2300
|
+
'Test cell 4-6',
|
|
2301
|
+
'Test cell 4-7',
|
|
2302
|
+
'Test cell 4-8',
|
|
2303
|
+
'Test cell 4-9'
|
|
2304
|
+
],
|
|
2305
|
+
[
|
|
2306
|
+
'Fact 5',
|
|
2307
|
+
'State 5',
|
|
2308
|
+
'Test cell 5-3',
|
|
2309
|
+
'Test cell 5-4',
|
|
2310
|
+
'Test cell 5-5',
|
|
2311
|
+
'Test cell 5-6',
|
|
2312
|
+
'Test cell 5-7',
|
|
2313
|
+
'Test cell 5-8',
|
|
2314
|
+
'Test cell 5-9'
|
|
2315
|
+
],
|
|
2316
|
+
[
|
|
2317
|
+
'Fact 6',
|
|
2318
|
+
'State 6',
|
|
2319
|
+
'Test cell 6-3',
|
|
2320
|
+
'Test cell 6-4',
|
|
2321
|
+
'Test cell 6-5',
|
|
2322
|
+
'Test cell 6-6',
|
|
2323
|
+
'Test cell 6-7',
|
|
2324
|
+
'Test cell 6-8',
|
|
2325
|
+
'Test cell 6-9'
|
|
2326
|
+
],
|
|
2327
|
+
[
|
|
2328
|
+
'Fact 7',
|
|
2329
|
+
'State 7',
|
|
2330
|
+
'Test cell 7-3',
|
|
2331
|
+
'Test cell 7-4',
|
|
2332
|
+
'Test cell 7-5',
|
|
2333
|
+
'Test cell 7-6',
|
|
2334
|
+
'Test cell 7-7',
|
|
2335
|
+
'Test cell 7-8',
|
|
2336
|
+
'Test cell 7-9'
|
|
2337
|
+
],
|
|
2338
|
+
[
|
|
2339
|
+
'Fact 8',
|
|
2340
|
+
'State 8',
|
|
2341
|
+
'Test cell 8-3',
|
|
2342
|
+
'Test cell 8-4',
|
|
2343
|
+
'Test cell 8-5',
|
|
2344
|
+
'Test cell 8-6',
|
|
2345
|
+
'Test cell 8-7',
|
|
2346
|
+
'Test cell 8-8',
|
|
2347
|
+
'Test cell 8-9'
|
|
2348
|
+
],
|
|
2349
|
+
[
|
|
2350
|
+
'Fact 9',
|
|
2351
|
+
'State 9',
|
|
2352
|
+
'Test cell 9-3',
|
|
2353
|
+
'Test cell 9-4',
|
|
2354
|
+
'Test cell 9-5',
|
|
2355
|
+
'Test cell 9-6',
|
|
2356
|
+
'Test cell 9-7',
|
|
2357
|
+
'Test cell 9-8',
|
|
2358
|
+
'Test cell 9-9'
|
|
2359
|
+
]
|
|
2360
|
+
]);
|
|
2361
|
+
// index of the currently active column
|
|
2362
|
+
const [activeSortIndex, setActiveSortIndex] = React.useState(-1);
|
|
2363
|
+
// sort direction of the currently active column
|
|
2364
|
+
const [activeSortDirection, setActiveSortDirection] = React.useState('none');
|
|
2365
|
+
const onSort = (event, index, direction) => {
|
|
2366
|
+
setActiveSortIndex(index);
|
|
2367
|
+
setActiveSortDirection(direction);
|
|
2368
|
+
// sorts the rows
|
|
2369
|
+
const updatedRows = rows.sort((a, b) => {
|
|
2370
|
+
if (typeof a[index] === 'number') {
|
|
2371
|
+
// numeric sort
|
|
2372
|
+
if (direction === 'asc') {
|
|
2373
|
+
return a[index] - b[index];
|
|
2374
|
+
}
|
|
2375
|
+
return b[index] - a[index];
|
|
2376
|
+
} else {
|
|
2377
|
+
// string sort
|
|
2378
|
+
if (direction === 'asc') {
|
|
2379
|
+
return a[index].localeCompare(b[index]);
|
|
2380
|
+
}
|
|
2381
|
+
return b[index].localeCompare(a[index]);
|
|
2382
|
+
}
|
|
2383
|
+
});
|
|
2384
|
+
setRows(updatedRows);
|
|
2385
|
+
};
|
|
2386
|
+
return (
|
|
2387
|
+
<React.Fragment>
|
|
2388
|
+
<InnerScrollContainer>
|
|
2389
|
+
<TableComposable aria-label="Sticky column table" gridBreakPoint="">
|
|
2390
|
+
<Thead>
|
|
2391
|
+
<Tr>
|
|
2392
|
+
{columns.map((column, columnIndex) => {
|
|
2393
|
+
const sortParams =
|
|
2394
|
+
columnIndex === 0 || columnIndex === 1
|
|
2395
|
+
? {
|
|
2396
|
+
sort: {
|
|
2397
|
+
sortBy: {
|
|
2398
|
+
index: activeSortIndex,
|
|
2399
|
+
direction: activeSortDirection
|
|
2400
|
+
},
|
|
2401
|
+
onSort,
|
|
2402
|
+
columnIndex
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2405
|
+
: {};
|
|
2406
|
+
|
|
2407
|
+
if (columnIndex === 0) {
|
|
2408
|
+
return (
|
|
2409
|
+
<Th key={columnIndex} isStickyColumn modifier="truncate" {...sortParams}>
|
|
2410
|
+
{column}
|
|
2411
|
+
</Th>
|
|
2412
|
+
);
|
|
2413
|
+
} else if (columnIndex === 1) {
|
|
2414
|
+
return (
|
|
2415
|
+
<Th
|
|
2416
|
+
key={columnIndex}
|
|
2417
|
+
isStickyColumn
|
|
2418
|
+
stickyMinWidth="120px"
|
|
2419
|
+
stickyLeftOffset="120px"
|
|
2420
|
+
hasRightBorder
|
|
2421
|
+
modifier="truncate"
|
|
2422
|
+
{...sortParams}
|
|
2423
|
+
>
|
|
2424
|
+
{column}
|
|
2425
|
+
</Th>
|
|
2426
|
+
);
|
|
2427
|
+
} else {
|
|
2428
|
+
return (
|
|
2429
|
+
<Th key={columnIndex} modifier="truncate">
|
|
2430
|
+
{column}
|
|
2431
|
+
</Th>
|
|
2432
|
+
);
|
|
2433
|
+
}
|
|
2434
|
+
})}
|
|
2435
|
+
</Tr>
|
|
2436
|
+
</Thead>
|
|
2437
|
+
<Tbody>
|
|
2438
|
+
{rows.map((row, rowIndex) => (
|
|
2439
|
+
<Tr key={rowIndex}>
|
|
2440
|
+
{row.map((cell, cellIndex) => {
|
|
2441
|
+
if (cellIndex === 0) {
|
|
2442
|
+
return (
|
|
2443
|
+
<Th key={cellIndex} isStickyColumn modifier="truncate">
|
|
2444
|
+
{cell}
|
|
2445
|
+
</Th>
|
|
2446
|
+
);
|
|
2447
|
+
} else if (cellIndex === 1) {
|
|
2448
|
+
return (
|
|
2449
|
+
<Th
|
|
2450
|
+
key={cellIndex}
|
|
2451
|
+
isStickyColumn
|
|
2452
|
+
stickyMinWidth="120px"
|
|
2453
|
+
stickyLeftOffset="120px"
|
|
2454
|
+
modifier="truncate"
|
|
2455
|
+
hasRightBorder
|
|
2456
|
+
>
|
|
2457
|
+
<BlueprintIcon />
|
|
2458
|
+
{` ${cell}`}
|
|
2459
|
+
</Th>
|
|
2460
|
+
);
|
|
2461
|
+
} else {
|
|
2462
|
+
return (
|
|
2463
|
+
<Td key={`${rowIndex}_${cellIndex}`} modifier="nowrap" dataLabel={columns[cellIndex]}>
|
|
2464
|
+
{cell}
|
|
2465
|
+
</Td>
|
|
2466
|
+
);
|
|
2467
|
+
}
|
|
2468
|
+
})}
|
|
2469
|
+
</Tr>
|
|
2470
|
+
))}
|
|
2471
|
+
</Tbody>
|
|
2472
|
+
</TableComposable>
|
|
2473
|
+
</InnerScrollContainer>
|
|
2474
|
+
</React.Fragment>
|
|
2475
|
+
);
|
|
2476
|
+
};
|
|
2477
|
+
```
|
|
2478
|
+
|
|
2479
|
+
### Composable: Sticky columns and header
|
|
2480
|
+
|
|
2481
|
+
To maintain proper sticky behavior across sticky columns and header, `TableComposable` must be wrapped with `OuterScrollContainer` and `InnerScrollContainer` as shown in the example below.
|
|
2482
|
+
|
|
2483
|
+
```js
|
|
2484
|
+
import React from 'react';
|
|
2485
|
+
import {
|
|
2486
|
+
TableComposable,
|
|
2487
|
+
Thead,
|
|
2488
|
+
Tbody,
|
|
2489
|
+
Tr,
|
|
2490
|
+
Th,
|
|
2491
|
+
Td,
|
|
2492
|
+
Caption,
|
|
2493
|
+
TableText,
|
|
2494
|
+
InnerScrollContainer,
|
|
2495
|
+
OuterScrollContainer
|
|
2496
|
+
} from '@patternfly/react-table';
|
|
2497
|
+
import { Flex, FlexItem } from '@patternfly/react-core';
|
|
2498
|
+
import BlueprintIcon from '@patternfly/react-icons/dist/esm/icons/blueprint-icon';
|
|
2499
|
+
|
|
2500
|
+
ComposableTableStickyColumnAndHeader = () => {
|
|
2501
|
+
const columns = ['Fact', 'State', 'Header 3', 'Header 4', 'Header 5', 'Header 6', 'Header 7', 'Header 8', 'Header 9'];
|
|
2502
|
+
const [rows, setRows] = React.useState([
|
|
2503
|
+
[
|
|
2504
|
+
'Fact 1',
|
|
2505
|
+
'State 1',
|
|
2506
|
+
'Test cell 1-3',
|
|
2507
|
+
'Test cell 1-4',
|
|
2508
|
+
'Test cell 1-5',
|
|
2509
|
+
'Test cell 1-6',
|
|
2510
|
+
'Test cell 1-7',
|
|
2511
|
+
'Test cell 1-8',
|
|
2512
|
+
'Test cell 1-9'
|
|
2513
|
+
],
|
|
2514
|
+
[
|
|
2515
|
+
'Fact 2',
|
|
2516
|
+
'State 2',
|
|
2517
|
+
'Test cell 2-3',
|
|
2518
|
+
'Test cell 2-4',
|
|
2519
|
+
'Test cell 2-5',
|
|
2520
|
+
'Test cell 2-6',
|
|
2521
|
+
'Test cell 2-7',
|
|
2522
|
+
'Test cell 2-8',
|
|
2523
|
+
'Test cell 2-9'
|
|
2524
|
+
],
|
|
2525
|
+
[
|
|
2526
|
+
'Fact 3',
|
|
2527
|
+
'State 3',
|
|
2528
|
+
'Test cell 3-3',
|
|
2529
|
+
'Test cell 3-4',
|
|
2530
|
+
'Test cell 3-5',
|
|
2531
|
+
'Test cell 3-6',
|
|
2532
|
+
'Test cell 3-7',
|
|
2533
|
+
'Test cell 3-8',
|
|
2534
|
+
'Test cell 3-9'
|
|
2535
|
+
],
|
|
2536
|
+
[
|
|
2537
|
+
'Fact 4',
|
|
2538
|
+
'State 4',
|
|
2539
|
+
'Test cell 4-3',
|
|
2540
|
+
'Test cell 4-4',
|
|
2541
|
+
'Test cell 4-5',
|
|
2542
|
+
'Test cell 4-6',
|
|
2543
|
+
'Test cell 4-7',
|
|
2544
|
+
'Test cell 4-8',
|
|
2545
|
+
'Test cell 4-9'
|
|
2546
|
+
],
|
|
2547
|
+
[
|
|
2548
|
+
'Fact 5',
|
|
2549
|
+
'State 5',
|
|
2550
|
+
'Test cell 5-3',
|
|
2551
|
+
'Test cell 5-4',
|
|
2552
|
+
'Test cell 5-5',
|
|
2553
|
+
'Test cell 5-6',
|
|
2554
|
+
'Test cell 5-7',
|
|
2555
|
+
'Test cell 5-8',
|
|
2556
|
+
'Test cell 5-9'
|
|
2557
|
+
],
|
|
2558
|
+
[
|
|
2559
|
+
'Fact 6',
|
|
2560
|
+
'State 6',
|
|
2561
|
+
'Test cell 6-3',
|
|
2562
|
+
'Test cell 6-4',
|
|
2563
|
+
'Test cell 6-5',
|
|
2564
|
+
'Test cell 6-6',
|
|
2565
|
+
'Test cell 6-7',
|
|
2566
|
+
'Test cell 6-8',
|
|
2567
|
+
'Test cell 6-9'
|
|
2568
|
+
],
|
|
2569
|
+
[
|
|
2570
|
+
'Fact 7',
|
|
2571
|
+
'State 7',
|
|
2572
|
+
'Test cell 7-3',
|
|
2573
|
+
'Test cell 7-4',
|
|
2574
|
+
'Test cell 7-5',
|
|
2575
|
+
'Test cell 7-6',
|
|
2576
|
+
'Test cell 7-7',
|
|
2577
|
+
'Test cell 7-8',
|
|
2578
|
+
'Test cell 7-9'
|
|
2579
|
+
],
|
|
2580
|
+
[
|
|
2581
|
+
'Fact 8',
|
|
2582
|
+
'State 8',
|
|
2583
|
+
'Test cell 8-3',
|
|
2584
|
+
'Test cell 8-4',
|
|
2585
|
+
'Test cell 8-5',
|
|
2586
|
+
'Test cell 8-6',
|
|
2587
|
+
'Test cell 8-7',
|
|
2588
|
+
'Test cell 8-8',
|
|
2589
|
+
'Test cell 8-9'
|
|
2590
|
+
],
|
|
2591
|
+
[
|
|
2592
|
+
'Fact 9',
|
|
2593
|
+
'State 9',
|
|
2594
|
+
'Test cell 9-3',
|
|
2595
|
+
'Test cell 9-4',
|
|
2596
|
+
'Test cell 9-5',
|
|
2597
|
+
'Test cell 9-6',
|
|
2598
|
+
'Test cell 9-7',
|
|
2599
|
+
'Test cell 9-8',
|
|
2600
|
+
'Test cell 9-9'
|
|
2601
|
+
]
|
|
2602
|
+
]);
|
|
2603
|
+
// index of the currently active column
|
|
2604
|
+
const [activeSortIndex, setActiveSortIndex] = React.useState(-1);
|
|
2605
|
+
// sort direction of the currently active column
|
|
2606
|
+
const [activeSortDirection, setActiveSortDirection] = React.useState('none');
|
|
2607
|
+
const onSort = (event, index, direction) => {
|
|
2608
|
+
setActiveSortIndex(index);
|
|
2609
|
+
setActiveSortDirection(direction);
|
|
2610
|
+
// sorts the rows
|
|
2611
|
+
const updatedRows = rows.sort((a, b) => {
|
|
2612
|
+
if (typeof a[index] === 'number') {
|
|
2613
|
+
// numeric sort
|
|
2614
|
+
if (direction === 'asc') {
|
|
2615
|
+
return a[index] - b[index];
|
|
2616
|
+
}
|
|
2617
|
+
return b[index] - a[index];
|
|
2618
|
+
} else {
|
|
2619
|
+
// string sort
|
|
2620
|
+
if (direction === 'asc') {
|
|
2621
|
+
return a[index].localeCompare(b[index]);
|
|
2622
|
+
}
|
|
2623
|
+
return b[index].localeCompare(a[index]);
|
|
2624
|
+
}
|
|
2625
|
+
});
|
|
2626
|
+
setRows(updatedRows);
|
|
2627
|
+
};
|
|
2628
|
+
return (
|
|
2629
|
+
<React.Fragment>
|
|
2630
|
+
<div style={{ height: '600px' }}>
|
|
2631
|
+
<OuterScrollContainer>
|
|
2632
|
+
<InnerScrollContainer>
|
|
2633
|
+
<TableComposable aria-label="Sticky column table" gridBreakPoint="" isStickyHeader>
|
|
2634
|
+
<Thead>
|
|
2635
|
+
<Tr>
|
|
2636
|
+
{columns.map((column, columnIndex) => {
|
|
2637
|
+
const sortParams =
|
|
2638
|
+
columnIndex === 0 || columnIndex === 1
|
|
2639
|
+
? {
|
|
2640
|
+
sort: {
|
|
2641
|
+
sortBy: {
|
|
2642
|
+
index: activeSortIndex,
|
|
2643
|
+
direction: activeSortDirection
|
|
2644
|
+
},
|
|
2645
|
+
onSort,
|
|
2646
|
+
columnIndex
|
|
2647
|
+
}
|
|
2648
|
+
}
|
|
2649
|
+
: {};
|
|
2650
|
+
|
|
2651
|
+
if (columnIndex === 0) {
|
|
2652
|
+
return (
|
|
2653
|
+
<Th key={columnIndex} isStickyColumn modifier="truncate" {...sortParams}>
|
|
2654
|
+
{column}
|
|
2655
|
+
</Th>
|
|
2656
|
+
);
|
|
2657
|
+
} else if (columnIndex === 1) {
|
|
2658
|
+
return (
|
|
2659
|
+
<Th
|
|
2660
|
+
key={columnIndex}
|
|
2661
|
+
isStickyColumn
|
|
2662
|
+
stickyMinWidth="120px"
|
|
2663
|
+
stickyLeftOffset="120px"
|
|
2664
|
+
hasRightBorder
|
|
2665
|
+
modifier="truncate"
|
|
2666
|
+
{...sortParams}
|
|
2667
|
+
>
|
|
2668
|
+
{column}
|
|
2669
|
+
</Th>
|
|
2670
|
+
);
|
|
2671
|
+
} else {
|
|
2672
|
+
return (
|
|
2673
|
+
<Th key={columnIndex} modifier="truncate">
|
|
2674
|
+
{column}
|
|
2675
|
+
</Th>
|
|
2676
|
+
);
|
|
2677
|
+
}
|
|
2678
|
+
})}
|
|
2679
|
+
</Tr>
|
|
2680
|
+
</Thead>
|
|
2681
|
+
<Tbody>
|
|
2682
|
+
{rows.map((row, rowIndex) => (
|
|
2683
|
+
<Tr key={rowIndex}>
|
|
2684
|
+
{row.map((cell, cellIndex) => {
|
|
2685
|
+
if (cellIndex === 0) {
|
|
2686
|
+
return (
|
|
2687
|
+
<Th key={cellIndex} isStickyColumn modifier="truncate">
|
|
2688
|
+
{cell}
|
|
2689
|
+
</Th>
|
|
2690
|
+
);
|
|
2691
|
+
} else if (cellIndex === 1) {
|
|
2692
|
+
return (
|
|
2693
|
+
<Th
|
|
2694
|
+
key={cellIndex}
|
|
2695
|
+
isStickyColumn
|
|
2696
|
+
stickyMinWidth="120px"
|
|
2697
|
+
stickyLeftOffset="120px"
|
|
2698
|
+
modifier="truncate"
|
|
2699
|
+
hasRightBorder
|
|
2700
|
+
>
|
|
2701
|
+
<BlueprintIcon />
|
|
2702
|
+
{` ${cell}`}
|
|
2703
|
+
</Th>
|
|
2704
|
+
);
|
|
2705
|
+
} else {
|
|
2706
|
+
return (
|
|
2707
|
+
<Td key={`${rowIndex}_${cellIndex}`} modifier="nowrap" dataLabel={columns[cellIndex]}>
|
|
2708
|
+
{cell}
|
|
2709
|
+
</Td>
|
|
2710
|
+
);
|
|
2711
|
+
}
|
|
2712
|
+
})}
|
|
2713
|
+
</Tr>
|
|
2714
|
+
))}
|
|
2715
|
+
</Tbody>
|
|
2716
|
+
</TableComposable>
|
|
2717
|
+
</InnerScrollContainer>
|
|
2718
|
+
</OuterScrollContainer>
|
|
2719
|
+
</div>
|
|
2720
|
+
</React.Fragment>
|
|
2721
|
+
);
|
|
2722
|
+
};
|
|
2723
|
+
```
|
|
2724
|
+
|
|
2725
|
+
### Composable: Nested column headers
|
|
2726
|
+
|
|
2727
|
+
To make a nested column header:
|
|
2728
|
+
|
|
2729
|
+
1. Wrap `TableComposable` with `InnerScrollContainer`.
|
|
2730
|
+
2. Pass `nestedHeaderColumnSpans` to `TableComposable`. `nestedHeaderColumnSpans` is an array of numbers representing the column spans of the top level columns to `TableComposable`, where each number is equal to the number of sub columns for a column, or `1` if a column contains no sub columns.
|
|
2731
|
+
3. Pass `hasNestedHeader` to `Thead`.
|
|
2732
|
+
4. Pass two `Tr` as children of `Thead`.
|
|
2733
|
+
|
|
2734
|
+
The first `Tr` represents the top level of columns, and each must pass either `rowSpan` if the column does not contain sub columns or `colSpan` if the column contains sub columns. The value of `rowSpan` is equal to the number of rows the nested header will span, typically `2`, and the value of `colSpan` is equal to the number of sub columns in a column. Each `Th` except the last should also pass `hasRightBorder`.
|
|
2735
|
+
|
|
2736
|
+
The second `Tr` represents the second level of sub columns. The `Th` in this row each should pass `isSubHeader`, and the last sub column of a column should also pass `hasRightBorder`.
|
|
2737
|
+
|
|
2738
|
+
```js
|
|
2739
|
+
import React from 'react';
|
|
2740
|
+
import {
|
|
2741
|
+
TableComposable,
|
|
2742
|
+
Thead,
|
|
2743
|
+
Tbody,
|
|
2744
|
+
Tr,
|
|
2745
|
+
Th,
|
|
2746
|
+
Td,
|
|
2747
|
+
Caption,
|
|
2748
|
+
TableText,
|
|
2749
|
+
InnerScrollContainer,
|
|
2750
|
+
OuterScrollContainer
|
|
2751
|
+
} from '@patternfly/react-table';
|
|
2752
|
+
import { Flex, FlexItem, Stack, StackItem } from '@patternfly/react-core';
|
|
2753
|
+
import BlueprintIcon from '@patternfly/react-icons/dist/esm/icons/blueprint-icon';
|
|
2754
|
+
|
|
2755
|
+
ComposableTableStickyColumnAndHeader = () => {
|
|
2756
|
+
const columnData = [
|
|
2757
|
+
{
|
|
2758
|
+
name: 'Pods',
|
|
2759
|
+
subColumns: [
|
|
2760
|
+
{ name: 'Source', index: 0, sort: true },
|
|
2761
|
+
{ name: 'Destination', index: 1, sort: true },
|
|
2762
|
+
{ name: 'Date & Time', index: 2, sort: true }
|
|
2763
|
+
]
|
|
2764
|
+
},
|
|
2765
|
+
{
|
|
2766
|
+
name: 'Ports',
|
|
2767
|
+
subColumns: [
|
|
2768
|
+
{ name: 'Source', index: 3, sort: true },
|
|
2769
|
+
{ name: 'Desination', index: 4, sort: true }
|
|
2770
|
+
]
|
|
2771
|
+
},
|
|
2772
|
+
{ name: 'Protocol', index: 5, sort: true },
|
|
2773
|
+
{ name: 'Flow rate', index: 6, sort: true },
|
|
2774
|
+
{ name: 'Traffic', index: 7, sort: true },
|
|
2775
|
+
{ name: 'Packets', index: 8, sort: true }
|
|
2776
|
+
];
|
|
2777
|
+
const colSpans = columnData.map(column => {
|
|
2778
|
+
return column.subColumns ? column.subColumns.length : 1;
|
|
2779
|
+
});
|
|
2780
|
+
const [rows, setRows] = React.useState([
|
|
2781
|
+
[
|
|
2782
|
+
'api-pod-source-name',
|
|
2783
|
+
'api-pod-destination-name',
|
|
2784
|
+
<div>
|
|
2785
|
+
<span>June 22, 2021</span>
|
|
2786
|
+
<span className="pf-u-color-200">3:58:24 PM</span>
|
|
2787
|
+
</div>,
|
|
2788
|
+
<Stack>
|
|
2789
|
+
<StackItem>
|
|
2790
|
+
<span>443</span>
|
|
2791
|
+
</StackItem>
|
|
2792
|
+
<StackItem>
|
|
2793
|
+
<span className="pf-u-color-200">(HTTPS)</span>
|
|
2794
|
+
</StackItem>
|
|
2795
|
+
</Stack>,
|
|
2796
|
+
<Stack>
|
|
2797
|
+
<StackItem>
|
|
2798
|
+
<span>24</span>
|
|
2799
|
+
</StackItem>
|
|
2800
|
+
<StackItem>
|
|
2801
|
+
<span className="pf-u-color-200">(smtp)</span>
|
|
2802
|
+
</StackItem>
|
|
2803
|
+
</Stack>,
|
|
2804
|
+
'TCP',
|
|
2805
|
+
'1.9 Kbps',
|
|
2806
|
+
'2.1 KB',
|
|
2807
|
+
'3'
|
|
2808
|
+
]
|
|
2809
|
+
]);
|
|
2810
|
+
// index of the currently active column
|
|
2811
|
+
const [activeSortIndex, setActiveSortIndex] = React.useState(-1);
|
|
2812
|
+
// sort direction of the currently active column
|
|
2813
|
+
const [activeSortDirection, setActiveSortDirection] = React.useState('none');
|
|
2814
|
+
const onSort = (event, index, direction) => {
|
|
2815
|
+
setActiveSortIndex(index);
|
|
2816
|
+
setActiveSortDirection(direction);
|
|
2817
|
+
// sorts the rows
|
|
2818
|
+
const updatedRows = rows.sort((a, b) => {
|
|
2819
|
+
if (typeof a[index] === 'number') {
|
|
2820
|
+
// numeric sort
|
|
2821
|
+
if (direction === 'asc') {
|
|
2822
|
+
return a[index] - b[index];
|
|
2823
|
+
}
|
|
2824
|
+
return b[index] - a[index];
|
|
2825
|
+
} else {
|
|
2826
|
+
// string sort
|
|
2827
|
+
if (direction === 'asc') {
|
|
2828
|
+
return a[index].localeCompare(b[index]);
|
|
2829
|
+
}
|
|
2830
|
+
return b[index].localeCompare(a[index]);
|
|
2831
|
+
}
|
|
2832
|
+
});
|
|
2833
|
+
setRows(updatedRows);
|
|
2834
|
+
};
|
|
2835
|
+
|
|
2836
|
+
return (
|
|
2837
|
+
<React.Fragment>
|
|
2838
|
+
<InnerScrollContainer>
|
|
2839
|
+
<TableComposable aria-label="Sticky column table" gridBreakPoint="" nestedHeaderColumnSpans={colSpans}>
|
|
2840
|
+
<Thead hasNestedHeader>
|
|
2841
|
+
<Tr>
|
|
2842
|
+
{columnData.map((column, columnIndex) => {
|
|
2843
|
+
const sortParams = column.sort
|
|
2844
|
+
? {
|
|
2845
|
+
sort: {
|
|
2846
|
+
sortBy: {
|
|
2847
|
+
index: activeSortIndex,
|
|
2848
|
+
direction: activeSortDirection
|
|
2849
|
+
},
|
|
2850
|
+
onSort,
|
|
2851
|
+
columnIndex: column.index
|
|
2852
|
+
}
|
|
2853
|
+
}
|
|
2854
|
+
: {};
|
|
2855
|
+
const colParams = column.subColumns ? { colSpan: column.subColumns.length } : { rowSpan: 2 };
|
|
2856
|
+
return (
|
|
2857
|
+
<Th
|
|
2858
|
+
key={`${columnIndex}-${column.name}`}
|
|
2859
|
+
{...(columnIndex !== 0 && columnIndex !== 1 && { modifier: 'fitContent' })}
|
|
2860
|
+
{...(columnIndex !== columnData.length - 1 && { hasRightBorder: true })}
|
|
2861
|
+
{...colParams}
|
|
2862
|
+
{...sortParams}
|
|
2863
|
+
>
|
|
2864
|
+
{column.name}
|
|
2865
|
+
</Th>
|
|
2866
|
+
);
|
|
2867
|
+
})}
|
|
2868
|
+
</Tr>
|
|
2869
|
+
<Tr>
|
|
2870
|
+
{columnData.map((column, columnIndex) => {
|
|
2871
|
+
if (column.subColumns) {
|
|
2872
|
+
return column.subColumns.map((subColumn, subColumnIndex) => {
|
|
2873
|
+
const sortParams = subColumn.sort
|
|
2874
|
+
? {
|
|
2875
|
+
sort: {
|
|
2876
|
+
sortBy: {
|
|
2877
|
+
index: activeSortIndex,
|
|
2878
|
+
direction: activeSortDirection
|
|
2879
|
+
},
|
|
2880
|
+
onSort,
|
|
2881
|
+
columnIndex: subColumn.index
|
|
2882
|
+
}
|
|
2883
|
+
}
|
|
2884
|
+
: {};
|
|
2885
|
+
|
|
2886
|
+
return (
|
|
2887
|
+
<Th
|
|
2888
|
+
key={`${subColumnIndex}-${subColumn.name}`}
|
|
2889
|
+
isSubheader
|
|
2890
|
+
{...(columnIndex !== 0 && { modifier: 'fitContent' })}
|
|
2891
|
+
{...(columnIndex === 0 &&
|
|
2892
|
+
subColumnIndex !== 0 &&
|
|
2893
|
+
subColumnIndex !== 1 && { modifier: 'fitContent' })}
|
|
2894
|
+
{...(subColumnIndex === column.subColumns.length - 1 && { hasRightBorder: true })}
|
|
2895
|
+
{...sortParams}
|
|
2896
|
+
>
|
|
2897
|
+
{subColumn.name}
|
|
2898
|
+
</Th>
|
|
2899
|
+
);
|
|
2900
|
+
});
|
|
2901
|
+
}
|
|
2902
|
+
})}
|
|
2903
|
+
</Tr>
|
|
2904
|
+
</Thead>
|
|
2905
|
+
<Tbody>
|
|
2906
|
+
{rows.map((row, rowIndex) => (
|
|
2907
|
+
<Tr key={rowIndex}>
|
|
2908
|
+
{row.map((cell, cellIndex) => {
|
|
2909
|
+
return (
|
|
2910
|
+
<Td key={`${rowIndex}_${cellIndex}`} dataLabel={''}>
|
|
2911
|
+
{cell}
|
|
2912
|
+
</Td>
|
|
2913
|
+
);
|
|
2914
|
+
})}
|
|
2915
|
+
</Tr>
|
|
2916
|
+
))}
|
|
2917
|
+
</Tbody>
|
|
2918
|
+
</TableComposable>
|
|
2919
|
+
</InnerScrollContainer>
|
|
2920
|
+
</React.Fragment>
|
|
2921
|
+
);
|
|
2922
|
+
};
|
|
2923
|
+
```
|
|
2924
|
+
|
|
2925
|
+
### Composable: Nested column headers and expandable rows
|
|
2926
|
+
|
|
2927
|
+
```js
|
|
2928
|
+
import React from 'react';
|
|
2929
|
+
import {
|
|
2930
|
+
TableComposable,
|
|
2931
|
+
Thead,
|
|
2932
|
+
Tbody,
|
|
2933
|
+
Tr,
|
|
2934
|
+
Th,
|
|
2935
|
+
Td,
|
|
2936
|
+
ExpandableRowContent,
|
|
2937
|
+
InnerScrollContainer
|
|
2938
|
+
} from '@patternfly/react-table';
|
|
2939
|
+
import { Button } from '@patternfly/react-core';
|
|
2940
|
+
|
|
2941
|
+
ComposableTableNestedExpandable = () => {
|
|
2942
|
+
const columns = [
|
|
2943
|
+
{
|
|
2944
|
+
name: 'Team',
|
|
2945
|
+
index: 0
|
|
2946
|
+
},
|
|
2947
|
+
{
|
|
2948
|
+
name: 'Members',
|
|
2949
|
+
subColumns: [
|
|
2950
|
+
{ name: 'Design Lead', index: 1 },
|
|
2951
|
+
{ name: 'Interaction Designer', index: 2 },
|
|
2952
|
+
{ name: 'Visual Designer', index: 3 }
|
|
2953
|
+
]
|
|
2954
|
+
},
|
|
2955
|
+
{ name: 'Contact', index: 4 }
|
|
2956
|
+
];
|
|
2957
|
+
const rowPairs = [
|
|
2958
|
+
{
|
|
2959
|
+
parent: [
|
|
2960
|
+
'Developer program',
|
|
2961
|
+
'Person 1',
|
|
2962
|
+
'Person 2',
|
|
2963
|
+
'Person 3',
|
|
2964
|
+
<Button variant="link" isInline>
|
|
2965
|
+
Message us!
|
|
2966
|
+
</Button>
|
|
2967
|
+
],
|
|
2968
|
+
child: [
|
|
2969
|
+
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
|
|
2970
|
+
],
|
|
2971
|
+
fullWidth: true
|
|
2972
|
+
},
|
|
2973
|
+
{
|
|
2974
|
+
parent: [
|
|
2975
|
+
'Developer program',
|
|
2976
|
+
'Person A',
|
|
2977
|
+
'Person B',
|
|
2978
|
+
'Person C',
|
|
2979
|
+
<Button variant="link" isInline>
|
|
2980
|
+
Message us!
|
|
2981
|
+
</Button>
|
|
2982
|
+
],
|
|
2983
|
+
child: [
|
|
2984
|
+
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
|
|
2985
|
+
],
|
|
2986
|
+
fullWidth: true
|
|
2987
|
+
},
|
|
2988
|
+
{
|
|
2989
|
+
parent: [
|
|
2990
|
+
'Developer program',
|
|
2991
|
+
'Person X',
|
|
2992
|
+
'Person Y',
|
|
2993
|
+
'Person Z',
|
|
2994
|
+
<Button variant="link" isInline>
|
|
2995
|
+
Message us!
|
|
2996
|
+
</Button>
|
|
2997
|
+
],
|
|
2998
|
+
child: [
|
|
2999
|
+
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
|
|
3000
|
+
],
|
|
3001
|
+
fullWidth: true
|
|
3002
|
+
}
|
|
3003
|
+
];
|
|
3004
|
+
const numColumns = 5;
|
|
3005
|
+
const colSpans = columns.map(column => {
|
|
3006
|
+
return column.subColumns ? column.subColumns.length : 1;
|
|
3007
|
+
});
|
|
3008
|
+
// Init all to false
|
|
3009
|
+
const [expanded, setExpanded] = React.useState(
|
|
3010
|
+
Object.fromEntries(Object.entries(rowPairs).map(([k, v]) => [k, !Boolean(v.child)]))
|
|
3011
|
+
);
|
|
3012
|
+
const handleExpansionToggle = (event, pairIndex) => {
|
|
3013
|
+
setExpanded({
|
|
3014
|
+
...expanded,
|
|
3015
|
+
[pairIndex]: !expanded[pairIndex]
|
|
3016
|
+
});
|
|
3017
|
+
};
|
|
3018
|
+
let rowIndex = -1;
|
|
3019
|
+
return (
|
|
3020
|
+
<InnerScrollContainer>
|
|
3021
|
+
<TableComposable aria-label="Expandable Table" nestedHeaderColumnSpans={colSpans}>
|
|
3022
|
+
<Thead hasNestedHeader>
|
|
3023
|
+
<Tr>
|
|
3024
|
+
<Th rowSpan={2} />
|
|
3025
|
+
<Th rowSpan={2} hasRightBorder>
|
|
3026
|
+
{columns[0].name}
|
|
3027
|
+
</Th>
|
|
3028
|
+
<Th colSpan={3} hasRightBorder>
|
|
3029
|
+
{columns[1].name}
|
|
3030
|
+
</Th>
|
|
3031
|
+
<Th rowSpan={2}>{columns[2].name}</Th>
|
|
3032
|
+
</Tr>
|
|
3033
|
+
<Tr resetOffset>
|
|
3034
|
+
<Th isSubheader>{columns[1].subColumns[0].name}</Th>
|
|
3035
|
+
<Th isSubheader>{columns[1].subColumns[1].name}</Th>
|
|
3036
|
+
<Th isSubheader hasRightBorder>
|
|
3037
|
+
{columns[1].subColumns[2].name}
|
|
3038
|
+
</Th>
|
|
3039
|
+
</Tr>
|
|
3040
|
+
</Thead>
|
|
3041
|
+
{rowPairs.map((pair, pairIndex) => {
|
|
3042
|
+
rowIndex += 1;
|
|
3043
|
+
const parentRow = (
|
|
3044
|
+
<Tr key={rowIndex}>
|
|
3045
|
+
<Td
|
|
3046
|
+
key={`${rowIndex}_0`}
|
|
3047
|
+
expand={
|
|
3048
|
+
pair.child
|
|
3049
|
+
? {
|
|
3050
|
+
rowIndex: pairIndex,
|
|
3051
|
+
isExpanded: expanded[pairIndex],
|
|
3052
|
+
onToggle: handleExpansionToggle
|
|
3053
|
+
}
|
|
3054
|
+
: null
|
|
3055
|
+
}
|
|
3056
|
+
/>
|
|
3057
|
+
{pair.parent.map((cell, cellIndex) => (
|
|
3058
|
+
<Td key={`${rowIndex}_${cellIndex}`} dataLabel={columns[cellIndex]}>
|
|
3059
|
+
{cell}
|
|
3060
|
+
</Td>
|
|
3061
|
+
))}
|
|
3062
|
+
</Tr>
|
|
3063
|
+
);
|
|
3064
|
+
if (pair.child) {
|
|
3065
|
+
rowIndex += 1;
|
|
3066
|
+
}
|
|
3067
|
+
const childRow = pair.child ? (
|
|
3068
|
+
<Tr key={rowIndex} isExpanded={expanded[pairIndex] === true}>
|
|
3069
|
+
{!rowPairs[pairIndex].fullWidth && <Td key={`${rowIndex}_0`} />}
|
|
3070
|
+
{rowPairs[pairIndex].child.map((cell, cellIndex) => {
|
|
3071
|
+
const numChildCells = rowPairs[pairIndex].child.length;
|
|
3072
|
+
const shift = rowPairs[pairIndex].fullWidth ? 1 : 0;
|
|
3073
|
+
const shiftedCellIndex = cellIndex + shift;
|
|
3074
|
+
// some examples of how you could customize colSpan based on your needs
|
|
3075
|
+
const getColSpan = () => {
|
|
3076
|
+
// we have 6 columns (1 expandable column + 5 regular columns)
|
|
3077
|
+
// for the rowPairs where we've specificed `fullWidth`, add +1 to account for the expandable column
|
|
3078
|
+
let colSpan = 1;
|
|
3079
|
+
if (numChildCells === 1) {
|
|
3080
|
+
// single child cell: take up full width
|
|
3081
|
+
colSpan = numColumns + shift;
|
|
3082
|
+
} else if (numChildCells === 2) {
|
|
3083
|
+
// 2 children
|
|
3084
|
+
// child 1: 2 colspan
|
|
3085
|
+
// child 2: 3 or 4 colspan depending on fullWidth
|
|
3086
|
+
colSpan = cellIndex === 0 ? 2 : 3 + shift;
|
|
3087
|
+
} else if (numChildCells === 3) {
|
|
3088
|
+
// 3 children
|
|
3089
|
+
// child 1: 2 colspam
|
|
3090
|
+
// child 2: 2 colspan
|
|
3091
|
+
// child 3: 1 or 2 colspan depending on fullWidth
|
|
3092
|
+
colSpan = cellIndex === 2 ? 1 + shift : 2;
|
|
3093
|
+
}
|
|
3094
|
+
return colSpan;
|
|
3095
|
+
};
|
|
3096
|
+
return (
|
|
3097
|
+
<Td
|
|
3098
|
+
key={`${rowIndex}_${shiftedCellIndex}`}
|
|
3099
|
+
dataLabel={columns[cellIndex]}
|
|
3100
|
+
noPadding={rowPairs[pairIndex].noPadding}
|
|
3101
|
+
colSpan={getColSpan()}
|
|
3102
|
+
>
|
|
3103
|
+
<ExpandableRowContent>{cell.title || cell}</ExpandableRowContent>
|
|
3104
|
+
</Td>
|
|
3105
|
+
);
|
|
3106
|
+
})}
|
|
3107
|
+
</Tr>
|
|
3108
|
+
) : null;
|
|
3109
|
+
return (
|
|
3110
|
+
<Tbody key={pairIndex} isExpanded={expanded[pairIndex] === true}>
|
|
3111
|
+
{parentRow}
|
|
3112
|
+
{childRow}
|
|
3113
|
+
</Tbody>
|
|
3114
|
+
);
|
|
3115
|
+
})}
|
|
3116
|
+
</TableComposable>
|
|
3117
|
+
</InnerScrollContainer>
|
|
3118
|
+
);
|
|
3119
|
+
};
|
|
3120
|
+
```
|