@patternfly/react-table 6.5.0-prerelease.7 → 6.5.0-prerelease.71

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 (80) hide show
  1. package/CHANGELOG.md +264 -0
  2. package/README.md +1 -1
  3. package/components/package.json +1 -1
  4. package/deprecated/package.json +1 -1
  5. package/dist/dynamic/components/Table/package.json +1 -1
  6. package/dist/dynamic/components/Table/utils/decorators/package.json +1 -1
  7. package/dist/dynamic/components/Table/utils/package.json +1 -1
  8. package/dist/dynamic/deprecated/components/Table/base/package.json +1 -1
  9. package/dist/dynamic/deprecated/components/Table/package.json +1 -1
  10. package/dist/dynamic/deprecated/components/package.json +1 -1
  11. package/dist/esm/components/Table/CollapseColumn.js +2 -2
  12. package/dist/esm/components/Table/CollapseColumn.js.map +1 -1
  13. package/dist/esm/components/Table/EditColumn.js +2 -2
  14. package/dist/esm/components/Table/EditColumn.js.map +1 -1
  15. package/dist/esm/components/Table/EditableSelectInputCell.d.ts.map +1 -1
  16. package/dist/esm/components/Table/EditableSelectInputCell.js.map +1 -1
  17. package/dist/esm/components/Table/InnerScrollContainer.d.ts +3 -1
  18. package/dist/esm/components/Table/InnerScrollContainer.d.ts.map +1 -1
  19. package/dist/esm/components/Table/InnerScrollContainer.js +5 -3
  20. package/dist/esm/components/Table/InnerScrollContainer.js.map +1 -1
  21. package/dist/esm/components/Table/Table.d.ts +7 -1
  22. package/dist/esm/components/Table/Table.d.ts.map +1 -1
  23. package/dist/esm/components/Table/Table.js +3 -3
  24. package/dist/esm/components/Table/Table.js.map +1 -1
  25. package/dist/esm/components/Table/Th.d.ts.map +1 -1
  26. package/dist/esm/components/Table/Th.js.map +1 -1
  27. package/dist/esm/components/Table/utils/decorators/sortable.js +2 -2
  28. package/dist/esm/components/Table/utils/decorators/sortable.js.map +1 -1
  29. package/dist/esm/components/Table/utils/decorators/treeRow.js +2 -2
  30. package/dist/esm/components/Table/utils/decorators/treeRow.js.map +1 -1
  31. package/dist/esm/demos/DashboardHeader.js +4 -4
  32. package/dist/esm/demos/DashboardHeader.js.map +1 -1
  33. package/dist/js/components/Table/CollapseColumn.js +2 -2
  34. package/dist/js/components/Table/CollapseColumn.js.map +1 -1
  35. package/dist/js/components/Table/EditColumn.js +2 -2
  36. package/dist/js/components/Table/EditColumn.js.map +1 -1
  37. package/dist/js/components/Table/EditableSelectInputCell.d.ts.map +1 -1
  38. package/dist/js/components/Table/EditableSelectInputCell.js.map +1 -1
  39. package/dist/js/components/Table/InnerScrollContainer.d.ts +3 -1
  40. package/dist/js/components/Table/InnerScrollContainer.d.ts.map +1 -1
  41. package/dist/js/components/Table/InnerScrollContainer.js +5 -4
  42. package/dist/js/components/Table/InnerScrollContainer.js.map +1 -1
  43. package/dist/js/components/Table/Table.d.ts +7 -1
  44. package/dist/js/components/Table/Table.d.ts.map +1 -1
  45. package/dist/js/components/Table/Table.js +3 -3
  46. package/dist/js/components/Table/Table.js.map +1 -1
  47. package/dist/js/components/Table/Th.d.ts.map +1 -1
  48. package/dist/js/components/Table/Th.js.map +1 -1
  49. package/dist/js/components/Table/utils/decorators/sortable.js +2 -2
  50. package/dist/js/components/Table/utils/decorators/sortable.js.map +1 -1
  51. package/dist/js/components/Table/utils/decorators/treeRow.js +2 -2
  52. package/dist/js/components/Table/utils/decorators/treeRow.js.map +1 -1
  53. package/dist/js/demos/DashboardHeader.js +4 -4
  54. package/dist/js/demos/DashboardHeader.js.map +1 -1
  55. package/dist/umd/assets/{output-DgRiEz7K.css → output-CI0BoW1v.css} +4827 -4632
  56. package/dist/umd/react-table.min.js +5 -5
  57. package/package.json +7 -7
  58. package/src/components/Table/CollapseColumn.tsx +2 -2
  59. package/src/components/Table/EditColumn.tsx +2 -2
  60. package/src/components/Table/EditableSelectInputCell.tsx +4 -2
  61. package/src/components/Table/InnerScrollContainer.tsx +9 -2
  62. package/src/components/Table/Table.tsx +13 -1
  63. package/src/components/Table/Th.tsx +1 -2
  64. package/src/components/Table/__tests__/Table.test.tsx +72 -0
  65. package/src/components/Table/__tests__/__snapshots__/RowWrapper.test.tsx.snap +2 -2
  66. package/src/components/Table/__tests__/__snapshots__/Table.test.tsx.snap +1 -1
  67. package/src/components/Table/__tests__/__snapshots__/Tr.test.tsx.snap +2 -2
  68. package/src/components/Table/examples/Table.md +18 -6
  69. package/src/components/Table/examples/TableActions.tsx +4 -9
  70. package/src/components/Table/examples/TableBasic.tsx +5 -10
  71. package/src/components/Table/examples/TableEditable.tsx +2 -2
  72. package/src/components/Table/examples/TableMultipleStickyColumns.tsx +2 -2
  73. package/src/components/Table/examples/TableStickyColumnsAndHeader.tsx +2 -2
  74. package/src/components/Table/examples/TableStickyHeaderDynamic.tsx +140 -0
  75. package/src/components/Table/utils/decorators/sortable.tsx +2 -2
  76. package/src/components/Table/utils/decorators/treeRow.tsx +2 -2
  77. package/src/demos/DashboardHeader.tsx +4 -4
  78. package/src/demos/Table.md +7 -8
  79. package/src/demos/examples/TableEmptyStateError.tsx +2 -2
  80. package/src/deprecated/components/Table/__tests__/__snapshots__/Table.test.tsx.snap +937 -469
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patternfly/react-table",
3
- "version": "6.5.0-prerelease.7",
3
+ "version": "6.5.0-prerelease.71",
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",
@@ -40,16 +40,16 @@
40
40
  "subpaths": "node ../../scripts/exportSubpaths.mjs --config subpaths.config.json"
