@patternfly/react-core 4.247.0 → 4.248.0
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 +19 -0
- package/dist/esm/components/Menu/Menu.d.ts.map +1 -1
- package/dist/esm/components/Menu/Menu.js +10 -3
- package/dist/esm/components/Menu/Menu.js.map +1 -1
- package/dist/esm/components/MenuToggle/MenuToggle.d.ts.map +1 -1
- package/dist/esm/components/MenuToggle/MenuToggle.js +1 -1
- package/dist/esm/components/MenuToggle/MenuToggle.js.map +1 -1
- package/dist/js/components/Menu/Menu.d.ts.map +1 -1
- package/dist/js/components/Menu/Menu.js +10 -3
- package/dist/js/components/Menu/Menu.js.map +1 -1
- package/dist/js/components/MenuToggle/MenuToggle.d.ts.map +1 -1
- package/dist/js/components/MenuToggle/MenuToggle.js +1 -1
- package/dist/js/components/MenuToggle/MenuToggle.js.map +1 -1
- package/dist/umd/react-core.min.css +1942 -1942
- package/dist/umd/react-core.min.js +1 -1
- package/package.json +2 -2
- package/src/components/Menu/Menu.tsx +13 -7
- package/src/components/MenuToggle/MenuToggle.tsx +1 -0
- package/src/demos/Filters/FilterDemos.md +27 -5
- package/src/demos/Filters/examples/FilterAttributeSearch.tsx +701 -0
- package/src/demos/Filters/examples/FilterCheckboxSelect.tsx +66 -53
- package/src/demos/Filters/examples/FilterFaceted.tsx +512 -0
- package/src/demos/Filters/examples/FilterMixedSelectGroup.tsx +569 -0
- package/src/demos/Filters/examples/FilterSameSelectGroup.tsx +542 -0
- package/src/demos/Filters/examples/FilterSearchInput.tsx +91 -68
- package/src/demos/Filters/examples/FilterSingleSelect.tsx +63 -52
- package/src/demos/Page.md +47 -0
- package/src/demos/examples/DashboardWrapper.js +3 -1
- package/src/demos/examples/Page/PageStickySectionBreadcrumb.tsx +305 -0
- package/src/demos/examples/Page/PageStickySectionGroup.tsx +306 -0
- package/src/demos/examples/Page/PageStickySectionGroupAlternate.tsx +301 -0
- package/src/demos/examples/Page/PageStickySectionGroupUsingPageHeader.tsx +293 -0
- package/src/demos/Page/Page.md +0 -1184
- package/src/demos/Page/imgAvatar.svg +0 -33
- package/src/demos/Page/imgBrand.svg +0 -1
|
@@ -32,7 +32,7 @@ const repositories: Repository[] = [
|
|
|
32
32
|
{ name: 'US-Node 1', threads: '5', apps: '25', workspaces: '5', status: 'Stopped', location: 'Raleigh' },
|
|
33
33
|
{ name: 'US-Node 2', threads: '5', apps: '30', workspaces: '2', status: 'Down', location: 'Westford' },
|
|
34
34
|
{ name: 'US-Node 3', threads: '13', apps: '35', workspaces: '12', status: 'Degraded', location: 'Boston' },
|
|
35
|
-
{ name: 'US-Node 4', threads: '2', apps: '5', workspaces: '18', status: 'Needs
|
|
35
|
+
{ name: 'US-Node 4', threads: '2', apps: '5', workspaces: '18', status: 'Needs Maintenance', location: 'Raleigh' },
|
|
36
36
|
{ name: 'US-Node 5', threads: '7', apps: '30', workspaces: '5', status: 'Running', location: 'Boston' },
|
|
37
37
|
{ name: 'US-Node 6', threads: '5', apps: '20', workspaces: '15', status: 'Stopped', location: 'Raleigh' },
|
|
38
38
|
{ name: 'CZ-Node 1', threads: '12', apps: '48', workspaces: '13', status: 'Down', location: 'Brno' },
|
|
@@ -52,12 +52,30 @@ const columnNames = {
|
|
|
52
52
|
|
|
53
53
|
/* eslint-disable patternfly-react/no-anonymous-functions */
|
|
54
54
|
export const FilterCheckboxSelect: React.FunctionComponent = () => {
|
|
55
|
-
// Set up
|
|
56
|
-
const
|
|
57
|
-
const
|
|
55
|
+
// Set up repo filtering
|
|
56
|
+
const [selections, setSelections] = React.useState<string[]>([]);
|
|
57
|
+
const onFilter = (repo: Repository) => {
|
|
58
|
+
if (selections.length === 0) {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return selections.some(searchValue => {
|
|
63
|
+
let input: RegExp;
|
|
64
|
+
try {
|
|
65
|
+
input = new RegExp(searchValue, 'i');
|
|
66
|
+
} catch (err) {
|
|
67
|
+
input = new RegExp(searchValue.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i');
|
|
68
|
+
}
|
|
69
|
+
return repo.location.search(input) >= 0;
|
|
70
|
+
});
|
|
71
|
+
};
|
|
58
72
|
|
|
73
|
+
const filteredRepos = repositories.filter(onFilter);
|
|
74
|
+
|
|
75
|
+
// Set up table selection
|
|
59
76
|
// In this example, selected rows are tracked by the repo names from each row. This could be any unique identifier.
|
|
60
77
|
// This is to prevent state from being based on row order index in case we later add sorting.
|
|
78
|
+
const isRepoSelectable = (repo: Repository) => repo.name !== 'a'; // Arbitrary logic for this example
|
|
61
79
|
const [selectedRepoNames, setSelectedRepoNames] = React.useState<string[]>([]);
|
|
62
80
|
const setRepoSelected = (repo: Repository, isSelecting = true) =>
|
|
63
81
|
setSelectedRepoNames(prevSelected => {
|
|
@@ -65,8 +83,8 @@ export const FilterCheckboxSelect: React.FunctionComponent = () => {
|
|
|
65
83
|
return isSelecting && isRepoSelectable(repo) ? [...otherSelectedRepoNames, repo.name] : otherSelectedRepoNames;
|
|
66
84
|
});
|
|
67
85
|
const selectAllRepos = (isSelecting = true) =>
|
|
68
|
-
setSelectedRepoNames(isSelecting ?
|
|
69
|
-
const areAllReposSelected = selectedRepoNames.length ===
|
|
86
|
+
setSelectedRepoNames(isSelecting ? filteredRepos.map(r => r.name) : []);
|
|
87
|
+
const areAllReposSelected = selectedRepoNames.length === filteredRepos.length && filteredRepos.length > 0;
|
|
70
88
|
const areSomeReposSelected = selectedRepoNames.length > 0;
|
|
71
89
|
const isRepoSelected = (repo: Repository) => selectedRepoNames.includes(repo.name);
|
|
72
90
|
|
|
@@ -111,21 +129,12 @@ export const FilterCheckboxSelect: React.FunctionComponent = () => {
|
|
|
111
129
|
}, []);
|
|
112
130
|
|
|
113
131
|
// Set up bulk selection menu
|
|
114
|
-
const bulkSelectMenuRef = React.
|
|
115
|
-
const bulkSelectToggleRef = React.
|
|
116
|
-
const
|
|
132
|
+
const bulkSelectMenuRef = React.useRef<HTMLDivElement>(null);
|
|
133
|
+
const bulkSelectToggleRef = React.useRef<any>(null);
|
|
134
|
+
const bulkSelectContainerRef = React.useRef<HTMLDivElement>(null);
|
|
117
135
|
|
|
118
136
|
const [isBulkSelectOpen, setIsBulkSelectOpen] = React.useState<boolean>(false);
|
|
119
137
|
|
|
120
|
-
React.useEffect(() => {
|
|
121
|
-
window.addEventListener('keydown', handleBulkSelectMenuKeys);
|
|
122
|
-
window.addEventListener('click', handleBulkSelectClickOutside);
|
|
123
|
-
return () => {
|
|
124
|
-
window.removeEventListener('keydown', handleBulkSelectMenuKeys);
|
|
125
|
-
window.removeEventListener('click', handleBulkSelectClickOutside);
|
|
126
|
-
};
|
|
127
|
-
}, [isBulkSelectOpen, bulkSelectMenuRef]);
|
|
128
|
-
|
|
129
138
|
const handleBulkSelectClickOutside = (event: MouseEvent) => {
|
|
130
139
|
if (isBulkSelectOpen && !bulkSelectMenuRef.current?.contains(event.target as Node)) {
|
|
131
140
|
setIsBulkSelectOpen(false);
|
|
@@ -142,11 +151,20 @@ export const FilterCheckboxSelect: React.FunctionComponent = () => {
|
|
|
142
151
|
) {
|
|
143
152
|
if (event.key === 'Escape' || event.key === 'Tab') {
|
|
144
153
|
setIsBulkSelectOpen(!isBulkSelectOpen);
|
|
145
|
-
bulkSelectToggleRef.current?.focus();
|
|
154
|
+
bulkSelectToggleRef.current?.querySelector('button').focus();
|
|
146
155
|
}
|
|
147
156
|
}
|
|
148
157
|
};
|
|
149
158
|
|
|
159
|
+
React.useEffect(() => {
|
|
160
|
+
window.addEventListener('keydown', handleBulkSelectMenuKeys);
|
|
161
|
+
window.addEventListener('click', handleBulkSelectClickOutside);
|
|
162
|
+
return () => {
|
|
163
|
+
window.removeEventListener('keydown', handleBulkSelectMenuKeys);
|
|
164
|
+
window.removeEventListener('click', handleBulkSelectClickOutside);
|
|
165
|
+
};
|
|
166
|
+
}, [isBulkSelectOpen, bulkSelectMenuRef]);
|
|
167
|
+
|
|
150
168
|
const onBulkSelectToggleClick = (ev: React.MouseEvent) => {
|
|
151
169
|
ev.stopPropagation(); // Stop handleClickOutside from handling
|
|
152
170
|
setTimeout(() => {
|
|
@@ -173,8 +191,8 @@ export const FilterCheckboxSelect: React.FunctionComponent = () => {
|
|
|
173
191
|
splitButtonOptions={{
|
|
174
192
|
items: [
|
|
175
193
|
<MenuToggleCheckbox
|
|
176
|
-
id="select
|
|
177
|
-
key="select
|
|
194
|
+
id="checkbox-bulk-select"
|
|
195
|
+
key="checkbox-bulk-select"
|
|
178
196
|
aria-label="Select all"
|
|
179
197
|
isChecked={menuToggleCheckmark}
|
|
180
198
|
onChange={(checked, _event) => selectAllRepos(checked)}
|
|
@@ -186,12 +204,12 @@ export const FilterCheckboxSelect: React.FunctionComponent = () => {
|
|
|
186
204
|
);
|
|
187
205
|
|
|
188
206
|
const bulkSelectMenu = (
|
|
189
|
-
// eslint-disable-next-line no-console
|
|
190
207
|
<Menu
|
|
191
208
|
ref={bulkSelectMenuRef}
|
|
192
209
|
onSelect={(_ev, itemId) => {
|
|
193
210
|
selectAllRepos(itemId === 1 || itemId === 2);
|
|
194
211
|
setIsBulkSelectOpen(!isBulkSelectOpen);
|
|
212
|
+
bulkSelectToggleRef.current?.querySelector('button').focus();
|
|
195
213
|
}}
|
|
196
214
|
>
|
|
197
215
|
<MenuContent>
|
|
@@ -205,40 +223,23 @@ export const FilterCheckboxSelect: React.FunctionComponent = () => {
|
|
|
205
223
|
);
|
|
206
224
|
|
|
207
225
|
const toolbarBulkSelect = (
|
|
208
|
-
<div ref={
|
|
226
|
+
<div ref={bulkSelectContainerRef}>
|
|
209
227
|
<Popper
|
|
210
228
|
trigger={bulkSelectToggle}
|
|
211
229
|
popper={bulkSelectMenu}
|
|
212
|
-
appendTo={
|
|
230
|
+
appendTo={bulkSelectContainerRef.current || undefined}
|
|
213
231
|
isVisible={isBulkSelectOpen}
|
|
214
232
|
popperMatchesTriggerWidth={false}
|
|
215
233
|
/>
|
|
216
234
|
</div>
|
|
217
235
|
);
|
|
218
236
|
|
|
219
|
-
// Set up
|
|
237
|
+
// Set up checkbox select menu
|
|
220
238
|
const [isOpen, setIsOpen] = React.useState<boolean>(false);
|
|
221
|
-
const [selections, setSelections] = React.useState<string[]>([]);
|
|
222
239
|
const toggleRef = React.useRef<HTMLButtonElement>(null);
|
|
223
240
|
const menuRef = React.useRef<HTMLDivElement>(null);
|
|
224
241
|
const containerRef = React.useRef<HTMLDivElement>(null);
|
|
225
242
|
|
|
226
|
-
const onFilter = (repo: Repository) => {
|
|
227
|
-
if (selections.length === 0) {
|
|
228
|
-
return true;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
return selections.some(searchValue => {
|
|
232
|
-
let input: RegExp;
|
|
233
|
-
try {
|
|
234
|
-
input = new RegExp(searchValue, 'i');
|
|
235
|
-
} catch (err) {
|
|
236
|
-
input = new RegExp(searchValue.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i');
|
|
237
|
-
}
|
|
238
|
-
return repo.location.search(input) >= 0;
|
|
239
|
-
});
|
|
240
|
-
};
|
|
241
|
-
|
|
242
243
|
const handleMenuKeys = (event: KeyboardEvent) => {
|
|
243
244
|
if (isOpen && menuRef.current?.contains(event.target as Node)) {
|
|
244
245
|
if (event.key === 'Escape' || event.key === 'Tab') {
|
|
@@ -303,7 +304,7 @@ export const FilterCheckboxSelect: React.FunctionComponent = () => {
|
|
|
303
304
|
);
|
|
304
305
|
|
|
305
306
|
const menu = (
|
|
306
|
-
<Menu ref={menuRef} id="select-menu" onSelect={onSelect} selected={selections}>
|
|
307
|
+
<Menu ref={menuRef} id="checkbox-select-menu" onSelect={onSelect} selected={selections}>
|
|
307
308
|
<MenuContent>
|
|
308
309
|
<MenuList>
|
|
309
310
|
<MenuItem hasCheck isSelected={selections.includes('Bangalore')} itemId="Bangalore">
|
|
@@ -372,15 +373,15 @@ export const FilterCheckboxSelect: React.FunctionComponent = () => {
|
|
|
372
373
|
<Tr>
|
|
373
374
|
<Th />
|
|
374
375
|
<Th width={20}>{columnNames.name}</Th>
|
|
375
|
-
<Th width={
|
|
376
|
-
<Th width={
|
|
377
|
-
<Th width={
|
|
376
|
+
<Th width={10}>{columnNames.threads}</Th>
|
|
377
|
+
<Th width={10}>{columnNames.apps}</Th>
|
|
378
|
+
<Th width={10}>{columnNames.workspaces}</Th>
|
|
378
379
|
<Th width={20}>{columnNames.status}</Th>
|
|
379
380
|
<Th width={20}>{columnNames.location}</Th>
|
|
380
381
|
</Tr>
|
|
381
382
|
</Thead>
|
|
382
383
|
<Tbody>
|
|
383
|
-
{
|
|
384
|
+
{filteredRepos.map((repo, rowIndex) => (
|
|
384
385
|
<Tr key={repo.name}>
|
|
385
386
|
<Td
|
|
386
387
|
select={{
|
|
@@ -390,12 +391,24 @@ export const FilterCheckboxSelect: React.FunctionComponent = () => {
|
|
|
390
391
|
disable: !isRepoSelectable(repo)
|
|
391
392
|
}}
|
|
392
393
|
/>
|
|
393
|
-
<Td dataLabel={columnNames.name}>
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
<Td dataLabel={columnNames.
|
|
397
|
-
|
|
398
|
-
|
|
394
|
+
<Td dataLabel={columnNames.name} modifier="truncate">
|
|
395
|
+
{repo.name}
|
|
396
|
+
</Td>
|
|
397
|
+
<Td dataLabel={columnNames.threads} modifier="truncate">
|
|
398
|
+
{repo.threads}
|
|
399
|
+
</Td>
|
|
400
|
+
<Td dataLabel={columnNames.apps} modifier="truncate">
|
|
401
|
+
{repo.apps}
|
|
402
|
+
</Td>
|
|
403
|
+
<Td dataLabel={columnNames.workspaces} modifier="truncate">
|
|
404
|
+
{repo.workspaces}
|
|
405
|
+
</Td>
|
|
406
|
+
<Td dataLabel={columnNames.status} modifier="truncate">
|
|
407
|
+
{repo.status}
|
|
408
|
+
</Td>
|
|
409
|
+
<Td dataLabel={columnNames.location} modifier="truncate">
|
|
410
|
+
{repo.location}
|
|
411
|
+
</Td>
|
|
399
412
|
</Tr>
|
|
400
413
|
))}
|
|
401
414
|
</Tbody>
|