@patternfly/react-table 6.5.0-prerelease.75 → 6.5.0-prerelease.77
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 +10 -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/SelectColumn.d.ts +2 -0
- package/dist/esm/components/Table/SelectColumn.d.ts.map +1 -1
- package/dist/esm/components/Table/SelectColumn.js +3 -2
- package/dist/esm/components/Table/SelectColumn.js.map +1 -1
- package/dist/esm/components/Table/TableTypes.d.ts +1 -0
- package/dist/esm/components/Table/TableTypes.d.ts.map +1 -1
- package/dist/esm/components/Table/Th.d.ts.map +1 -1
- package/dist/esm/components/Table/Th.js +2 -1
- package/dist/esm/components/Table/Th.js.map +1 -1
- package/dist/esm/components/Table/base/types.d.ts +2 -0
- package/dist/esm/components/Table/base/types.d.ts.map +1 -1
- package/dist/esm/components/Table/base/types.js.map +1 -1
- package/dist/esm/components/Table/utils/decorators/selectable.d.ts.map +1 -1
- package/dist/esm/components/Table/utils/decorators/selectable.js +2 -2
- package/dist/esm/components/Table/utils/decorators/selectable.js.map +1 -1
- package/dist/js/components/Table/SelectColumn.d.ts +2 -0
- package/dist/js/components/Table/SelectColumn.d.ts.map +1 -1
- package/dist/js/components/Table/SelectColumn.js +3 -2
- package/dist/js/components/Table/SelectColumn.js.map +1 -1
- package/dist/js/components/Table/TableTypes.d.ts +1 -0
- package/dist/js/components/Table/TableTypes.d.ts.map +1 -1
- package/dist/js/components/Table/Th.d.ts.map +1 -1
- package/dist/js/components/Table/Th.js +2 -1
- package/dist/js/components/Table/Th.js.map +1 -1
- package/dist/js/components/Table/base/types.d.ts +2 -0
- package/dist/js/components/Table/base/types.d.ts.map +1 -1
- package/dist/js/components/Table/base/types.js.map +1 -1
- package/dist/js/components/Table/utils/decorators/selectable.d.ts.map +1 -1
- package/dist/js/components/Table/utils/decorators/selectable.js +2 -2
- package/dist/js/components/Table/utils/decorators/selectable.js.map +1 -1
- package/dist/umd/assets/{output-Bcoo6kWu.css → output-CSi7jW03.css} +2316 -2316
- package/dist/umd/react-table.min.js +3 -3
- package/package.json +6 -6
- package/src/components/Table/SelectColumn.tsx +9 -1
- package/src/components/Table/TableTypes.tsx +1 -0
- package/src/components/Table/Th.tsx +2 -1
- package/src/components/Table/__tests__/Th.test.tsx +23 -0
- package/src/components/Table/base/types.tsx +2 -0
- package/src/components/Table/examples/Table.md +8 -0
- package/src/components/Table/examples/TableSelectableIndeterminate.tsx +128 -0
- package/src/components/Table/utils/decorators/selectable.tsx +2 -1
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.77",
|
|
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,10 +40,10 @@
|
|
|
40
40
|
"subpaths": "node ../../scripts/exportSubpaths.mjs --config subpaths.config.json"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@patternfly/react-core": "^6.5.0-prerelease.
|
|
44
|
-
"@patternfly/react-icons": "^6.5.0-prerelease.
|
|
45
|
-
"@patternfly/react-styles": "^6.5.0-prerelease.
|
|
46
|
-
"@patternfly/react-tokens": "^6.5.0-prerelease.
|
|
43
|
+
"@patternfly/react-core": "^6.5.0-prerelease.73",
|
|
44
|
+
"@patternfly/react-icons": "^6.5.0-prerelease.34",
|
|
45
|
+
"@patternfly/react-styles": "^6.5.0-prerelease.24",
|
|
46
|
+
"@patternfly/react-tokens": "^6.5.0-prerelease.23",
|
|
47
47
|
"lodash": "^4.18.1",
|
|
48
48
|
"tslib": "^2.8.1"
|
|
49
49
|
},
|
|
@@ -51,5 +51,5 @@
|
|
|
51
51
|
"react": "^17 || ^18 || ^19",
|
|
52
52
|
"react-dom": "^17 || ^18 || ^19"
|
|
53
53
|
},
|
|
54
|
-
"gitHead": "
|
|
54
|
+
"gitHead": "f937b3a1b22083cb926adb0fd02366b998173418"
|
|
55
55
|
}
|
|
@@ -21,6 +21,8 @@ export interface SelectColumnProps {
|
|
|
21
21
|
id?: string;
|
|
22
22
|
/** name for the input element - required by Radio component */
|
|
23
23
|
name?: string;
|
|
24
|
+
/** Whether the checkbox should be in an indeterminate state */
|
|
25
|
+
isIndeterminate?: boolean;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
export const SelectColumn: React.FunctionComponent<SelectColumnProps> = ({
|
|
@@ -33,6 +35,7 @@ export const SelectColumn: React.FunctionComponent<SelectColumnProps> = ({
|
|
|
33
35
|
tooltipProps,
|
|
34
36
|
id,
|
|
35
37
|
name,
|
|
38
|
+
isIndeterminate,
|
|
36
39
|
...props
|
|
37
40
|
}: SelectColumnProps) => {
|
|
38
41
|
const inputRef = createRef<any>();
|
|
@@ -48,10 +51,15 @@ export const SelectColumn: React.FunctionComponent<SelectColumnProps> = ({
|
|
|
48
51
|
onChange: handleChange
|
|
49
52
|
};
|
|
50
53
|
|
|
54
|
+
const checkboxProps = {
|
|
55
|
+
...commonProps,
|
|
56
|
+
...(isIndeterminate && { isChecked: null })
|
|
57
|
+
};
|
|
58
|
+
|
|
51
59
|
const content = (
|
|
52
60
|
<Fragment>
|
|
53
61
|
{selectVariant === RowSelectVariant.checkbox ? (
|
|
54
|
-
<Checkbox {...
|
|
62
|
+
<Checkbox {...checkboxProps} />
|
|
55
63
|
) : (
|
|
56
64
|
<Radio {...commonProps} name={name} />
|
|
57
65
|
)}
|
|
@@ -158,7 +158,8 @@ const ThBase: React.FunctionComponent<ThProps> = ({
|
|
|
158
158
|
onSelect: select?.onSelect,
|
|
159
159
|
selectVariant: 'checkbox',
|
|
160
160
|
allRowsSelected: select.isSelected,
|
|
161
|
-
isHeaderSelectDisabled: !!select.isHeaderSelectDisabled
|
|
161
|
+
isHeaderSelectDisabled: !!select.isHeaderSelectDisabled,
|
|
162
|
+
isIndeterminate: select?.isIndeterminate
|
|
162
163
|
}
|
|
163
164
|
},
|
|
164
165
|
tooltip: tooltip as string,
|
|
@@ -54,3 +54,26 @@ test('Additional content renders after children when additionalContent is passed
|
|
|
54
54
|
expect(thChildren.item(0)?.textContent).toEqual('Test');
|
|
55
55
|
expect(thChildren.item(1)?.textContent).toEqual('Extra');
|
|
56
56
|
});
|
|
57
|
+
|
|
58
|
+
test('Renders checkbox without indeterminate state by default', () => {
|
|
59
|
+
render(<Th select={{ onSelect: jest.fn(), isSelected: false }} aria-label="Select all" />);
|
|
60
|
+
|
|
61
|
+
const checkbox = screen.getByRole('checkbox') as HTMLInputElement;
|
|
62
|
+
expect(checkbox).not.toBeChecked();
|
|
63
|
+
expect(checkbox.indeterminate).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test('Renders checkbox with indeterminate state when isIndeterminate is true', () => {
|
|
67
|
+
render(<Th select={{ onSelect: jest.fn(), isSelected: false, isIndeterminate: true }} aria-label="Select all" />);
|
|
68
|
+
|
|
69
|
+
const checkbox = screen.getByRole('checkbox') as HTMLInputElement;
|
|
70
|
+
expect(checkbox.indeterminate).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('Renders checked checkbox when isSelected is true and isIndeterminate is false', () => {
|
|
74
|
+
render(<Th select={{ onSelect: jest.fn(), isSelected: true, isIndeterminate: false }} aria-label="Select all" />);
|
|
75
|
+
|
|
76
|
+
const checkbox = screen.getByRole('checkbox') as HTMLInputElement;
|
|
77
|
+
expect(checkbox).toBeChecked();
|
|
78
|
+
expect(checkbox.indeterminate).toBe(false);
|
|
79
|
+
});
|
|
@@ -180,6 +180,8 @@ export interface ThSelectType {
|
|
|
180
180
|
onSelect?: OnSelect;
|
|
181
181
|
/** Whether the cell is selected */
|
|
182
182
|
isSelected: boolean;
|
|
183
|
+
/** Whether the select checkbox should be in an indeterminate state (some items selected) */
|
|
184
|
+
isIndeterminate?: boolean;
|
|
183
185
|
/** Flag indicating the select checkbox in the th is disabled */
|
|
184
186
|
isHeaderSelectDisabled?: boolean;
|
|
185
187
|
/** Whether to disable the selection */
|
|
@@ -158,6 +158,14 @@ checking checkboxes will check intermediate rows' checkboxes.
|
|
|
158
158
|
|
|
159
159
|
```
|
|
160
160
|
|
|
161
|
+
### Selectable with indeterminate state
|
|
162
|
+
|
|
163
|
+
To indicate partial selection, use `isIndeterminate` on the header's `select` prop. When some (but not all) selectable rows are selected, the header checkbox will convey this information to assistive technologies and also display a dash instead of a checkmark.
|
|
164
|
+
|
|
165
|
+
```ts file="TableSelectableIndeterminate.tsx"
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
|
|
161
169
|
### Selectable radio input
|
|
162
170
|
|
|
163
171
|
Similarly to the selectable example above, the radio buttons use the first column. The first header cell is empty, and each body row's first cell has radio button props.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { Table, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
|
|
3
|
+
|
|
4
|
+
interface Repository {
|
|
5
|
+
name: string;
|
|
6
|
+
branches: string;
|
|
7
|
+
prs: string;
|
|
8
|
+
workspaces: string;
|
|
9
|
+
lastCommit: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const TableSelectableIndeterminate: React.FunctionComponent = () => {
|
|
13
|
+
// In real usage, this data would come from some external source like an API via props.
|
|
14
|
+
const repositories: Repository[] = [
|
|
15
|
+
{ name: 'one', branches: 'two', prs: 'a', workspaces: 'four', lastCommit: 'five' },
|
|
16
|
+
{ name: 'a', branches: 'two', prs: 'k', workspaces: 'four', lastCommit: 'five' },
|
|
17
|
+
{ name: 'b', branches: 'two', prs: 'k', workspaces: 'four', lastCommit: 'five' },
|
|
18
|
+
{ name: 'c', branches: 'two', prs: 'k', workspaces: 'four', lastCommit: 'five' },
|
|
19
|
+
{ name: 'd', branches: 'two', prs: 'k', workspaces: 'four', lastCommit: 'five' },
|
|
20
|
+
{ name: 'e', branches: 'two', prs: 'b', workspaces: 'four', lastCommit: 'five' }
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const columnNames = {
|
|
24
|
+
name: 'Repositories',
|
|
25
|
+
branches: 'Branches',
|
|
26
|
+
prs: 'Pull requests',
|
|
27
|
+
workspaces: 'Workspaces',
|
|
28
|
+
lastCommit: 'Last commit'
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const isRepoSelectable = (repo: Repository) => repo.name !== 'a'; // Arbitrary logic for this example
|
|
32
|
+
const selectableRepos = repositories.filter(isRepoSelectable);
|
|
33
|
+
|
|
34
|
+
// In this example, selected rows are tracked by the repo names from each row. This could be any unique identifier.
|
|
35
|
+
// This is to prevent state from being based on row order index in case we later add sorting.
|
|
36
|
+
const [selectedRepoNames, setSelectedRepoNames] = useState<string[]>([]);
|
|
37
|
+
const setRepoSelected = (repo: Repository, isSelecting = true) =>
|
|
38
|
+
setSelectedRepoNames((prevSelected) => {
|
|
39
|
+
const otherSelectedRepoNames = prevSelected.filter((r) => r !== repo.name);
|
|
40
|
+
return isSelecting && isRepoSelectable(repo) ? [...otherSelectedRepoNames, repo.name] : otherSelectedRepoNames;
|
|
41
|
+
});
|
|
42
|
+
const selectAllRepos = (isSelecting = true) =>
|
|
43
|
+
setSelectedRepoNames(isSelecting ? selectableRepos.map((r) => r.name) : []);
|
|
44
|
+
const areAllReposSelected = selectedRepoNames.length === selectableRepos.length;
|
|
45
|
+
const areSomeReposSelected = selectedRepoNames.length > 0 && selectedRepoNames.length < selectableRepos.length;
|
|
46
|
+
const isRepoSelected = (repo: Repository) => selectedRepoNames.includes(repo.name);
|
|
47
|
+
|
|
48
|
+
// To allow shift+click to select/deselect multiple rows
|
|
49
|
+
const [recentSelectedRowIndex, setRecentSelectedRowIndex] = useState<number | null>(null);
|
|
50
|
+
const [shifting, setShifting] = useState(false);
|
|
51
|
+
|
|
52
|
+
const onSelectRepo = (repo: Repository, rowIndex: number, isSelecting: boolean) => {
|
|
53
|
+
// If the user is shift + selecting the checkboxes, then all intermediate checkboxes should be selected
|
|
54
|
+
if (shifting && recentSelectedRowIndex !== null) {
|
|
55
|
+
const numberSelected = rowIndex - recentSelectedRowIndex;
|
|
56
|
+
const intermediateIndexes =
|
|
57
|
+
numberSelected > 0
|
|
58
|
+
? Array.from(new Array(numberSelected + 1), (_x, i) => i + recentSelectedRowIndex)
|
|
59
|
+
: Array.from(new Array(Math.abs(numberSelected) + 1), (_x, i) => i + rowIndex);
|
|
60
|
+
intermediateIndexes.forEach((index) => setRepoSelected(repositories[index], isSelecting));
|
|
61
|
+
} else {
|
|
62
|
+
setRepoSelected(repo, isSelecting);
|
|
63
|
+
}
|
|
64
|
+
setRecentSelectedRowIndex(rowIndex);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
const onKeyDown = (e: KeyboardEvent) => {
|
|
69
|
+
if (e.key === 'Shift') {
|
|
70
|
+
setShifting(true);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
const onKeyUp = (e: KeyboardEvent) => {
|
|
74
|
+
if (e.key === 'Shift') {
|
|
75
|
+
setShifting(false);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
document.addEventListener('keydown', onKeyDown);
|
|
80
|
+
document.addEventListener('keyup', onKeyUp);
|
|
81
|
+
|
|
82
|
+
return () => {
|
|
83
|
+
document.removeEventListener('keydown', onKeyDown);
|
|
84
|
+
document.removeEventListener('keyup', onKeyUp);
|
|
85
|
+
};
|
|
86
|
+
}, []);
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<Table aria-label="Selectable table with indeterminate state">
|
|
90
|
+
<Thead>
|
|
91
|
+
<Tr>
|
|
92
|
+
<Th
|
|
93
|
+
select={{
|
|
94
|
+
onSelect: (_event, isSelecting) => selectAllRepos(isSelecting),
|
|
95
|
+
isSelected: areAllReposSelected,
|
|
96
|
+
isIndeterminate: areSomeReposSelected
|
|
97
|
+
}}
|
|
98
|
+
aria-label="Row select"
|
|
99
|
+
/>
|
|
100
|
+
<Th>{columnNames.name}</Th>
|
|
101
|
+
<Th>{columnNames.branches}</Th>
|
|
102
|
+
<Th>{columnNames.prs}</Th>
|
|
103
|
+
<Th>{columnNames.workspaces}</Th>
|
|
104
|
+
<Th>{columnNames.lastCommit}</Th>
|
|
105
|
+
</Tr>
|
|
106
|
+
</Thead>
|
|
107
|
+
<Tbody>
|
|
108
|
+
{repositories.map((repo, rowIndex) => (
|
|
109
|
+
<Tr key={repo.name}>
|
|
110
|
+
<Td
|
|
111
|
+
select={{
|
|
112
|
+
rowIndex,
|
|
113
|
+
onSelect: (_event, isSelecting) => onSelectRepo(repo, rowIndex, isSelecting),
|
|
114
|
+
isSelected: isRepoSelected(repo),
|
|
115
|
+
isDisabled: !isRepoSelectable(repo)
|
|
116
|
+
}}
|
|
117
|
+
/>
|
|
118
|
+
<Td dataLabel={columnNames.name}>{repo.name}</Td>
|
|
119
|
+
<Td dataLabel={columnNames.branches}>{repo.branches}</Td>
|
|
120
|
+
<Td dataLabel={columnNames.prs}>{repo.prs}</Td>
|
|
121
|
+
<Td dataLabel={columnNames.workspaces}>{repo.workspaces}</Td>
|
|
122
|
+
<Td dataLabel={columnNames.lastCommit}>{repo.lastCommit}</Td>
|
|
123
|
+
</Tr>
|
|
124
|
+
))}
|
|
125
|
+
</Tbody>
|
|
126
|
+
</Table>
|
|
127
|
+
);
|
|
128
|
+
};
|
|
@@ -9,7 +9,7 @@ export const selectable: ITransform = (
|
|
|
9
9
|
{ rowIndex, columnIndex, rowData, column, property, tooltip }: IExtra
|
|
10
10
|
) => {
|
|
11
11
|
const {
|
|
12
|
-
extraParams: { onSelect, selectVariant, allRowsSelected, isHeaderSelectDisabled }
|
|
12
|
+
extraParams: { onSelect, selectVariant, allRowsSelected, isHeaderSelectDisabled, isIndeterminate }
|
|
13
13
|
} = column;
|
|
14
14
|
const extraData = {
|
|
15
15
|
rowIndex,
|
|
@@ -70,6 +70,7 @@ export const selectable: ITransform = (
|
|
|
70
70
|
onSelect={selectClick}
|
|
71
71
|
name={selectName}
|
|
72
72
|
tooltip={tooltip}
|
|
73
|
+
isIndeterminate={rowId === -1 ? isIndeterminate : undefined}
|
|
73
74
|
>
|
|
74
75
|
{label as React.ReactNode}
|
|
75
76
|
</SelectColumn>
|