41
41
  },
42
42
  "dependencies": {
43
- "@patternfly/react-core": "^6.5.0-prerelease.7",
44
- "@patternfly/react-icons": "^6.5.0-prerelease.3",
45
- "@patternfly/react-styles": "^6.5.0-prerelease.3",
46
- "@patternfly/react-tokens": "^6.5.0-prerelease.3",
47
- "lodash": "^4.17.21",
43
+ "@patternfly/react-core": "^6.5.0-prerelease.68",
44
+ "@patternfly/react-icons": "^6.5.0-prerelease.30",
45
+ "@patternfly/react-styles": "^6.5.0-prerelease.21",
46
+ "@patternfly/react-tokens": "^6.5.0-prerelease.20",
47
+ "lodash": "^4.18.1",
48
48
  "tslib": "^2.8.1"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "react": "^17 || ^18 || ^19",
52
52
  "react-dom": "^17 || ^18 || ^19"
53
53
  },
54
- "gitHead": "d09b3a3cb11d10807ada3c9fbde44254818f2fa2"
54
+ "gitHead": "3502b378ff6c4c1f59467079b3405dd1f7f0afde"
55
55
  }
@@ -1,5 +1,5 @@
1
1
  import { Fragment } from 'react';
2
- import AngleDownIcon from '@patternfly/react-icons/dist/esm/icons/angle-down-icon';
2
+ import RhMicronsCaretDownIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-caret-down-icon';
3
3
  import { css } from '@patternfly/react-styles';
4
4
  import { Button } from '@patternfly/react-core/dist/esm/components/Button';
5
5
  import styles from '@patternfly/react-styles/css/components/Table/table';
