@patternfly/react-table 6.0.0-alpha.96 → 6.0.0-alpha.98
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 +8 -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/TableTypes.d.ts.map +1 -1
- package/dist/esm/deprecated/components/Table/base/header-row.js +1 -1
- package/dist/esm/deprecated/components/Table/base/header-row.js.map +1 -1
- package/dist/js/components/Table/TableTypes.d.ts.map +1 -1
- package/dist/js/deprecated/components/Table/base/header-row.js +1 -1
- package/dist/js/deprecated/components/Table/base/header-row.js.map +1 -1
- package/dist/umd/assets/{output-Z6ljXPFB.css → output-BqxaVYKh.css} +4484 -4484
- package/dist/umd/react-table.min.js +1 -1
- package/package.json +6 -6
- package/src/components/Table/TableTypes.tsx +0 -1
- package/src/components/Table/examples/Table.md +11 -0
- package/src/components/Table/examples/TableActionsOverflow.tsx +0 -1
- package/src/components/Table/examples/TableEditable.tsx +313 -0
- package/src/components/Table/examples/TableExpandable.tsx +0 -1
- package/src/deprecated/components/Table/base/header-row.tsx +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patternfly/react-table",
|
|
3
|
-
"version": "6.0.0-alpha.
|
|
3
|
+
"version": "6.0.0-alpha.98",
|
|
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.js --config subpaths.config.json"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@patternfly/react-core": "^6.0.0-alpha.
|
|
44
|
-
"@patternfly/react-icons": "^6.0.0-alpha.
|
|
45
|
-
"@patternfly/react-styles": "^6.0.0-alpha.
|
|
46
|
-
"@patternfly/react-tokens": "^6.0.0-alpha.
|
|
43
|
+
"@patternfly/react-core": "^6.0.0-alpha.97",
|
|
44
|
+
"@patternfly/react-icons": "^6.0.0-alpha.35",
|
|
45
|
+
"@patternfly/react-styles": "^6.0.0-alpha.34",
|
|
46
|
+
"@patternfly/react-tokens": "^6.0.0-alpha.34",
|
|
47
47
|
"lodash": "^4.17.21",
|
|
48
48
|
"tslib": "^2.6.3"
|
|
49
49
|
},
|
|
@@ -51,5 +51,5 @@
|
|
|
51
51
|
"react": "^17 || ^18",
|
|
52
52
|
"react-dom": "^17 || ^18"
|
|
53
53
|
},
|
|
54
|
-
"gitHead": "
|
|
54
|
+
"gitHead": "5e19008b3872fc1fb2cdea963253d3d48e6cd329"
|
|
55
55
|
}
|
|
@@ -81,7 +81,6 @@ export type OnCheckChange = (
|
|
|
81
81
|
// Todo: Update type with next breaking change release
|
|
82
82
|
// export type IHeaderRow = ColumnType;
|
|
83
83
|
|
|
84
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
85
84
|
export interface IHeaderRow extends ColumnType {}
|
|
86
85
|
|
|
87
86
|
export interface IRowData extends IRow {
|
|
@@ -51,11 +51,15 @@ import FolderOpenIcon from '@patternfly/react-icons/dist/esm/icons/folder-open-i
|
|
|
51
51
|
import SortAmountDownIcon from '@patternfly/react-icons/dist/esm/icons/sort-amount-down-icon';
|
|
52
52
|
import BlueprintIcon from '@patternfly/react-icons/dist/esm/icons/blueprint-icon';
|
|
53
53
|
import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon';
|
|
54
|
+
import PencilAltIcon from '@patternfly/react-icons/dist/esm/icons/pencil-alt-icon';
|
|
55
|
+
import CheckIcon from '@patternfly/react-icons/dist/esm/icons/check-icon';
|
|
56
|
+
import TimesIcon from '@patternfly/react-icons/dist/esm/icons/times-icon';
|
|
54
57
|
|
|
55
58
|
import { css } from '@patternfly/react-styles';
|
|
56
59
|
import styles from '@patternfly/react-styles/css/components/Table/table';
|
|
57
60
|
import spacing from '@patternfly/react-styles/css/utilities/Spacing/spacing';
|
|
58
61
|
import textStyles from '@patternfly/react-styles/css/utilities/Text/text';
|
|
62
|
+
import inlineEditStyles from '@patternfly/react-styles/css/components/InlineEdit/inline-edit';
|
|
59
63
|
import global_background_color_secondary_default from '@patternfly/react-tokens/dist/esm/global_background_color_secondary_default';
|
|
60
64
|
|
|
61
65
|
## Table examples
|
|
@@ -163,6 +167,13 @@ This selectable rows feature is intended for use when a table is used to present
|
|
|
163
167
|
|
|
164
168
|
```
|
|
165
169
|
|
|
170
|
+
### Editable rows
|
|
171
|
+
|
|
172
|
+
This example shows a table with editable rows. Cells in a row can be edited after clicking on the edit icon.
|
|
173
|
+
|
|
174
|
+
```ts file="TableEditable.tsx"
|
|
175
|
+
```
|
|
176
|
+
|
|
166
177
|
### Actions
|
|
167
178
|
|
|
168
179
|
This example demonstrates adding actions as the last column. The header's last cell is an empty cell, and each body row's last cell is an action cell.
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Table, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
|
|
3
|
+
import { Button, Checkbox, Radio, TextInput, KeyTypes, getUniqueId } from '@patternfly/react-core';
|
|
4
|
+
import PencilAltIcon from '@patternfly/react-icons/dist/esm/icons/pencil-alt-icon';
|
|
5
|
+
import CheckIcon from '@patternfly/react-icons/dist/esm/icons/check-icon';
|
|
6
|
+
import TimesIcon from '@patternfly/react-icons/dist/esm/icons/times-icon';
|
|
7
|
+
import inlineEditStyles from '@patternfly/react-styles/css/components/InlineEdit/inline-edit';
|
|
8
|
+
import { css } from '@patternfly/react-styles';
|
|
9
|
+
|
|
10
|
+
interface EditButtonsCellProps {
|
|
11
|
+
onClick: (type: 'save' | 'cancel' | 'edit') => void;
|
|
12
|
+
elementToFocusOnEditRef?: React.MutableRefObject<HTMLElement>;
|
|
13
|
+
rowAriaLabel: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const EditButtonsCell: React.FunctionComponent<EditButtonsCellProps> = ({
|
|
17
|
+
onClick,
|
|
18
|
+
elementToFocusOnEditRef,
|
|
19
|
+
rowAriaLabel = 'row'
|
|
20
|
+
}) => {
|
|
21
|
+
const editButtonRef = React.useRef<HTMLButtonElement>();
|
|
22
|
+
|
|
23
|
+
const onKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>, button: 'edit' | 'stopEditing') => {
|
|
24
|
+
const focusRef = button === 'edit' ? elementToFocusOnEditRef : editButtonRef;
|
|
25
|
+
|
|
26
|
+
if (event.key === KeyTypes.Enter || event.key === KeyTypes.Space) {
|
|
27
|
+
// because space key triggers click event before keyDown, we have to prevent default behaviour and trigger click manually
|
|
28
|
+
event.preventDefault();
|
|
29
|
+
(event.target as HTMLButtonElement).click();
|
|
30
|
+
setTimeout(() => {
|
|
31
|
+
focusRef?.current?.focus();
|
|
32
|
+
}, 0);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<>
|
|
38
|
+
<Td
|
|
39
|
+
dataLabel="Save and cancel buttons"
|
|
40
|
+
className={css(
|
|
41
|
+
inlineEditStyles.inlineEditGroup,
|
|
42
|
+
inlineEditStyles.modifiers.iconGroup,
|
|
43
|
+
inlineEditStyles.modifiers.actionGroup
|
|
44
|
+
)}
|
|
45
|
+
>
|
|
46
|
+
<div className={css(inlineEditStyles.inlineEditAction, inlineEditStyles.modifiers.valid)}>
|
|
47
|
+
<Button
|
|
48
|
+
aria-label={`Save edits of ${rowAriaLabel}`}
|
|
49
|
+
onClick={() => onClick('save')}
|
|
50
|
+
onKeyDown={(event) => onKeyDown(event, 'stopEditing')}
|
|
51
|
+
variant="plain"
|
|
52
|
+
>
|
|
53
|
+
<CheckIcon />
|
|
54
|
+
</Button>
|
|
55
|
+
</div>
|
|
56
|
+
<div className={css(inlineEditStyles.inlineEditAction)}>
|
|
57
|
+
<Button
|
|
58
|
+
aria-label={`Discard edits of ${rowAriaLabel}`}
|
|
59
|
+
onClick={() => onClick('cancel')}
|
|
60
|
+
onKeyDown={(event) => onKeyDown(event, 'stopEditing')}
|
|
61
|
+
variant="plain"
|
|
62
|
+
>
|
|
63
|
+
<TimesIcon />
|
|
64
|
+
</Button>
|
|
65
|
+
</div>
|
|
66
|
+
</Td>
|
|
67
|
+
<Td
|
|
68
|
+
dataLabel="Edit button"
|
|
69
|
+
className={css(inlineEditStyles.inlineEditAction, inlineEditStyles.modifiers.enableEditable)}
|
|
70
|
+
>
|
|
71
|
+
<Button
|
|
72
|
+
ref={editButtonRef}
|
|
73
|
+
aria-label={`Edit ${rowAriaLabel}`}
|
|
74
|
+
onClick={() => onClick('edit')}
|
|
75
|
+
onKeyDown={(event) => onKeyDown(event, 'edit')}
|
|
76
|
+
variant="plain"
|
|
77
|
+
>
|
|
78
|
+
<PencilAltIcon />
|
|
79
|
+
</Button>
|
|
80
|
+
</Td>
|
|
81
|
+
</>
|
|
82
|
+
);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
interface EditableCellProps {
|
|
86
|
+
dataLabel: string;
|
|
87
|
+
staticValue: React.ReactNode;
|
|
88
|
+
editingValue: React.ReactNode;
|
|
89
|
+
role?: string;
|
|
90
|
+
ariaLabel?: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const EditableCell: React.FunctionComponent<EditableCellProps> = ({
|
|
94
|
+
dataLabel,
|
|
95
|
+
staticValue,
|
|
96
|
+
editingValue,
|
|
97
|
+
role,
|
|
98
|
+
ariaLabel
|
|
99
|
+
}) => {
|
|
100
|
+
const hasMultipleInputs = Array.isArray(editingValue) && editingValue.every((elem) => React.isValidElement(elem));
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<Td dataLabel={dataLabel}>
|
|
104
|
+
<div className={css(inlineEditStyles.inlineEditValue)}>{staticValue}</div>
|
|
105
|
+
{hasMultipleInputs ? (
|
|
106
|
+
<div className={css(inlineEditStyles.inlineEditGroup, 'pf-m-column')} role={role} aria-label={ariaLabel}>
|
|
107
|
+
{(editingValue as React.ReactElement[]).map((elem, index) => (
|
|
108
|
+
<div key={index} className={css(inlineEditStyles.inlineEditInput)}>
|
|
109
|
+
{elem}
|
|
110
|
+
</div>
|
|
111
|
+
))}
|
|
112
|
+
</div>
|
|
113
|
+
) : (
|
|
114
|
+
<div className={css(inlineEditStyles.inlineEditInput)}>{editingValue}</div>
|
|
115
|
+
)}
|
|
116
|
+
</Td>
|
|
117
|
+
);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
interface EditableRow {
|
|
121
|
+
data: CustomData;
|
|
122
|
+
columnNames: ColumnNames<CustomData>;
|
|
123
|
+
dataOptions?: CustomDataOptions;
|
|
124
|
+
saveChanges: (editedData: CustomData) => void;
|
|
125
|
+
ariaLabel: string;
|
|
126
|
+
rowIndex?: number;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const EditableRow: React.FunctionComponent<EditableRow> = ({
|
|
130
|
+
data,
|
|
131
|
+
columnNames,
|
|
132
|
+
dataOptions,
|
|
133
|
+
saveChanges,
|
|
134
|
+
ariaLabel,
|
|
135
|
+
rowIndex
|
|
136
|
+
}) => {
|
|
137
|
+
const [editable, setEditable] = React.useState(false);
|
|
138
|
+
const [editedData, setEditedData] = React.useState(data);
|
|
139
|
+
|
|
140
|
+
const inputRef = React.useRef();
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<Tr className={css(inlineEditStyles.inlineEdit, editable ? inlineEditStyles.modifiers.inlineEditable : '')}>
|
|
144
|
+
<EditableCell
|
|
145
|
+
dataLabel={columnNames.textInput}
|
|
146
|
+
staticValue={data.textInput}
|
|
147
|
+
editingValue={
|
|
148
|
+
<TextInput
|
|
149
|
+
aria-label={`${columnNames.textInput} ${ariaLabel}`}
|
|
150
|
+
ref={inputRef}
|
|
151
|
+
value={editedData.textInput}
|
|
152
|
+
onChange={(e) => setEditedData((data) => ({ ...data, textInput: (e.target as HTMLInputElement).value }))}
|
|
153
|
+
/>
|
|
154
|
+
}
|
|
155
|
+
/>
|
|
156
|
+
<EditableCell
|
|
157
|
+
dataLabel={columnNames.textInputDisabled}
|
|
158
|
+
staticValue={data.textInputDisabled}
|
|
159
|
+
editingValue={
|
|
160
|
+
<TextInput
|
|
161
|
+
aria-label={`${columnNames.textInputDisabled} ${ariaLabel}`}
|
|
162
|
+
isDisabled={true}
|
|
163
|
+
value={editedData.textInputDisabled ?? ''}
|
|
164
|
+
/>
|
|
165
|
+
}
|
|
166
|
+
/>
|
|
167
|
+
<EditableCell
|
|
168
|
+
dataLabel={columnNames.checkboxes}
|
|
169
|
+
staticValue={data.checkboxes.join(', ')}
|
|
170
|
+
role="group"
|
|
171
|
+
ariaLabel={`Checkbox group row ${rowIndex}`}
|
|
172
|
+
editingValue={dataOptions?.checkboxes.map((option) => {
|
|
173
|
+
const id = getUniqueId('checkbox');
|
|
174
|
+
return (
|
|
175
|
+
<Checkbox
|
|
176
|
+
key={id}
|
|
177
|
+
name={id}
|
|
178
|
+
id={id}
|
|
179
|
+
label={option}
|
|
180
|
+
isChecked={editedData.checkboxes.includes(option)}
|
|
181
|
+
onChange={(_e, checked) =>
|
|
182
|
+
setEditedData((data) => ({
|
|
183
|
+
...data,
|
|
184
|
+
checkboxes: checked ? [...data.checkboxes, option] : data.checkboxes.filter((item) => item !== option)
|
|
185
|
+
}))
|
|
186
|
+
}
|
|
187
|
+
/>
|
|
188
|
+
);
|
|
189
|
+
})}
|
|
190
|
+
/>
|
|
191
|
+
<EditableCell
|
|
192
|
+
dataLabel={columnNames.radios}
|
|
193
|
+
staticValue={data.radios}
|
|
194
|
+
ariaLabel={`Radio button group row ${rowIndex}`}
|
|
195
|
+
role="radiogroup"
|
|
196
|
+
editingValue={dataOptions?.radios.map((option) => {
|
|
197
|
+
const id = getUniqueId('radio');
|
|
198
|
+
return (
|
|
199
|
+
<Radio
|
|
200
|
+
key={id}
|
|
201
|
+
name={id}
|
|
202
|
+
id={id}
|
|
203
|
+
label={option}
|
|
204
|
+
isChecked={editedData.radios === option}
|
|
205
|
+
onChange={() => setEditedData((data) => ({ ...data, radios: option }))}
|
|
206
|
+
/>
|
|
207
|
+
);
|
|
208
|
+
})}
|
|
209
|
+
/>
|
|
210
|
+
<EditButtonsCell
|
|
211
|
+
onClick={(type) => {
|
|
212
|
+
type === 'edit' ? setEditable(true) : setEditable(false);
|
|
213
|
+
type === 'save' && saveChanges(editedData);
|
|
214
|
+
type === 'cancel' && setEditedData(data);
|
|
215
|
+
}}
|
|
216
|
+
rowAriaLabel={ariaLabel}
|
|
217
|
+
elementToFocusOnEditRef={inputRef}
|
|
218
|
+
/>
|
|
219
|
+
</Tr>
|
|
220
|
+
);
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
interface CustomData {
|
|
224
|
+
textInput: string;
|
|
225
|
+
textInputDisabled: string | null;
|
|
226
|
+
checkboxes: string[];
|
|
227
|
+
radios: string;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
interface CustomDataOptions {
|
|
231
|
+
checkboxes: string[];
|
|
232
|
+
radios: string[];
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
type ColumnNames<T> = { [K in keyof T]: string };
|
|
236
|
+
|
|
237
|
+
export const TableEditable: React.FunctionComponent = () => {
|
|
238
|
+
// In real usage, this data would come from some external source like an API via props.
|
|
239
|
+
const initialRows: CustomData[] = [
|
|
240
|
+
{
|
|
241
|
+
textInput: 'Editable text 1',
|
|
242
|
+
textInputDisabled: 'Non-editable text 1',
|
|
243
|
+
checkboxes: ['Option A'],
|
|
244
|
+
radios: 'Option A'
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
textInput: 'Editable text 2',
|
|
248
|
+
textInputDisabled: null,
|
|
249
|
+
checkboxes: [],
|
|
250
|
+
radios: 'Option B'
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
textInput: 'Editable text 3',
|
|
254
|
+
textInputDisabled: 'Non-editable text 3',
|
|
255
|
+
checkboxes: ['Option A', 'Option B'],
|
|
256
|
+
radios: 'Option A'
|
|
257
|
+
}
|
|
258
|
+
];
|
|
259
|
+
|
|
260
|
+
// List of all selectable options for some cells of initialRows
|
|
261
|
+
const initialRowsOptions: CustomDataOptions[] = [
|
|
262
|
+
{
|
|
263
|
+
checkboxes: ['Option A', 'Option B', 'Option C'],
|
|
264
|
+
radios: ['Option A', 'Option B']
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
checkboxes: ['Option A', 'Option B'],
|
|
268
|
+
radios: ['Option A', 'Option B', 'Option C']
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
checkboxes: ['Option A', 'Option B'],
|
|
272
|
+
radios: ['Option A', 'Option B']
|
|
273
|
+
}
|
|
274
|
+
];
|
|
275
|
+
|
|
276
|
+
const [rows, setRows] = React.useState(initialRows);
|
|
277
|
+
|
|
278
|
+
const columnNames: ColumnNames<CustomData> = {
|
|
279
|
+
textInput: 'Text input',
|
|
280
|
+
textInputDisabled: 'Disabled text input',
|
|
281
|
+
checkboxes: 'Checkboxes',
|
|
282
|
+
radios: 'Radios'
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
return (
|
|
286
|
+
<Table aria-label="Editable table">
|
|
287
|
+
<Thead>
|
|
288
|
+
<Tr>
|
|
289
|
+
<Th>{columnNames.textInput}</Th>
|
|
290
|
+
<Th>{columnNames.textInputDisabled}</Th>
|
|
291
|
+
<Th>{columnNames.checkboxes}</Th>
|
|
292
|
+
<Th>{columnNames.radios}</Th>
|
|
293
|
+
<Th screenReaderText="Row edit actions" />
|
|
294
|
+
</Tr>
|
|
295
|
+
</Thead>
|
|
296
|
+
<Tbody>
|
|
297
|
+
{rows.map((data, index) => (
|
|
298
|
+
<EditableRow
|
|
299
|
+
key={index}
|
|
300
|
+
data={data}
|
|
301
|
+
rowIndex={index}
|
|
302
|
+
dataOptions={initialRowsOptions[index]}
|
|
303
|
+
columnNames={columnNames}
|
|
304
|
+
saveChanges={(editedRow) => {
|
|
305
|
+
setRows((rows) => rows.map((row, i) => (i === index ? editedRow : row)));
|
|
306
|
+
}}
|
|
307
|
+
ariaLabel={`row ${index + 1}`}
|
|
308
|
+
></EditableRow>
|
|
309
|
+
))}
|
|
310
|
+
</Tbody>
|
|
311
|
+
</Table>
|
|
312
|
+
);
|
|
313
|
+
};
|
|
@@ -16,7 +16,6 @@ interface Repository {
|
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
20
19
|
export const TableExpandable: React.FunctionComponent = () => {
|
|
21
20
|
// In real usage, this data would come from some external source like an API via props.
|
|
22
21
|
const repositories: Repository[] = [
|
|
@@ -46,7 +46,7 @@ export const HeaderRow: React.FunctionComponent<HeaderRowProps> = ({
|
|
|
46
46
|
|
|
47
47
|
if (!transformedProps) {
|
|
48
48
|
// tslint:disable-next-line:no-console
|
|
49
|
-
console.warn('Table.Header - Failed to receive a transformed result'); // eslint-disable-line
|
|
49
|
+
console.warn('Table.Header - Failed to receive a transformed result'); // eslint-disable-line no-console
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
let cellNode;
|