@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.
Files changed (35) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/esm/components/Menu/Menu.d.ts.map +1 -1
  3. package/dist/esm/components/Menu/Menu.js +10 -3
  4. package/dist/esm/components/Menu/Menu.js.map +1 -1
  5. package/dist/esm/components/MenuToggle/MenuToggle.d.ts.map +1 -1
  6. package/dist/esm/components/MenuToggle/MenuToggle.js +1 -1
  7. package/dist/esm/components/MenuToggle/MenuToggle.js.map +1 -1
  8. package/dist/js/components/Menu/Menu.d.ts.map +1 -1
  9. package/dist/js/components/Menu/Menu.js +10 -3
  10. package/dist/js/components/Menu/Menu.js.map +1 -1
  11. package/dist/js/components/MenuToggle/MenuToggle.d.ts.map +1 -1
  12. package/dist/js/components/MenuToggle/MenuToggle.js +1 -1
  13. package/dist/js/components/MenuToggle/MenuToggle.js.map +1 -1
  14. package/dist/umd/react-core.min.css +1942 -1942
  15. package/dist/umd/react-core.min.js +1 -1
  16. package/package.json +2 -2
  17. package/src/components/Menu/Menu.tsx +13 -7
  18. package/src/components/MenuToggle/MenuToggle.tsx +1 -0
  19. package/src/demos/Filters/FilterDemos.md +27 -5
  20. package/src/demos/Filters/examples/FilterAttributeSearch.tsx +701 -0
  21. package/src/demos/Filters/examples/FilterCheckboxSelect.tsx +66 -53
  22. package/src/demos/Filters/examples/FilterFaceted.tsx +512 -0
  23. package/src/demos/Filters/examples/FilterMixedSelectGroup.tsx +569 -0
  24. package/src/demos/Filters/examples/FilterSameSelectGroup.tsx +542 -0
  25. package/src/demos/Filters/examples/FilterSearchInput.tsx +91 -68
  26. package/src/demos/Filters/examples/FilterSingleSelect.tsx +63 -52
  27. package/src/demos/Page.md +47 -0
  28. package/src/demos/examples/DashboardWrapper.js +3 -1
  29. package/src/demos/examples/Page/PageStickySectionBreadcrumb.tsx +305 -0
  30. package/src/demos/examples/Page/PageStickySectionGroup.tsx +306 -0
  31. package/src/demos/examples/Page/PageStickySectionGroupAlternate.tsx +301 -0
  32. package/src/demos/examples/Page/PageStickySectionGroupUsingPageHeader.tsx +293 -0
  33. package/src/demos/Page/Page.md +0 -1184
  34. package/src/demos/Page/imgAvatar.svg +0 -33
  35. 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 Maintainence', location: 'Raleigh' },
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 table selection
56
- const isRepoSelectable = (repo: Repository) => repo.name !== 'a'; // Arbitrary logic for this example
57
- const selectableRepos = repositories.filter(isRepoSelectable);
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 ? selectableRepos.map(r => r.name) : []);
69
- const areAllReposSelected = selectedRepoNames.length === selectableRepos.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.createRef<HTMLDivElement>();
115
- const bulkSelectToggleRef = React.createRef<any>();
116
- const bulkSelectcontainerRef = React.createRef<HTMLDivElement>();
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-checkbox"
177
- key="select-checkbox"
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={bulkSelectcontainerRef}>
226
+ <div ref={bulkSelectContainerRef}>
209
227
  <Popper
210
228
  trigger={bulkSelectToggle}
211
229
  popper={bulkSelectMenu}
212
- appendTo={bulkSelectcontainerRef.current || undefined}
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 single select menu & state
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={20}>{columnNames.threads}</Th>
376
- <Th width={20}>{columnNames.apps}</Th>
377
- <Th width={20}>{columnNames.workspaces}</Th>
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
- {repositories.filter(onFilter).map((repo, rowIndex) => (
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}>{repo.name}</Td>
394
- <Td dataLabel={columnNames.threads}>{repo.threads}</Td>
395
- <Td dataLabel={columnNames.apps}>{repo.apps}</Td>
396
- <Td dataLabel={columnNames.workspaces}>{repo.workspaces}</Td>
397
- <Td dataLabel={columnNames.status}>{repo.status}</Td>
398
- <Td dataLabel={columnNames.location}>{repo.location}</Td>
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>