@@ -34,7 +34,7 @@ export const CollapseColumn: React.FunctionComponent<CollapseColumnProps> = ({
34
34
  aria-expanded={isOpen}
35
35
  icon={
36
36
  <div className={css(styles.tableToggleIcon)}>
37
- <AngleDownIcon />
37
+ <RhMicronsCaretDownIcon />
38
38
  </div>
39
39
  }
40
40
  />
@@ -2,7 +2,7 @@ import { Fragment } from 'react';
2
2
  import { Button } from '@patternfly/react-core/dist/esm/components/Button';
3
3
  import PencilAltIcon from '@patternfly/react-icons/dist/esm/icons/pencil-alt-icon';
4
4
  import CheckIcon from '@patternfly/react-icons/dist/esm/icons/check-icon';
5
- import TimesIcon from '@patternfly/react-icons/dist/esm/icons/times-icon';
5
+ import RhMicronsCloseIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-close-icon';
6
6
  import { OnRowEdit } from './TableTypes';
7
7
  import inlineStyles from '@patternfly/react-styles/css/components/InlineEdit/inline-edit';
8
8
  import { css } from '@patternfly/react-styles';
@@ -47,7 +47,7 @@ export const EditColumn: React.FunctionComponent<EditColumnProps> = ({
47
47
  {...props}
48
48
  onClick={(e) => onClick(e, 'cancel')}
49
49
  variant="plain"
50
- icon={<TimesIcon />}
50
+ icon={<RhMicronsCloseIcon />}
51
51
  />
52
52
  </div>
53
53
  </div>
@@ -6,8 +6,10 @@ import inlineStyles from '@patternfly/react-styles/css/components/InlineEdit/inl
6
6
  import formStyles from '@patternfly/react-styles/css/components/Form/form';
7
7
  import { EditableSelectInputProps } from './base/types';
8
8
 
9
- export interface IEditableSelectInputCell
10
- extends Omit<React.HTMLProps<HTMLElement | HTMLDivElement>, 'onSelect' | 'onToggle'> {
9
+ export interface IEditableSelectInputCell extends Omit<
10
+ React.HTMLProps<HTMLElement | HTMLDivElement>,
11
+ 'onSelect' | 'onToggle'
12
+ > {
11
13
  /** Row index of this select input cell */
12
14
  rowIndex: number;
13
15
  /** Cell index of this select input cell */
@@ -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
- export const InnerScrollContainer: React.FunctionComponent<InnerScrollContainerProps> = ({
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';
@@ -50,8 +50,14 @@ export interface TableProps extends React.HTMLProps<HTMLTableElement>, OUIAProps
50
50
  role?: string;
51
51
  /** @beta Flag indicating if the table should have plain styling with a transparent background */
52
52
  isPlain?: boolean;
53
- /** If set to true, the table header sticks to the top of its container */
53
+ /** @beta Flag indicating if the table should not have plain styling when in the glass theme */
54
+ isNoPlainOnGlass?: boolean;
55
+ /** If set to true, the table header sticks to the top of its container. This property applies both the sticky position and styling. */
54
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;
55
61
  /** @hide Forwarded ref */
56
62
  innerRef?: React.RefObject<any>;
57
63
  /** Flag indicating table is a tree table */
@@ -96,7 +102,10 @@ const TableBase: React.FunctionComponent<TableProps> = ({
96
102
  variant,
97
103
  borders = true,
98
104
  isStickyHeader = false,
105
+ isStickyHeaderBase = false,
106
+ isStickyHeaderStuck = false,
99
107
  isPlain = false,
108
+ isNoPlainOnGlass = false,
100
109
  gridBreakPoint = TableGridBreakpoint.gridMd,
101
110
  'aria-label': ariaLabel,
102
111
  role = 'grid',
@@ -222,10 +231,13 @@ const TableBase: React.FunctionComponent<TableProps> = ({
222
231
  styles.modifiers[variant],
223
232
  !borders && styles.modifiers.noBorderRows,
224
233
  isStickyHeader && styles.modifiers.stickyHeader,
234
+ isStickyHeaderBase && styles.modifiers.stickyHeaderBase,
235
+ isStickyHeaderStuck && styles.modifiers.stickyHeaderStuck,
225
236
  isTreeTable && stylesTreeView.modifiers.treeView,
226
237
  isStriped && styles.modifiers.striped,
227
238
  isExpandable && styles.modifiers.expandable,
228
239
  isPlain && styles.modifiers.plain,
240
+ isNoPlainOnGlass && styles.modifiers.noPlainOnGlass,
229
241
  hasNoInset && stylesTreeView.modifiers.noInset,
230
242
  isNested && 'pf-m-nested',
231
243
  hasAnimations && styles.modifiers.animateExpand
@@ -15,8 +15,7 @@ import cssStickyCellInlineStart from '@patternfly/react-tokens/dist/esm/c_table_
15
15
  import cssStickyCellInlineEnd from '@patternfly/react-tokens/dist/esm/c_table__sticky_cell_InsetInlineEnd';
16
16
 
17
17
  export interface ThProps
18
- extends BaseCellProps,
19
- Omit<React.HTMLProps<HTMLTableHeaderCellElement>, 'onSelect' | 'width'> {
18
+ extends BaseCellProps, Omit<React.HTMLProps<HTMLTableHeaderCellElement>, 'onSelect' | 'width'> {
20
19
  /**
21
20
  * The column header the cell corresponds to. Applicable when this component is used as a direct child to <Tr>.
22
21
  * This attribute replaces table header in mobile viewport. It is rendered by ::before pseudo element.
@@ -150,3 +150,75 @@ test('Renders expandable toggle button in Th with pf-m-small class when variant
150
150
  expect(button).toHaveClass('pf-m-small');
151
151
  });
152
152
  });
153
+
154
+ test(`Renders with class ${styles.modifiers.plain} when isPlain is true`, () => {
155
+ render(<Table isPlain aria-label="Test table" />);
156
+
157
+ expect(screen.getByRole('grid', { name: 'Test table' })).toHaveClass(styles.modifiers.plain);
158
+ });
159
+
160
+ test(`Does not render with class ${styles.modifiers.plain} when isPlain is not defined`, () => {
161
+ render(<Table aria-label="Test table" />);
162
+
163
+ expect(screen.getByRole('grid', { name: 'Test table' })).not.toHaveClass(styles.modifiers.plain);
164
+ });
165
+
166
+ test(`Does not render with class ${styles.modifiers.plain} when isPlain is false`, () => {
167
+ render(<Table isPlain={false} aria-label="Test table" />);
168
+
169
+ expect(screen.getByRole('grid', { name: 'Test table' })).not.toHaveClass(styles.modifiers.plain);
170
+ });
171
+
172
+ test(`Renders with class ${styles.modifiers.noPlainOnGlass} when isNoPlainOnGlass is true`, () => {
173
+ render(<Table isNoPlainOnGlass aria-label="Test table" />);
174
+
175
+ expect(screen.getByRole('grid', { name: 'Test table' })).toHaveClass(styles.modifiers.noPlainOnGlass);
176
+ });
177
+
178
+ test(`Does not render with class ${styles.modifiers.noPlainOnGlass} when isNoPlainOnGlass is undefined`, () => {
179
+ render(<Table aria-label="Test table" />);
180
+
181
+ expect(screen.getByRole('grid', { name: 'Test table' })).not.toHaveClass(styles.modifiers.noPlainOnGlass);
182
+ });
183
+
184
+ test(`Does not render with class ${styles.modifiers.noPlainOnGlass} when isNoPlainOnGlass is false`, () => {
185
+ render(<Table isNoPlainOnGlass={false} aria-label="Test table" />);
186
+
187
+ expect(screen.getByRole('grid', { name: 'Test table' })).not.toHaveClass(styles.modifiers.noPlainOnGlass);
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
+ });
@@ -6,7 +6,7 @@ exports[`RowWrapper renders correctly 1`] = `
6
6
  <tbody>
7
7
  <tr
8
8
  class="pf-v6-c-table__tr"
9
- data-ouia-component-id="OUIA-Generated-TableRow-1"
9
+ data-ouia-component-id="OUIA-Generated-TableRow-:r0:"
10
10
  data-ouia-component-type="PF6/TableRow"
11
11
  data-ouia-safe="true"
12
12
  />
@@ -21,7 +21,7 @@ exports[`RowWrapper renders expanded correctly 1`] = `
21
21
  <tbody>
22
22
  <tr
23
23
  class="pf-v6-c-table__tr pf-v6-c-table__expandable-row pf-m-expanded"
24
- data-ouia-component-id="OUIA-Generated-TableRow-2"
24
+ data-ouia-component-id="OUIA-Generated-TableRow-:r1:"
25
25
  data-ouia-component-type="PF6/TableRow"
26
26
  data-ouia-safe="true"
27
27
  />
@@ -4,7 +4,7 @@ exports[`Matches snapshot without children 1`] = `
4
4
  <DocumentFragment>
5
5
  <table
6
6
  class="pf-v6-c-table pf-m-grid-md"
7
- data-ouia-component-id="OUIA-Generated-Table-12"
7
+ data-ouia-component-id="OUIA-Generated-Table-:rb:"
8
8
  data-ouia-component-type="PF6/Table"
9
9
  data-ouia-safe="true"
10
10
  role="grid"
@@ -6,7 +6,7 @@ exports[`Matches snapshot with children 1`] = `
6
6
  <tbody>
7
7
  <tr
8
8
  class="pf-v6-c-table__tr"
9
- data-ouia-component-id="OUIA-Generated-TableRow-6"
9
+ data-ouia-component-id="OUIA-Generated-TableRow-:r5:"
10
10
  data-ouia-component-type="PF6/TableRow"
11
11
  data-ouia-safe="true"
12
12
  >
@@ -25,7 +25,7 @@ exports[`Matches snapshot without children 1`] = `
25
25
  <tbody>
26
26
  <tr
27
27
  class="pf-v6-c-table__tr"
28
- data-ouia-component-id="OUIA-Generated-TableRow-5"
28
+ data-ouia-component-id="OUIA-Generated-TableRow-:r4:"
29
29
  data-ouia-component-type="PF6/TableRow"
30
30
  data-ouia-safe="true"
31
31
  />
@@ -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';
@@ -50,11 +50,11 @@ import LeafIcon from '@patternfly/react-icons/dist/esm/icons/leaf-icon';
50
50
  import FolderIcon from '@patternfly/react-icons/dist/esm/icons/folder-icon';
51
51
  import FolderOpenIcon from '@patternfly/react-icons/dist/esm/icons/folder-open-icon';
52
52
  import SortAmountDownIcon from '@patternfly/react-icons/dist/esm/icons/sort-amount-down-icon';
53
- import BlueprintIcon from '@patternfly/react-icons/dist/esm/icons/blueprint-icon';
53
+ import RhUiBlueprintIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-blueprint-icon';
54
54
  import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon';
55
55
  import PencilAltIcon from '@patternfly/react-icons/dist/esm/icons/pencil-alt-icon';
56
56
  import CheckIcon from '@patternfly/react-icons/dist/esm/icons/check-icon';
57
- import TimesIcon from '@patternfly/react-icons/dist/esm/icons/times-icon';
57
+ import RhMicronsCloseIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-close-icon';
58
58
 
59
59
  import { css } from '@patternfly/react-styles';
60
60
  import styles from '@patternfly/react-styles/css/components/Table/table';
@@ -78,10 +78,13 @@ Some general notes:
78
78
  ```ts file="TableBasic.tsx"
79
79
 
80
80
  ```
81
- ### Table Plain
82
- ``` file="TablePlain.tsx"
81
+
82
+ ### Plain
83
+
84
+ ```ts file="TablePlain.tsx"
83
85
 
84
86
  ```
87
+
85
88
  ### Custom row wrapper, header tooltips & popovers
86
89
 
87
90
  - If you add the `noWrap` prop to `Thead`, it won't wrap it if there is no space
@@ -324,7 +327,6 @@ To enable a tree table:
324
327
  - `checkAriaLabel` - (optional) accessible label for the checkbox
325
328
  - `showDetailsAriaLabel` - (optional) accessible label for the show row details button in the responsive view
326
329
  4. The first `Td` in each row will pass the following to the `treeRow` prop:
327
-
328
330
  - `onCollapse` - Callback when user expands/collapses a row to reveal/hide the row's children.
329
331
  - `onCheckChange` - (optional) Callback when user changes the checkbox on a row.
330
332
  - `onToggleRowDetails` - (optional) Callback when user shows/hides the row details in responsive view.
@@ -416,6 +418,16 @@ To prevent the default text wrapping behavior and allow horizontal scrolling, al
416
418
 
417
419
  ```
418
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
+
419
431
  ### Sticky columns and header
420
432
 
421
433
  To maintain proper sticky behavior across sticky columns and header, `Table` must be wrapped with `OuterScrollContainer` and `InnerScrollContainer`.
@@ -23,7 +23,7 @@ interface Repository {
23
23
  singleAction: string;
24
24
  }
25
25
 
26
- type ExampleType = 'defaultToggle' | 'customToggle';
26
+ type ExampleType = 'customToggle';
27
27
 
28
28
  export const TableActions: React.FunctionComponent = () => {
29
29
  // In real usage, this data would come from some external source like an API via props.
@@ -45,10 +45,11 @@ export const TableActions: React.FunctionComponent = () => {
45
45
  };
46
46
 
47
47
  // This state is just for the ToggleGroup in this example and isn't necessary for Table usage.
48
- const [exampleChoice, setExampleChoice] = useState<ExampleType>('defaultToggle');
48
+ const [exampleChoice, setExampleChoice] = useState<ExampleType | ''>('');
49
49
  const onExampleTypeChange: ToggleGroupItemProps['onChange'] = (event, _isSelected) => {
50
50
  const id = event.currentTarget.id;
51
- setExampleChoice(id as ExampleType);
51
+ // Allow toggling off if clicking the already selected item
52
+ setExampleChoice(exampleChoice === id ? '' : (id as ExampleType));
52
53
  };
53
54
 
54
55
  const customActionsToggle = (props: CustomActionsToggleProps) => (
@@ -95,12 +96,6 @@ export const TableActions: React.FunctionComponent = () => {
95
96
  return (
96
97
  <Fragment>
97
98
  <ToggleGroup aria-label="Default uses kebab toggle">
98
- <ToggleGroupItem
99
- text="Default actions toggle"
100
- buttonId="defaultToggle"
101
- isSelected={exampleChoice === 'defaultToggle'}
102
- onChange={onExampleTypeChange}
103
- />
104
99
  <ToggleGroupItem
105
100
  text="Custom actions toggle"
106
101
  buttonId="customToggle"
@@ -10,7 +10,7 @@ interface Repository {
10
10
  lastCommit: string;
11
11
  }
12
12
 
13
- type ExampleType = 'default' | 'compact' | 'compactBorderless';
13
+ type ExampleType = 'compact' | 'compactBorderless';
14
14
 
15
15
  export const TableBasic: React.FunctionComponent = () => {
16
16
  // In real usage, this data would come from some external source like an API via props.
@@ -29,21 +29,16 @@ export const TableBasic: React.FunctionComponent = () => {
29
29
  };
30
30
 
31
31
  // This state is just for the ToggleGroup in this example and isn't necessary for Table usage.
32
- const [exampleChoice, setExampleChoice] = useState<ExampleType>('default');
32
+ const [exampleChoice, setExampleChoice] = useState<ExampleType | ''>('');
33
33
  const onExampleTypeChange: ToggleGroupItemProps['onChange'] = (event, _isSelected) => {
34
34
  const id = event.currentTarget.id;
35
- setExampleChoice(id as ExampleType);
35
+ // Allow toggling off if clicking the already selected item
36
+ setExampleChoice(exampleChoice === id ? '' : (id as ExampleType));
36
37
  };
37
38
 
38
39
  return (
39
40
  <Fragment>
40
41
  <ToggleGroup aria-label="Default with single selectable">
41
- <ToggleGroupItem
42
- text="Default"
43
- buttonId="default"
44
- isSelected={exampleChoice === 'default'}
45
- onChange={onExampleTypeChange}
46
- />
47
42
  <ToggleGroupItem
48
43
  text="Compact"
49
44
  buttonId="compact"
@@ -59,7 +54,7 @@ export const TableBasic: React.FunctionComponent = () => {
59
54
  </ToggleGroup>
60
55
  <Table
61
56
  aria-label="Simple table"
62
- variant={exampleChoice !== 'default' ? 'compact' : undefined}
57
+ variant={exampleChoice === 'compact' || exampleChoice === 'compactBorderless' ? 'compact' : undefined}
63
58
  borders={exampleChoice !== 'compactBorderless'}
64
59
  >
65
60
  <Caption>Simple table using composable components</Caption>
@@ -3,7 +3,7 @@ import { Table, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
3
3
  import { Button, Checkbox, Radio, TextInput, KeyTypes, getUniqueId } from '@patternfly/react-core';
4
4
  import PencilAltIcon from '@patternfly/react-icons/dist/esm/icons/pencil-alt-icon';
5
5
  import CheckIcon from '@patternfly/react-icons/dist/esm/icons/check-icon';
6
- import TimesIcon from '@patternfly/react-icons/dist/esm/icons/times-icon';
6
+ import RhMicronsCloseIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-close-icon';
7
7
  import inlineEditStyles from '@patternfly/react-styles/css/components/InlineEdit/inline-edit';
8
8
  import { css } from '@patternfly/react-styles';
9
9
 
@@ -60,7 +60,7 @@ const EditButtonsCell: React.FunctionComponent<EditButtonsCellProps> = ({
60
60
  onKeyDown={(event) => onKeyDown(event, 'stopEditing')}
61
61
  variant="plain"
62
62
  >
63
- <TimesIcon />
63
+ <RhMicronsCloseIcon />
64
64
  </Button>
65
65
  </div>
66
66
  </Td>
@@ -1,6 +1,6 @@
1
1
  import { useState } from 'react';
2
2
  import { Table, Thead, Tr, Th, Tbody, Td, InnerScrollContainer, ThProps } from '@patternfly/react-table';
3
- import BlueprintIcon from '@patternfly/react-icons/dist/esm/icons/blueprint-icon';
3
+ import RhUiBlueprintIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-blueprint-icon';
4
4
 
5
5
  interface Fact {
6
6
  name: string;
@@ -120,7 +120,7 @@ export const TableMultipleStickyColumns: React.FunctionComponent = () => {
120
120
  {fact.name}
121
121
  </Th>
122
122
  <Th isStickyColumn stickyMinWidth="120px" stickyLeftOffset="120px" modifier="truncate" hasRightBorder>
123
- <BlueprintIcon />
123
+ <RhUiBlueprintIcon />
124
124
  {` ${fact.state}`}
125
125
  </Th>
126
126
  <Td modifier="nowrap" dataLabel={columnNames.header3}>
@@ -11,7 +11,7 @@ import {
11
11
  ThProps,
12
12
  ISortBy
13
13
  } from '@patternfly/react-table';
14
- import BlueprintIcon from '@patternfly/react-icons/dist/esm/icons/blueprint-icon';
14
+ import RhUiBlueprintIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-blueprint-icon';
15
15
 
16
16
  interface Fact {
17
17
  name: string;
@@ -133,7 +133,7 @@ export const TableStickyColumnsAndHeader: React.FunctionComponent = () => {
133
133
  {fact.name}
134
134
  </Th>
135
135
  <Th isStickyColumn stickyMinWidth="120px" stickyLeftOffset="120px" modifier="truncate" hasRightBorder>
136
- <BlueprintIcon />
136
+ <RhUiBlueprintIcon />
137
137
  {` ${fact.state}`}
138
138
  </Th>
139
139
  <Td modifier="nowrap" dataLabel={columnNames.header3}>
@@ -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 RhUiBlueprintIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-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
+ <RhUiBlueprintIcon />
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
+ };
@@ -2,10 +2,10 @@ import { css } from '@patternfly/react-styles';
2
2
  import styles from '@patternfly/react-styles/css/components/Table/table';
3
3
  import { IExtra, IFormatterValueType, ITransform } from '../../TableTypes';
4
4
  import { SortColumn, SortByDirection } from '../../SortColumn';
5
- import StarIcon from '@patternfly/react-icons/dist/esm/icons/star-icon';
5
+ import RhUiStarFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-star-fill-icon';
6
6
 
7
7
  export const sortableFavorites = (sort: any) => () =>
8
- sortable(<StarIcon />, {
8
+ sortable(<RhUiStarFillIcon />, {
9
9
  columnIndex: sort.columnIndex,
10
10
  className: styles.tableFavorite,
11
11
  ariaLabel: sort.ariaLabel ?? 'Sort favorites',