@patternfly/react-table 6.5.0-prerelease.61 → 6.5.0-prerelease.62
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 +6 -0
- package/components/package.json +1 -1
- package/deprecated/package.json +1 -1
- package/dist/dynamic/components/Table/package.json +1 -1
- package/dist/dynamic/components/Table/utils/decorators/package.json +1 -1
- package/dist/dynamic/components/Table/utils/package.json +1 -1
- package/dist/dynamic/deprecated/components/Table/base/package.json +1 -1
- package/dist/dynamic/deprecated/components/Table/package.json +1 -1
- package/dist/dynamic/deprecated/components/package.json +1 -1
- package/dist/esm/components/Table/InnerScrollContainer.d.ts +3 -1
- package/dist/esm/components/Table/InnerScrollContainer.d.ts.map +1 -1
- package/dist/esm/components/Table/InnerScrollContainer.js +5 -3
- package/dist/esm/components/Table/InnerScrollContainer.js.map +1 -1
- package/dist/esm/components/Table/Table.d.ts +5 -1
- package/dist/esm/components/Table/Table.d.ts.map +1 -1
- package/dist/esm/components/Table/Table.js +3 -3
- package/dist/esm/components/Table/Table.js.map +1 -1
- package/dist/js/components/Table/InnerScrollContainer.d.ts +3 -1
- package/dist/js/components/Table/InnerScrollContainer.d.ts.map +1 -1
- package/dist/js/components/Table/InnerScrollContainer.js +5 -4
- package/dist/js/components/Table/InnerScrollContainer.js.map +1 -1
- package/dist/js/components/Table/Table.d.ts +5 -1
- package/dist/js/components/Table/Table.d.ts.map +1 -1
- package/dist/js/components/Table/Table.js +3 -3
- package/dist/js/components/Table/Table.js.map +1 -1
- package/dist/umd/assets/{output-Df8I4QNx.css → output-Br-aNBLk.css} +6267 -6267
- package/dist/umd/react-table.min.js +3 -3
- package/package.json +2 -2
- package/src/components/Table/InnerScrollContainer.tsx +9 -2
- package/src/components/Table/Table.tsx +9 -1
- package/src/components/Table/__tests__/Table.test.tsx +36 -0
- package/src/components/Table/examples/Table.md +11 -2
- package/src/components/Table/examples/TableStickyHeaderDynamic.tsx +140 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patternfly/react-table",
|
|
3
|
-
"version": "6.5.0-prerelease.
|
|
3
|
+
"version": "6.5.0-prerelease.62",
|
|
4
4
|
"description": "This library provides a set of React table components for use with the PatternFly 4",
|
|
5
5
|
"main": "dist/js/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -51,5 +51,5 @@
|
|
|
51
51
|
"react": "^17 || ^18 || ^19",
|
|
52
52
|
"react-dom": "^17 || ^18 || ^19"
|
|
53
53
|
},
|
|
54
|
-
"gitHead": "
|
|
54
|
+
"gitHead": "a42646491bffc8f27c860285ba61630931f755dc"
|
|
55
55
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { forwardRef } from 'react';
|
|
1
2
|
import { css } from '@patternfly/react-styles';
|
|
2
3
|
import styles from '@patternfly/react-styles/css/components/Table/table-scrollable';
|
|
3
4
|
|
|
@@ -6,16 +7,22 @@ export interface InnerScrollContainerProps extends React.HTMLProps<HTMLDivElemen
|
|
|
6
7
|
children?: React.ReactNode;
|
|
7
8
|
/** Additional classes added to the container */
|
|
8
9
|
className?: string;
|
|
10
|
+
/** @hide Forwarded ref */
|
|
11
|
+
innerRef?: React.Ref<HTMLDivElement>;
|
|
9
12
|
}
|
|
10
13
|
|
|
11
|
-
|
|
14
|
+
const InnerScrollContainerBase: React.FunctionComponent<InnerScrollContainerProps> = ({
|
|
12
15
|
children,
|
|
13
16
|
className,
|
|
17
|
+
innerRef,
|
|
14
18
|
...props
|
|
15
19
|
}: InnerScrollContainerProps) => (
|
|
16
|
-
<div className={css(className, styles.scrollInnerWrapper)} {...props}>
|
|
20
|
+
<div ref={innerRef} className={css(className, styles.scrollInnerWrapper)} {...props}>
|
|
17
21
|
{children}
|
|
18
22
|
</div>
|
|
19
23
|
);
|
|
20
24
|
|
|
25
|
+
export const InnerScrollContainer = forwardRef((props: InnerScrollContainerProps, ref: React.Ref<HTMLDivElement>) => (
|
|
26
|
+
<InnerScrollContainerBase innerRef={ref} {...props} />
|
|
27
|
+
));
|
|
21
28
|
InnerScrollContainer.displayName = 'InnerScrollContainer';
|
|
@@ -52,8 +52,12 @@ export interface TableProps extends React.HTMLProps<HTMLTableElement>, OUIAProps
|
|
|
52
52
|
isPlain?: boolean;
|
|
53
53
|
/** @beta Flag indicating if the table should not have plain styling when in the glass theme */
|
|
54
54
|
isNoPlainOnGlass?: boolean;
|
|
55
|
-
/** If set to true, the table header sticks to the top of its container */
|
|
55
|
+
/** If set to true, the table header sticks to the top of its container. This property applies both the sticky position and styling. */
|
|
56
56
|
isStickyHeader?: boolean;
|
|
57
|
+
/** @beta Flag indicating the table header should have sticky positioning to the top of the parent InnerScrollContainer. */
|
|
58
|
+
isStickyHeaderBase?: boolean;
|
|
59
|
+
/** @beta Flag indicating the table header should have stuck styling, when the header is not at the top of the scroll container. */
|
|
60
|
+
isStickyHeaderStuck?: boolean;
|
|
57
61
|
/** @hide Forwarded ref */
|
|
58
62
|
innerRef?: React.RefObject<any>;
|
|
59
63
|
/** Flag indicating table is a tree table */
|
|
@@ -98,6 +102,8 @@ const TableBase: React.FunctionComponent<TableProps> = ({
|
|
|
98
102
|
variant,
|
|
99
103
|
borders = true,
|
|
100
104
|
isStickyHeader = false,
|
|
105
|
+
isStickyHeaderBase = false,
|
|
106
|
+
isStickyHeaderStuck = false,
|
|
101
107
|
isPlain = false,
|
|
102
108
|
isNoPlainOnGlass = false,
|
|
103
109
|
gridBreakPoint = TableGridBreakpoint.gridMd,
|
|
@@ -225,6 +231,8 @@ const TableBase: React.FunctionComponent<TableProps> = ({
|
|
|
225
231
|
styles.modifiers[variant],
|
|
226
232
|
!borders && styles.modifiers.noBorderRows,
|
|
227
233
|
isStickyHeader && styles.modifiers.stickyHeader,
|
|
234
|
+
isStickyHeaderBase && styles.modifiers.stickyHeaderBase,
|
|
235
|
+
isStickyHeaderStuck && styles.modifiers.stickyHeaderStuck,
|
|
228
236
|
isTreeTable && stylesTreeView.modifiers.treeView,
|
|
229
237
|
isStriped && styles.modifiers.striped,
|
|
230
238
|
isExpandable && styles.modifiers.expandable,
|
|
@@ -186,3 +186,39 @@ test(`Does not render with class ${styles.modifiers.noPlainOnGlass} when isNoPla
|
|
|
186
186
|
|
|
187
187
|
expect(screen.getByRole('grid', { name: 'Test table' })).not.toHaveClass(styles.modifiers.noPlainOnGlass);
|
|
188
188
|
});
|
|
189
|
+
|
|
190
|
+
test(`Renders with class ${styles.modifiers.stickyHeaderBase} when isStickyHeaderBase is true`, () => {
|
|
191
|
+
render(<Table isStickyHeaderBase aria-label="Test table" />);
|
|
192
|
+
|
|
193
|
+
expect(screen.getByRole('grid', { name: 'Test table' })).toHaveClass(styles.modifiers.stickyHeaderBase);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
test(`Does not render with class ${styles.modifiers.stickyHeaderBase} when isStickyHeaderBase is false`, () => {
|
|
197
|
+
render(<Table isStickyHeaderBase={false} aria-label="Test table" />);
|
|
198
|
+
|
|
199
|
+
expect(screen.getByRole('grid', { name: 'Test table' })).not.toHaveClass(styles.modifiers.stickyHeaderBase);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
test(`Does not render with class ${styles.modifiers.stickyHeaderBase} when isStickyHeaderBase is undefined`, () => {
|
|
203
|
+
render(<Table aria-label="Test table" />);
|
|
204
|
+
|
|
205
|
+
expect(screen.getByRole('grid', { name: 'Test table' })).not.toHaveClass(styles.modifiers.stickyHeaderBase);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test(`Renders with class ${styles.modifiers.stickyHeaderStuck} when isStickyHeaderStuck is true`, () => {
|
|
209
|
+
render(<Table isStickyHeaderStuck aria-label="Test table" />);
|
|
210
|
+
|
|
211
|
+
expect(screen.getByRole('grid', { name: 'Test table' })).toHaveClass(styles.modifiers.stickyHeaderStuck);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
test(`Does not render with class ${styles.modifiers.stickyHeaderStuck} when isStickyHeaderStuck is false`, () => {
|
|
215
|
+
render(<Table isStickyHeaderStuck={false} aria-label="Test table" />);
|
|
216
|
+
|
|
217
|
+
expect(screen.getByRole('grid', { name: 'Test table' })).not.toHaveClass(styles.modifiers.stickyHeaderStuck);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
test(`Does not render with class ${styles.modifiers.stickyHeaderStuck} when isStickyHeaderStuck is undefined`, () => {
|
|
221
|
+
render(<Table aria-label="Test table" />);
|
|
222
|
+
|
|
223
|
+
expect(screen.getByRole('grid', { name: 'Test table' })).not.toHaveClass(styles.modifiers.stickyHeaderStuck);
|
|
224
|
+
});
|
|
@@ -41,7 +41,7 @@ The `Table` component takes an explicit and declarative approach, and its implem
|
|
|
41
41
|
|
|
42
42
|
The documentation for the deprecated table implementation can be found under the [React deprecated](/components/table/react-deprecated) tab. It is configuration based and takes a less declarative and more implicit approach to laying out the table structure, such as the rows and cells within it.
|
|
43
43
|
|
|
44
|
-
import { Fragment, isValidElement, useCallback, useEffect, useRef, useState } from 'react';
|
|
44
|
+
import { Fragment, isValidElement, useCallback, useEffect, useRef, useState, useLayoutEffect } from 'react';
|
|
45
45
|
import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';
|
|
46
46
|
import CodeBranchIcon from '@patternfly/react-icons/dist/esm/icons/code-branch-icon';
|
|
47
47
|
import CodeIcon from '@patternfly/react-icons/dist/esm/icons/code-icon';
|
|
@@ -327,7 +327,6 @@ To enable a tree table:
|
|
|
327
327
|
- `checkAriaLabel` - (optional) accessible label for the checkbox
|
|
328
328
|
- `showDetailsAriaLabel` - (optional) accessible label for the show row details button in the responsive view
|
|
329
329
|
4. The first `Td` in each row will pass the following to the `treeRow` prop:
|
|
330
|
-
|
|
331
330
|
- `onCollapse` - Callback when user expands/collapses a row to reveal/hide the row's children.
|
|
332
331
|
- `onCheckChange` - (optional) Callback when user changes the checkbox on a row.
|
|
333
332
|
- `onToggleRowDetails` - (optional) Callback when user shows/hides the row details in responsive view.
|
|
@@ -419,6 +418,16 @@ To prevent the default text wrapping behavior and allow horizontal scrolling, al
|
|
|
419
418
|
|
|
420
419
|
```
|
|
421
420
|
|
|
421
|
+
### Dynamic sticky header
|
|
422
|
+
|
|
423
|
+
A sticky header may alternatively be implemented with two properties: `isStickyHeaderBase` and `isStickyHeaderStuck` - which allows separate control of the sticky position and sticky styling. `isStickyHeaderBase` should always be applied to make the header position sticky, and `isStickyHeaderStuck` may be applied dynamically to enable the sticky styling, such as when the sticky header is not at the top of the scroll parent as shown in the example.
|
|
424
|
+
|
|
425
|
+
`isStickyHeader` acts as if both properties are present and true when applied, and is useful when dynamic sticky styling is not necessary.
|
|
426
|
+
|
|
427
|
+
```ts file="TableStickyHeaderDynamic.tsx"
|
|
428
|
+
|
|
429
|
+
```
|
|
430
|
+
|
|
422
431
|
### Sticky columns and header
|
|
423
432
|
|
|
424
433
|
To maintain proper sticky behavior across sticky columns and header, `Table` must be wrapped with `OuterScrollContainer` and `InnerScrollContainer`.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { useLayoutEffect, useRef, useState } from 'react';
|
|
2
|
+
import { Table, Thead, Tr, Th, Tbody, Td, InnerScrollContainer } 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
|
+
const useIsStuckFromScrollParent = ({
|
|
18
|
+
shouldTrack,
|
|
19
|
+
scrollParentRef
|
|
20
|
+
}: {
|
|
21
|
+
/** Indicates whether to track the scroll top position of the scroll parent element */
|
|
22
|
+
shouldTrack: boolean;
|
|
23
|
+
/** Reference to the scroll parent element */
|
|
24
|
+
scrollParentRef: React.RefObject<any>;
|
|
25
|
+
}): boolean => {
|
|
26
|
+
const [isStuck, setIsStuck] = useState(false);
|
|
27
|
+
|
|
28
|
+
useLayoutEffect(() => {
|
|
29
|
+
if (!shouldTrack) {
|
|
30
|
+
setIsStuck(false);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const scrollElement = scrollParentRef.current;
|
|
35
|
+
if (!scrollElement) {
|
|
36
|
+
setIsStuck(false);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const syncFromScroll = () => {
|
|
41
|
+
setIsStuck(scrollElement.scrollTop > 0);
|
|
42
|
+
};
|
|
43
|
+
syncFromScroll();
|
|
44
|
+
scrollElement.addEventListener('scroll', syncFromScroll, { passive: true });
|
|
45
|
+
return () => scrollElement.removeEventListener('scroll', syncFromScroll);
|
|
46
|
+
}, [shouldTrack, scrollParentRef]);
|
|
47
|
+
|
|
48
|
+
return isStuck;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const TableStickyHeaderDynamic: React.FunctionComponent = () => {
|
|
52
|
+
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
|
53
|
+
const isStuck = useIsStuckFromScrollParent({ shouldTrack: true, scrollParentRef: scrollContainerRef });
|
|
54
|
+
|
|
55
|
+
// In real usage, this data would come from some external source like an API via props.
|
|
56
|
+
const facts: Fact[] = Array.from({ length: 9 }, (_, index) => ({
|
|
57
|
+
name: `Fact ${index + 1}`,
|
|
58
|
+
state: `State ${index + 1}`,
|
|
59
|
+
detail1: `Test cell ${index + 1}-3`,
|
|
60
|
+
detail2: `Test cell ${index + 1}-4`,
|
|
61
|
+
detail3: `Test cell ${index + 1}-5`,
|
|
62
|
+
detail4: `Test cell ${index + 1}-6`,
|
|
63
|
+
detail5: `Test cell ${index + 1}-7`,
|
|
64
|
+
detail6: `Test cell ${index + 1}-8`,
|
|
65
|
+
detail7: `Test cell ${index + 1}-9`
|
|
66
|
+
}));
|
|
67
|
+
|
|
68
|
+
const columnNames = {
|
|
69
|
+
name: 'Fact',
|
|
70
|
+
state: 'State',
|
|
71
|
+
header3: 'Header 3',
|
|
72
|
+
header4: 'Header 4',
|
|
73
|
+
header5: 'Header 5',
|
|
74
|
+
header6: 'Header 6',
|
|
75
|
+
header7: 'Header 7',
|
|
76
|
+
header8: 'Header 8',
|
|
77
|
+
header9: 'Header 9'
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<div style={{ height: '400px' }}>
|
|
82
|
+
<InnerScrollContainer ref={scrollContainerRef}>
|
|
83
|
+
<Table
|
|
84
|
+
aria-label="Dynamic sticky header table"
|
|
85
|
+
gridBreakPoint=""
|
|
86
|
+
isStickyHeaderBase
|
|
87
|
+
isStickyHeaderStuck={isStuck}
|
|
88
|
+
>
|
|
89
|
+
<Thead>
|
|
90
|
+
<Tr>
|
|
91
|
+
<Th modifier="truncate">{columnNames.name}</Th>
|
|
92
|
+
<Th modifier="truncate">{columnNames.state}</Th>
|
|
93
|
+
<Th modifier="truncate">{columnNames.header3}</Th>
|
|
94
|
+
<Th modifier="truncate">{columnNames.header4}</Th>
|
|
95
|
+
<Th modifier="truncate">{columnNames.header5}</Th>
|
|
96
|
+
<Th modifier="truncate">{columnNames.header6}</Th>
|
|
97
|
+
<Th modifier="truncate">{columnNames.header7}</Th>
|
|
98
|
+
<Th modifier="truncate">{columnNames.header8}</Th>
|
|
99
|
+
<Th modifier="truncate">{columnNames.header9}</Th>
|
|
100
|
+
</Tr>
|
|
101
|
+
</Thead>
|
|
102
|
+
<Tbody>
|
|
103
|
+
{facts.map((fact) => (
|
|
104
|
+
<Tr key={fact.name}>
|
|
105
|
+
<Td modifier="nowrap" dataLabel={columnNames.name}>
|
|
106
|
+
{fact.name}
|
|
107
|
+
</Td>
|
|
108
|
+
<Td modifier="nowrap" dataLabel={columnNames.state}>
|
|
109
|
+
<BlueprintIcon />
|
|
110
|
+
{` ${fact.state}`}
|
|
111
|
+
</Td>
|
|
112
|
+
<Td modifier="nowrap" dataLabel={columnNames.header3}>
|
|
113
|
+
{fact.detail1}
|
|
114
|
+
</Td>
|
|
115
|
+
<Td modifier="nowrap" dataLabel={columnNames.header4}>
|
|
116
|
+
{fact.detail2}
|
|
117
|
+
</Td>
|
|
118
|
+
<Td modifier="nowrap" dataLabel={columnNames.header5}>
|
|
119
|
+
{fact.detail3}
|
|
120
|
+
</Td>
|
|
121
|
+
<Td modifier="nowrap" dataLabel={columnNames.header6}>
|
|
122
|
+
{fact.detail4}
|
|
123
|
+
</Td>
|
|
124
|
+
<Td modifier="nowrap" dataLabel={columnNames.header7}>
|
|
125
|
+
{fact.detail5}
|
|
126
|
+
</Td>
|
|
127
|
+
<Td modifier="nowrap" dataLabel={columnNames.header8}>
|
|
128
|
+
{fact.detail6}
|
|
129
|
+
</Td>
|
|
130
|
+
<Td modifier="nowrap" dataLabel={columnNames.header9}>
|
|
131
|
+
{fact.detail7}
|
|
132
|
+
</Td>
|
|
133
|
+
</Tr>
|
|
134
|
+
))}
|
|
135
|
+
</Tbody>
|
|
136
|
+
</Table>
|
|
137
|
+
</InnerScrollContainer>
|
|
138
|
+
</div>
|
|
139
|
+
);
|
|
140
|
+
};
|