@patternfly/react-core 5.0.0-alpha.107 → 5.0.0-alpha.108

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 (271) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/esm/components/AboutModal/package.json +1 -1
  3. package/dist/esm/components/Accordion/package.json +1 -1
  4. package/dist/esm/components/ActionList/package.json +1 -1
  5. package/dist/esm/components/Alert/package.json +1 -1
  6. package/dist/esm/components/Avatar/package.json +1 -1
  7. package/dist/esm/components/BackToTop/package.json +1 -1
  8. package/dist/esm/components/Backdrop/package.json +1 -1
  9. package/dist/esm/components/BackgroundImage/package.json +1 -1
  10. package/dist/esm/components/Badge/package.json +1 -1
  11. package/dist/esm/components/Banner/package.json +1 -1
  12. package/dist/esm/components/Brand/package.json +1 -1
  13. package/dist/esm/components/Breadcrumb/package.json +1 -1
  14. package/dist/esm/components/Button/package.json +1 -1
  15. package/dist/esm/components/CalendarMonth/package.json +1 -1
  16. package/dist/esm/components/Card/package.json +1 -1
  17. package/dist/esm/components/Checkbox/package.json +1 -1
  18. package/dist/esm/components/Chip/package.json +1 -1
  19. package/dist/esm/components/ClipboardCopy/package.json +1 -1
  20. package/dist/esm/components/CodeBlock/package.json +1 -1
  21. package/dist/esm/components/DataList/package.json +1 -1
  22. package/dist/esm/components/DatePicker/package.json +1 -1
  23. package/dist/esm/components/DescriptionList/package.json +1 -1
  24. package/dist/esm/components/Divider/package.json +1 -1
  25. package/dist/esm/components/DragDrop/package.json +1 -1
  26. package/dist/esm/components/Drawer/package.json +1 -1
  27. package/dist/esm/components/Dropdown/Dropdown.d.ts +11 -3
  28. package/dist/esm/components/Dropdown/Dropdown.d.ts.map +1 -1
  29. package/dist/esm/components/Dropdown/Dropdown.js +11 -5
  30. package/dist/esm/components/Dropdown/Dropdown.js.map +1 -1
  31. package/dist/esm/components/Dropdown/package.json +1 -1
  32. package/dist/esm/components/DualListSelector/package.json +1 -1
  33. package/dist/esm/components/EmptyState/package.json +1 -1
  34. package/dist/esm/components/ExpandableSection/package.json +1 -1
  35. package/dist/esm/components/FileUpload/package.json +1 -1
  36. package/dist/esm/components/Form/package.json +1 -1
  37. package/dist/esm/components/FormSelect/package.json +1 -1
  38. package/dist/esm/components/HelperText/package.json +1 -1
  39. package/dist/esm/components/Hint/package.json +1 -1
  40. package/dist/esm/components/Icon/package.json +1 -1
  41. package/dist/esm/components/InputGroup/package.json +1 -1
  42. package/dist/esm/components/JumpLinks/package.json +1 -1
  43. package/dist/esm/components/Label/package.json +1 -1
  44. package/dist/esm/components/List/package.json +1 -1
  45. package/dist/esm/components/LoginPage/package.json +1 -1
  46. package/dist/esm/components/Masthead/package.json +1 -1
  47. package/dist/esm/components/Menu/package.json +1 -1
  48. package/dist/esm/components/MenuToggle/package.json +1 -1
  49. package/dist/esm/components/Modal/package.json +1 -1
  50. package/dist/esm/components/MultipleFileUpload/package.json +1 -1
  51. package/dist/esm/components/Nav/package.json +1 -1
  52. package/dist/esm/components/NotificationBadge/package.json +1 -1
  53. package/dist/esm/components/NotificationDrawer/package.json +1 -1
  54. package/dist/esm/components/NumberInput/package.json +1 -1
  55. package/dist/esm/components/OverflowMenu/package.json +1 -1
  56. package/dist/esm/components/Page/package.json +1 -1
  57. package/dist/esm/components/Pagination/package.json +1 -1
  58. package/dist/esm/components/Panel/package.json +1 -1
  59. package/dist/esm/components/Popover/package.json +1 -1
  60. package/dist/esm/components/Progress/package.json +1 -1
  61. package/dist/esm/components/ProgressStepper/package.json +1 -1
  62. package/dist/esm/components/Radio/package.json +1 -1
  63. package/dist/esm/components/SearchInput/package.json +1 -1
  64. package/dist/esm/components/Select/Select.d.ts +31 -5
  65. package/dist/esm/components/Select/Select.d.ts.map +1 -1
  66. package/dist/esm/components/Select/Select.js +16 -10
  67. package/dist/esm/components/Select/Select.js.map +1 -1
  68. package/dist/esm/components/Select/SelectGroup.d.ts +3 -0
  69. package/dist/esm/components/Select/SelectGroup.d.ts.map +1 -1
  70. package/dist/esm/components/Select/SelectGroup.js.map +1 -1
  71. package/dist/esm/components/Select/SelectOption.d.ts +14 -1
  72. package/dist/esm/components/Select/SelectOption.d.ts.map +1 -1
  73. package/dist/esm/components/Select/SelectOption.js +4 -3
  74. package/dist/esm/components/Select/SelectOption.js.map +1 -1
  75. package/dist/esm/components/Select/package.json +1 -1
  76. package/dist/esm/components/Sidebar/package.json +1 -1
  77. package/dist/esm/components/SimpleList/package.json +1 -1
  78. package/dist/esm/components/Skeleton/package.json +1 -1
  79. package/dist/esm/components/SkipToContent/package.json +1 -1
  80. package/dist/esm/components/Slider/package.json +1 -1
  81. package/dist/esm/components/Spinner/package.json +1 -1
  82. package/dist/esm/components/Switch/package.json +1 -1
  83. package/dist/esm/components/Tabs/package.json +1 -1
  84. package/dist/esm/components/Text/package.json +1 -1
  85. package/dist/esm/components/TextArea/package.json +1 -1
  86. package/dist/esm/components/TextInput/package.json +1 -1
  87. package/dist/esm/components/TextInputGroup/package.json +1 -1
  88. package/dist/esm/components/Tile/package.json +1 -1
  89. package/dist/esm/components/TimePicker/package.json +1 -1
  90. package/dist/esm/components/Timestamp/package.json +1 -1
  91. package/dist/esm/components/Title/package.json +1 -1
  92. package/dist/esm/components/ToggleGroup/package.json +1 -1
  93. package/dist/esm/components/Toolbar/package.json +1 -1
  94. package/dist/esm/components/Tooltip/package.json +1 -1
  95. package/dist/esm/components/TreeView/package.json +1 -1
  96. package/dist/esm/components/Truncate/package.json +1 -1
  97. package/dist/esm/components/Wizard/hooks/package.json +1 -1
  98. package/dist/esm/components/Wizard/package.json +1 -1
  99. package/dist/esm/components/package.json +1 -1
  100. package/dist/esm/deprecated/components/ApplicationLauncher/package.json +1 -1
  101. package/dist/esm/deprecated/components/ContextSelector/package.json +1 -1
  102. package/dist/esm/deprecated/components/Dropdown/package.json +1 -1
  103. package/dist/esm/deprecated/components/OptionsMenu/package.json +1 -1
  104. package/dist/esm/deprecated/components/PageHeader/package.json +1 -1
  105. package/dist/esm/deprecated/components/Select/package.json +1 -1
  106. package/dist/esm/deprecated/components/Wizard/package.json +1 -1
  107. package/dist/esm/deprecated/components/package.json +1 -1
  108. package/dist/esm/deprecated/package.json +1 -1
  109. package/dist/esm/helpers/Popper/Popper.d.ts +1 -1
  110. package/dist/esm/helpers/Popper/Popper.d.ts.map +1 -1
  111. package/dist/esm/helpers/Popper/thirdparty/popper-core/package.json +1 -1
  112. package/dist/esm/helpers/package.json +1 -1
  113. package/dist/esm/layouts/Bullseye/package.json +1 -1
  114. package/dist/esm/layouts/Flex/package.json +1 -1
  115. package/dist/esm/layouts/Gallery/package.json +1 -1
  116. package/dist/esm/layouts/Grid/package.json +1 -1
  117. package/dist/esm/layouts/Level/package.json +1 -1
  118. package/dist/esm/layouts/Split/package.json +1 -1
  119. package/dist/esm/layouts/Stack/package.json +1 -1
  120. package/dist/esm/layouts/package.json +1 -1
  121. package/dist/esm/next/components/package.json +1 -1
  122. package/dist/esm/next/package.json +1 -1
  123. package/dist/esm/package.json +1 -1
  124. package/dist/js/components/AboutModal/package.json +1 -1
  125. package/dist/js/components/Accordion/package.json +1 -1
  126. package/dist/js/components/ActionList/package.json +1 -1
  127. package/dist/js/components/Alert/package.json +1 -1
  128. package/dist/js/components/Avatar/package.json +1 -1
  129. package/dist/js/components/BackToTop/package.json +1 -1
  130. package/dist/js/components/Backdrop/package.json +1 -1
  131. package/dist/js/components/BackgroundImage/package.json +1 -1
  132. package/dist/js/components/Badge/package.json +1 -1
  133. package/dist/js/components/Banner/package.json +1 -1
  134. package/dist/js/components/Brand/package.json +1 -1
  135. package/dist/js/components/Breadcrumb/package.json +1 -1
  136. package/dist/js/components/Button/package.json +1 -1
  137. package/dist/js/components/CalendarMonth/package.json +1 -1
  138. package/dist/js/components/Card/package.json +1 -1
  139. package/dist/js/components/Checkbox/package.json +1 -1
  140. package/dist/js/components/Chip/package.json +1 -1
  141. package/dist/js/components/ClipboardCopy/package.json +1 -1
  142. package/dist/js/components/CodeBlock/package.json +1 -1
  143. package/dist/js/components/DataList/package.json +1 -1
  144. package/dist/js/components/DatePicker/package.json +1 -1
  145. package/dist/js/components/DescriptionList/package.json +1 -1
  146. package/dist/js/components/Divider/package.json +1 -1
  147. package/dist/js/components/DragDrop/package.json +1 -1
  148. package/dist/js/components/Drawer/package.json +1 -1
  149. package/dist/js/components/Dropdown/Dropdown.d.ts +11 -3
  150. package/dist/js/components/Dropdown/Dropdown.d.ts.map +1 -1
  151. package/dist/js/components/Dropdown/Dropdown.js +11 -5
  152. package/dist/js/components/Dropdown/Dropdown.js.map +1 -1
  153. package/dist/js/components/Dropdown/package.json +1 -1
  154. package/dist/js/components/DualListSelector/package.json +1 -1
  155. package/dist/js/components/EmptyState/package.json +1 -1
  156. package/dist/js/components/ExpandableSection/package.json +1 -1
  157. package/dist/js/components/FileUpload/package.json +1 -1
  158. package/dist/js/components/Form/package.json +1 -1
  159. package/dist/js/components/FormSelect/package.json +1 -1
  160. package/dist/js/components/HelperText/package.json +1 -1
  161. package/dist/js/components/Hint/package.json +1 -1
  162. package/dist/js/components/Icon/package.json +1 -1
  163. package/dist/js/components/InputGroup/package.json +1 -1
  164. package/dist/js/components/JumpLinks/package.json +1 -1
  165. package/dist/js/components/Label/package.json +1 -1
  166. package/dist/js/components/List/package.json +1 -1
  167. package/dist/js/components/LoginPage/package.json +1 -1
  168. package/dist/js/components/Masthead/package.json +1 -1
  169. package/dist/js/components/Menu/package.json +1 -1
  170. package/dist/js/components/MenuToggle/package.json +1 -1
  171. package/dist/js/components/Modal/package.json +1 -1
  172. package/dist/js/components/MultipleFileUpload/package.json +1 -1
  173. package/dist/js/components/Nav/package.json +1 -1
  174. package/dist/js/components/NotificationBadge/package.json +1 -1
  175. package/dist/js/components/NotificationDrawer/package.json +1 -1
  176. package/dist/js/components/NumberInput/package.json +1 -1
  177. package/dist/js/components/OverflowMenu/package.json +1 -1
  178. package/dist/js/components/Page/package.json +1 -1
  179. package/dist/js/components/Pagination/package.json +1 -1
  180. package/dist/js/components/Panel/package.json +1 -1
  181. package/dist/js/components/Popover/package.json +1 -1
  182. package/dist/js/components/Progress/package.json +1 -1
  183. package/dist/js/components/ProgressStepper/package.json +1 -1
  184. package/dist/js/components/Radio/package.json +1 -1
  185. package/dist/js/components/SearchInput/package.json +1 -1
  186. package/dist/js/components/Select/Select.d.ts +31 -5
  187. package/dist/js/components/Select/Select.d.ts.map +1 -1
  188. package/dist/js/components/Select/Select.js +16 -10
  189. package/dist/js/components/Select/Select.js.map +1 -1
  190. package/dist/js/components/Select/SelectGroup.d.ts +3 -0
  191. package/dist/js/components/Select/SelectGroup.d.ts.map +1 -1
  192. package/dist/js/components/Select/SelectGroup.js.map +1 -1
  193. package/dist/js/components/Select/SelectOption.d.ts +14 -1
  194. package/dist/js/components/Select/SelectOption.d.ts.map +1 -1
  195. package/dist/js/components/Select/SelectOption.js +4 -4
  196. package/dist/js/components/Select/SelectOption.js.map +1 -1
  197. package/dist/js/components/Select/package.json +1 -1
  198. package/dist/js/components/Sidebar/package.json +1 -1
  199. package/dist/js/components/SimpleList/package.json +1 -1
  200. package/dist/js/components/Skeleton/package.json +1 -1
  201. package/dist/js/components/SkipToContent/package.json +1 -1
  202. package/dist/js/components/Slider/package.json +1 -1
  203. package/dist/js/components/Spinner/package.json +1 -1
  204. package/dist/js/components/Switch/package.json +1 -1
  205. package/dist/js/components/Tabs/package.json +1 -1
  206. package/dist/js/components/Text/package.json +1 -1
  207. package/dist/js/components/TextArea/package.json +1 -1
  208. package/dist/js/components/TextInput/package.json +1 -1
  209. package/dist/js/components/TextInputGroup/package.json +1 -1
  210. package/dist/js/components/Tile/package.json +1 -1
  211. package/dist/js/components/TimePicker/package.json +1 -1
  212. package/dist/js/components/Timestamp/package.json +1 -1
  213. package/dist/js/components/Title/package.json +1 -1
  214. package/dist/js/components/ToggleGroup/package.json +1 -1
  215. package/dist/js/components/Toolbar/package.json +1 -1
  216. package/dist/js/components/Tooltip/package.json +1 -1
  217. package/dist/js/components/TreeView/package.json +1 -1
  218. package/dist/js/components/Truncate/package.json +1 -1
  219. package/dist/js/components/Wizard/hooks/package.json +1 -1
  220. package/dist/js/components/Wizard/package.json +1 -1
  221. package/dist/js/components/package.json +1 -1
  222. package/dist/js/deprecated/components/ApplicationLauncher/package.json +1 -1
  223. package/dist/js/deprecated/components/ContextSelector/package.json +1 -1
  224. package/dist/js/deprecated/components/Dropdown/package.json +1 -1
  225. package/dist/js/deprecated/components/OptionsMenu/package.json +1 -1
  226. package/dist/js/deprecated/components/PageHeader/package.json +1 -1
  227. package/dist/js/deprecated/components/Select/package.json +1 -1
  228. package/dist/js/deprecated/components/Wizard/package.json +1 -1
  229. package/dist/js/deprecated/components/package.json +1 -1
  230. package/dist/js/deprecated/package.json +1 -1
  231. package/dist/js/helpers/Popper/Popper.d.ts +1 -1
  232. package/dist/js/helpers/Popper/Popper.d.ts.map +1 -1
  233. package/dist/js/helpers/Popper/thirdparty/popper-core/package.json +1 -1
  234. package/dist/js/helpers/package.json +1 -1
  235. package/dist/js/layouts/Bullseye/package.json +1 -1
  236. package/dist/js/layouts/Flex/package.json +1 -1
  237. package/dist/js/layouts/Gallery/package.json +1 -1
  238. package/dist/js/layouts/Grid/package.json +1 -1
  239. package/dist/js/layouts/Level/package.json +1 -1
  240. package/dist/js/layouts/Split/package.json +1 -1
  241. package/dist/js/layouts/Stack/package.json +1 -1
  242. package/dist/js/layouts/package.json +1 -1
  243. package/dist/js/next/components/package.json +1 -1
  244. package/dist/js/next/package.json +1 -1
  245. package/dist/js/package.json +1 -1
  246. package/dist/umd/react-core.min.js +2 -2
  247. package/package.json +2 -2
  248. package/src/components/DatePicker/__tests__/__snapshots__/DatePicker.test.tsx.snap +27 -29
  249. package/src/components/Dropdown/Dropdown.tsx +25 -11
  250. package/src/components/Dropdown/examples/Dropdown.md +10 -1
  251. package/src/components/Dropdown/examples/DropdownBasic.tsx +2 -6
  252. package/src/components/Dropdown/examples/DropdownWithDescriptions.tsx +2 -6
  253. package/src/components/Dropdown/examples/DropdownWithGroups.tsx +2 -6
  254. package/src/components/Dropdown/examples/DropdownWithKebabToggle.tsx +2 -6
  255. package/src/components/Select/Select.tsx +62 -24
  256. package/src/components/Select/SelectGroup.tsx +3 -0
  257. package/src/components/Select/SelectOption.tsx +22 -2
  258. package/src/components/Select/examples/Select.md +49 -2
  259. package/src/components/Select/examples/SelectBasic.tsx +27 -17
  260. package/src/components/Select/examples/SelectCheckbox.tsx +1 -3
  261. package/src/components/Select/examples/SelectFooter.tsx +57 -0
  262. package/src/components/Select/examples/SelectGrouped.tsx +14 -6
  263. package/src/components/Select/examples/SelectMultiTypeahead.tsx +7 -12
  264. package/src/components/Select/examples/SelectMultiTypeaheadCheckbox.tsx +204 -0
  265. package/src/components/Select/examples/SelectMultiTypeaheadCreatable.tsx +222 -0
  266. package/src/components/Select/examples/SelectOptionVariations.tsx +70 -0
  267. package/src/components/Select/examples/SelectTypeahead.tsx +13 -13
  268. package/src/components/Select/examples/SelectTypeaheadCreatable.tsx +220 -0
  269. package/src/components/Select/examples/SelectViewMore.tsx +146 -0
  270. package/src/demos/ComposableMenu/ComposableMenu.md +14 -0
  271. package/src/helpers/Popper/Popper.tsx +1 -1
@@ -4,7 +4,6 @@ import { Select, SelectOption, SelectList, MenuToggle, MenuToggleElement, Badge
4
4
  export const SelectCheckbox: React.FunctionComponent = () => {
5
5
  const [isOpen, setIsOpen] = React.useState(false);
6
6
  const [selectedItems, setSelectedItems] = React.useState<number[]>([]);
7
- const menuRef = React.useRef<HTMLDivElement>(null);
8
7
 
9
8
  const onToggleClick = () => {
10
9
  setIsOpen(!isOpen);
@@ -15,7 +14,7 @@ export const SelectCheckbox: React.FunctionComponent = () => {
15
14
  console.log('selected', itemId);
16
15
 
17
16
  if (selectedItems.includes(itemId as number)) {
18
- setSelectedItems(selectedItems.filter(id => id !== itemId));
17
+ setSelectedItems(selectedItems.filter((id) => id !== itemId));
19
18
  } else {
20
19
  setSelectedItems([...selectedItems, itemId as number]);
21
20
  }
@@ -41,7 +40,6 @@ export const SelectCheckbox: React.FunctionComponent = () => {
41
40
  <Select
42
41
  role="menu"
43
42
  id="checkbox-select"
44
- ref={menuRef}
45
43
  isOpen={isOpen}
46
44
  selected={selectedItems}
47
45
  onSelect={onSelect}
@@ -0,0 +1,57 @@
1
+ import React from 'react';
2
+ import { MenuToggle, MenuFooter, Select, SelectList, SelectOption, Button } from '@patternfly/react-core';
3
+
4
+ export const SelectFooter: React.FunctionComponent = () => {
5
+ const [isOpen, setIsOpen] = React.useState<boolean>(false);
6
+ const [selected, setSelected] = React.useState<string>('Select a value');
7
+
8
+ const onToggleClick = () => {
9
+ setIsOpen(!isOpen);
10
+ };
11
+
12
+ const toggle = (toggleRef) => (
13
+ <MenuToggle
14
+ ref={toggleRef}
15
+ onClick={onToggleClick}
16
+ isExpanded={isOpen}
17
+ style={
18
+ {
19
+ width: '200px'
20
+ } as React.CSSProperties
21
+ }
22
+ >
23
+ {selected}
24
+ </MenuToggle>
25
+ );
26
+
27
+ function onSelect(event: React.MouseEvent | undefined, itemId: string | number | undefined) {
28
+ if (typeof itemId === 'undefined') {
29
+ return;
30
+ }
31
+
32
+ setSelected(itemId.toString());
33
+ }
34
+
35
+ return (
36
+ <Select
37
+ isOpen={isOpen}
38
+ onOpenChange={(isOpen) => setIsOpen(isOpen)}
39
+ onOpenChangeKeys={['Escape']}
40
+ toggle={toggle}
41
+ id="menu-with-footer"
42
+ onSelect={onSelect}
43
+ selected={selected}
44
+ >
45
+ <SelectList>
46
+ <SelectOption itemId="Option 1">Option 1</SelectOption>
47
+ <SelectOption itemId="Option 2">Option 2</SelectOption>
48
+ <SelectOption itemId="Option 3">Option 3</SelectOption>
49
+ </SelectList>
50
+ <MenuFooter>
51
+ <Button variant="link" isInline>
52
+ Footer action
53
+ </Button>
54
+ </MenuFooter>
55
+ </Select>
56
+ );
57
+ };
@@ -1,10 +1,17 @@
1
1
  import React from 'react';
2
- import { Select, SelectOption, SelectList, SelectGroup, MenuToggle, MenuToggleElement } from '@patternfly/react-core';
2
+ import {
3
+ Select,
4
+ SelectOption,
5
+ SelectList,
6
+ SelectGroup,
7
+ MenuToggle,
8
+ MenuToggleElement,
9
+ Divider
10
+ } from '@patternfly/react-core';
3
11
 
4
- export const SelectBasic: React.FunctionComponent = () => {
12
+ export const SelectGrouped: React.FunctionComponent = () => {
5
13
  const [isOpen, setIsOpen] = React.useState(false);
6
14
  const [selected, setSelected] = React.useState<string>('Select a value');
7
- const menuRef = React.useRef<HTMLDivElement>(null);
8
15
 
9
16
  const onToggleClick = () => {
10
17
  setIsOpen(!isOpen);
@@ -35,13 +42,13 @@ export const SelectBasic: React.FunctionComponent = () => {
35
42
 
36
43
  return (
37
44
  <Select
38
- id="single-select"
39
- ref={menuRef}
45
+ id="single-grouped-select"
40
46
  isOpen={isOpen}
41
47
  selected={selected}
42
48
  onSelect={onSelect}
43
- onOpenChange={isOpen => setIsOpen(isOpen)}
49
+ onOpenChange={(isOpen) => setIsOpen(isOpen)}
44
50
  toggle={toggle}
51
+ shouldFocusToggleOnSelect
45
52
  >
46
53
  <SelectGroup label="Group 1">
47
54
  <SelectList>
@@ -50,6 +57,7 @@ export const SelectBasic: React.FunctionComponent = () => {
50
57
  <SelectOption itemId="Option 3">Option 3</SelectOption>
51
58
  </SelectList>
52
59
  </SelectGroup>
60
+ <Divider />
53
61
  <SelectGroup label="Group 2">
54
62
  <SelectList>
55
63
  <SelectOption itemId="Option 4">Option 4</SelectOption>
@@ -31,8 +31,6 @@ export const SelectMultiTypeahead: React.FunctionComponent = () => {
31
31
  const [selectOptions, setSelectOptions] = React.useState<SelectOptionProps[]>(initialSelectOptions);
32
32
  const [focusedItemIndex, setFocusedItemIndex] = React.useState<number | null>(null);
33
33
  const [activeItem, setActiveItem] = React.useState<string | null>(null);
34
-
35
- const menuRef = React.useRef<HTMLDivElement>(null);
36
34
  const textInputRef = React.useRef<HTMLInputElement>();
37
35
 
38
36
  React.useEffect(() => {
@@ -40,10 +38,8 @@ export const SelectMultiTypeahead: React.FunctionComponent = () => {
40
38
 
41
39
  // Filter menu items based on the text input value when one exists
42
40
  if (inputValue) {
43
- newSelectOptions = initialSelectOptions.filter(menuItem =>
44
- String(menuItem.children)
45
- .toLowerCase()
46
- .includes(inputValue.toLowerCase())
41
+ newSelectOptions = initialSelectOptions.filter((menuItem) =>
42
+ String(menuItem.children).toLowerCase().includes(inputValue.toLowerCase())
47
43
  );
48
44
 
49
45
  // When no options are found after filtering, display 'No results found'
@@ -87,13 +83,13 @@ export const SelectMultiTypeahead: React.FunctionComponent = () => {
87
83
  }
88
84
 
89
85
  setFocusedItemIndex(indexToFocus);
90
- const focusedItem = selectOptions.filter(option => !option.isDisabled)[indexToFocus];
86
+ const focusedItem = selectOptions.filter((option) => !option.isDisabled)[indexToFocus];
91
87
  setActiveItem(`select-multi-typeahead-${focusedItem.itemId.replace(' ', '-')}`);
92
88
  }
93
89
  };
94
90
 
95
91
  const onInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
96
- const enabledMenuItems = selectOptions.filter(menuItem => !menuItem.isDisabled);
92
+ const enabledMenuItems = selectOptions.filter((menuItem) => !menuItem.isDisabled);
97
93
  const [firstMenuItem] = enabledMenuItems;
98
94
  const focusedItem = focusedItemIndex ? enabledMenuItems[focusedItemIndex] : firstMenuItem;
99
95
 
@@ -101,7 +97,7 @@ export const SelectMultiTypeahead: React.FunctionComponent = () => {
101
97
  // Select the first available option
102
98
  case 'Enter':
103
99
  if (!isOpen) {
104
- setIsOpen(prevIsOpen => !prevIsOpen);
100
+ setIsOpen((prevIsOpen) => !prevIsOpen);
105
101
  } else if (isOpen && focusedItem.itemId !== 'no results') {
106
102
  onSelect(focusedItem.itemId as string);
107
103
  }
@@ -133,7 +129,7 @@ export const SelectMultiTypeahead: React.FunctionComponent = () => {
133
129
 
134
130
  if (itemId && itemId !== 'no results') {
135
131
  setSelected(
136
- selected.includes(itemId) ? selected.filter(selection => selection !== itemId) : [...selected, itemId]
132
+ selected.includes(itemId) ? selected.filter((selection) => selection !== itemId) : [...selected, itemId]
137
133
  );
138
134
  }
139
135
 
@@ -161,7 +157,7 @@ export const SelectMultiTypeahead: React.FunctionComponent = () => {
161
157
  {selected.map((selection, index) => (
162
158
  <Chip
163
159
  key={index}
164
- onClick={ev => {
160
+ onClick={(ev) => {
165
161
  ev.stopPropagation();
166
162
  onSelect(selection);
167
163
  }}
@@ -193,7 +189,6 @@ export const SelectMultiTypeahead: React.FunctionComponent = () => {
193
189
  return (
194
190
  <Select
195
191
  id="multi-typeahead-select"
196
- ref={menuRef}
197
192
  isOpen={isOpen}
198
193
  selected={selected}
199
194
  onSelect={(ev, selection) => onSelect(selection as string)}
@@ -0,0 +1,204 @@
1
+ import React from 'react';
2
+ import {
3
+ Select,
4
+ SelectOption,
5
+ SelectList,
6
+ SelectOptionProps,
7
+ MenuToggle,
8
+ MenuToggleElement,
9
+ TextInputGroup,
10
+ TextInputGroupMain,
11
+ TextInputGroupUtilities,
12
+ Button
13
+ } from '@patternfly/react-core';
14
+ import TimesIcon from '@patternfly/react-icons/dist/esm/icons/times-icon';
15
+
16
+ const initialSelectOptions: SelectOptionProps[] = [
17
+ { itemId: 'Alabama', children: 'Alabama' },
18
+ { itemId: 'Florida', children: 'Florida' },
19
+ { itemId: 'New Jersey', children: 'New Jersey' },
20
+ { itemId: 'New Mexico', children: 'New Mexico' },
21
+ { itemId: 'New York', children: 'New York' },
22
+ { itemId: 'North Carolina', children: 'North Carolina' }
23
+ ];
24
+
25
+ export const SelectMultiTypeaheadCheckbox: React.FunctionComponent = () => {
26
+ const [isOpen, setIsOpen] = React.useState(false);
27
+ const [inputValue, setInputValue] = React.useState<string>('');
28
+ const [selected, setSelected] = React.useState<string[]>([]);
29
+ const [selectOptions, setSelectOptions] = React.useState<SelectOptionProps[]>(initialSelectOptions);
30
+ const [focusedItemIndex, setFocusedItemIndex] = React.useState<number | null>(null);
31
+ const [activeItem, setActiveItem] = React.useState<string | null>(null);
32
+ const [placeholder, setPlaceholder] = React.useState('0 items selected');
33
+ const textInputRef = React.useRef<HTMLInputElement>();
34
+
35
+ React.useEffect(() => {
36
+ let newSelectOptions: SelectOptionProps[] = initialSelectOptions;
37
+
38
+ // Filter menu items based on the text input value when one exists
39
+ if (inputValue) {
40
+ newSelectOptions = initialSelectOptions.filter((menuItem) =>
41
+ String(menuItem.children).toLowerCase().includes(inputValue.toLowerCase())
42
+ );
43
+
44
+ // When no options are found after filtering, display 'No results found'
45
+ if (!newSelectOptions.length) {
46
+ newSelectOptions = [
47
+ { isDisabled: false, children: `No results found for "${inputValue}"`, itemId: 'no results' }
48
+ ];
49
+ }
50
+
51
+ // Open the menu when the input value changes and the new value is not empty
52
+ if (!isOpen) {
53
+ setIsOpen(true);
54
+ }
55
+ }
56
+
57
+ setSelectOptions(newSelectOptions);
58
+ setFocusedItemIndex(null);
59
+ setActiveItem(null);
60
+ }, [inputValue]);
61
+
62
+ const handleMenuArrowKeys = (key: string) => {
63
+ let indexToFocus;
64
+
65
+ if (isOpen) {
66
+ if (key === 'ArrowUp') {
67
+ // When no index is set or at the first index, focus to the last, otherwise decrement focus index
68
+ if (focusedItemIndex === null || focusedItemIndex === 0) {
69
+ indexToFocus = selectOptions.length - 1;
70
+ } else {
71
+ indexToFocus = focusedItemIndex - 1;
72
+ }
73
+ }
74
+
75
+ if (key === 'ArrowDown') {
76
+ // When no index is set or at the last index, focus to the first, otherwise increment focus index
77
+ if (focusedItemIndex === null || focusedItemIndex === selectOptions.length - 1) {
78
+ indexToFocus = 0;
79
+ } else {
80
+ indexToFocus = focusedItemIndex + 1;
81
+ }
82
+ }
83
+
84
+ setFocusedItemIndex(indexToFocus);
85
+ const focusedItem = selectOptions.filter((option) => !option.isDisabled)[indexToFocus];
86
+ setActiveItem(`select-multi-typeahead-checkbox-${focusedItem.itemId.replace(' ', '-')}`);
87
+ }
88
+ };
89
+
90
+ const onInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
91
+ const enabledMenuItems = selectOptions.filter((menuItem) => !menuItem.isDisabled);
92
+ const [firstMenuItem] = enabledMenuItems;
93
+ const focusedItem = focusedItemIndex ? enabledMenuItems[focusedItemIndex] : firstMenuItem;
94
+
95
+ switch (event.key) {
96
+ // Select the first available option
97
+ case 'Enter':
98
+ if (!isOpen) {
99
+ setIsOpen((prevIsOpen) => !prevIsOpen);
100
+ } else if (isOpen && focusedItem.itemId !== 'no results') {
101
+ onSelect(focusedItem.itemId as string);
102
+ }
103
+ break;
104
+ case 'Tab':
105
+ case 'Escape':
106
+ setIsOpen(false);
107
+ setActiveItem(null);
108
+ break;
109
+ case 'ArrowUp':
110
+ case 'ArrowDown':
111
+ event.preventDefault();
112
+ handleMenuArrowKeys(event.key);
113
+ break;
114
+ }
115
+ };
116
+
117
+ const onToggleClick = () => {
118
+ setIsOpen(!isOpen);
119
+ };
120
+
121
+ const onTextInputChange = (_event: React.FormEvent<HTMLInputElement>, value: string) => {
122
+ setInputValue(value);
123
+ };
124
+
125
+ const onSelect = (itemId: string) => {
126
+ // eslint-disable-next-line no-console
127
+ console.log('selected', itemId);
128
+
129
+ if (itemId && itemId !== 'no results') {
130
+ setSelected(
131
+ selected.includes(itemId) ? selected.filter((selection) => selection !== itemId) : [...selected, itemId]
132
+ );
133
+ }
134
+
135
+ textInputRef.current?.focus();
136
+ };
137
+
138
+ React.useEffect(() => {
139
+ setPlaceholder(`${selected.length} items selected`);
140
+ }, [selected]);
141
+
142
+ const toggle = (toggleRef: React.Ref<MenuToggleElement>) => (
143
+ <MenuToggle variant="typeahead" onClick={onToggleClick} innerRef={toggleRef} isExpanded={isOpen} isFullWidth>
144
+ <TextInputGroup isPlain>
145
+ <TextInputGroupMain
146
+ value={inputValue}
147
+ onClick={onToggleClick}
148
+ onChange={onTextInputChange}
149
+ onKeyDown={onInputKeyDown}
150
+ id="multi-typeahead-select-checkbox-input"
151
+ autoComplete="off"
152
+ innerRef={textInputRef}
153
+ placeholder={placeholder}
154
+ {...(activeItem && { 'aria-activedescendant': activeItem })}
155
+ role="combobox"
156
+ isExpanded={isOpen}
157
+ aria-controls="select-multi-typeahead-checkbox-listbox"
158
+ />
159
+ <TextInputGroupUtilities>
160
+ {selected.length > 0 && (
161
+ <Button
162
+ variant="plain"
163
+ onClick={() => {
164
+ setInputValue('');
165
+ setSelected([]);
166
+ textInputRef?.current?.focus();
167
+ }}
168
+ aria-label="Clear input value"
169
+ >
170
+ <TimesIcon aria-hidden />
171
+ </Button>
172
+ )}
173
+ </TextInputGroupUtilities>
174
+ </TextInputGroup>
175
+ </MenuToggle>
176
+ );
177
+
178
+ return (
179
+ <Select
180
+ role="menu"
181
+ id="multi-typeahead-checkbox-select"
182
+ isOpen={isOpen}
183
+ selected={selected}
184
+ onSelect={(ev, selection) => onSelect(selection as string)}
185
+ onOpenChange={() => setIsOpen(false)}
186
+ toggle={toggle}
187
+ >
188
+ <SelectList id="select-multi-typeahead-checkbox-listbox">
189
+ {selectOptions.map((option, index) => (
190
+ <SelectOption
191
+ {...(!option.isDisabled && { hasCheckbox: true })}
192
+ isSelected={selected.includes(option.itemId)}
193
+ key={option.itemId || option.children}
194
+ isFocused={focusedItemIndex === index}
195
+ className={option.className}
196
+ id={`select-multi-typeahead-${option.itemId.replace(' ', '-')}`}
197
+ {...option}
198
+ ref={null}
199
+ />
200
+ ))}
201
+ </SelectList>
202
+ </Select>
203
+ );
204
+ };
@@ -0,0 +1,222 @@
1
+ import React from 'react';
2
+ import {
3
+ Select,
4
+ SelectOption,
5
+ SelectList,
6
+ SelectOptionProps,
7
+ MenuToggle,
8
+ MenuToggleElement,
9
+ TextInputGroup,
10
+ TextInputGroupMain,
11
+ TextInputGroupUtilities,
12
+ ChipGroup,
13
+ Chip,
14
+ Button
15
+ } from '@patternfly/react-core';
16
+ import TimesIcon from '@patternfly/react-icons/dist/esm/icons/times-icon';
17
+
18
+ let initialSelectOptions: SelectOptionProps[] = [
19
+ { itemId: 'Alabama', children: 'Alabama' },
20
+ { itemId: 'Florida', children: 'Florida' },
21
+ { itemId: 'New Jersey', children: 'New Jersey' },
22
+ { itemId: 'New Mexico', children: 'New Mexico' },
23
+ { itemId: 'New York', children: 'New York' },
24
+ { itemId: 'North Carolina', children: 'North Carolina' }
25
+ ];
26
+
27
+ export const SelectMultiTypeaheadCreatable: React.FunctionComponent = () => {
28
+ const [isOpen, setIsOpen] = React.useState(false);
29
+ const [inputValue, setInputValue] = React.useState<string>('');
30
+ const [selected, setSelected] = React.useState<string[]>([]);
31
+ const [selectOptions, setSelectOptions] = React.useState<SelectOptionProps[]>(initialSelectOptions);
32
+ const [focusedItemIndex, setFocusedItemIndex] = React.useState<number | null>(null);
33
+ const [activeItem, setActiveItem] = React.useState<string | null>(null);
34
+ const [onCreation, setOnCreation] = React.useState<boolean>(false); // Boolean to refresh filter state after new option is created
35
+ const textInputRef = React.useRef<HTMLInputElement>();
36
+
37
+ React.useEffect(() => {
38
+ let newSelectOptions: SelectOptionProps[] = initialSelectOptions;
39
+
40
+ // Filter menu items based on the text input value when one exists
41
+ if (inputValue) {
42
+ newSelectOptions = initialSelectOptions.filter((menuItem) =>
43
+ String(menuItem.children).toLowerCase().includes(inputValue.toLowerCase())
44
+ );
45
+
46
+ // When no options are found after filtering, display creation option
47
+ if (!newSelectOptions.length) {
48
+ newSelectOptions = [{ isDisabled: false, children: `Create new option "${inputValue}"`, itemId: 'create' }];
49
+ }
50
+
51
+ // Open the menu when the input value changes and the new value is not empty
52
+ if (!isOpen) {
53
+ setIsOpen(true);
54
+ }
55
+ }
56
+
57
+ setSelectOptions(newSelectOptions);
58
+ setFocusedItemIndex(null);
59
+ setActiveItem(null);
60
+ }, [inputValue, onCreation]);
61
+
62
+ const handleMenuArrowKeys = (key: string) => {
63
+ let indexToFocus;
64
+
65
+ if (isOpen) {
66
+ if (key === 'ArrowUp') {
67
+ // When no index is set or at the first index, focus to the last, otherwise decrement focus index
68
+ if (focusedItemIndex === null || focusedItemIndex === 0) {
69
+ indexToFocus = selectOptions.length - 1;
70
+ } else {
71
+ indexToFocus = focusedItemIndex - 1;
72
+ }
73
+ }
74
+
75
+ if (key === 'ArrowDown') {
76
+ // When no index is set or at the last index, focus to the first, otherwise increment focus index
77
+ if (focusedItemIndex === null || focusedItemIndex === selectOptions.length - 1) {
78
+ indexToFocus = 0;
79
+ } else {
80
+ indexToFocus = focusedItemIndex + 1;
81
+ }
82
+ }
83
+
84
+ setFocusedItemIndex(indexToFocus);
85
+ const focusedItem = selectOptions.filter((option) => !option.isDisabled)[indexToFocus];
86
+ setActiveItem(`select-multi-create-typeahead-${focusedItem.itemId.replace(' ', '-')}`);
87
+ }
88
+ };
89
+
90
+ const onInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
91
+ const enabledMenuItems = selectOptions.filter((menuItem) => !menuItem.isDisabled);
92
+ const [firstMenuItem] = enabledMenuItems;
93
+ const focusedItem = focusedItemIndex ? enabledMenuItems[focusedItemIndex] : firstMenuItem;
94
+
95
+ switch (event.key) {
96
+ // Select the first available option
97
+ case 'Enter':
98
+ if (!isOpen) {
99
+ setIsOpen((prevIsOpen) => !prevIsOpen);
100
+ } else if (isOpen && focusedItem.itemId !== 'no results') {
101
+ onSelect(focusedItem.itemId as string);
102
+ }
103
+ break;
104
+ case 'Tab':
105
+ case 'Escape':
106
+ setIsOpen(false);
107
+ setActiveItem(null);
108
+ break;
109
+ case 'ArrowUp':
110
+ case 'ArrowDown':
111
+ event.preventDefault();
112
+ handleMenuArrowKeys(event.key);
113
+ break;
114
+ }
115
+ };
116
+
117
+ const onToggleClick = () => {
118
+ setIsOpen(!isOpen);
119
+ };
120
+
121
+ const onTextInputChange = (_event: React.FormEvent<HTMLInputElement>, value: string) => {
122
+ setInputValue(value);
123
+ };
124
+
125
+ const onSelect = (itemId: string) => {
126
+ if (itemId) {
127
+ if (itemId === 'create') {
128
+ if (!initialSelectOptions.some((item) => item.itemId === inputValue)) {
129
+ initialSelectOptions = [...initialSelectOptions, { itemId: inputValue, children: inputValue }];
130
+ }
131
+ setSelected(
132
+ selected.includes(inputValue)
133
+ ? selected.filter((selection) => selection !== inputValue)
134
+ : [...selected, inputValue]
135
+ );
136
+ setOnCreation(!onCreation);
137
+ } else {
138
+ // eslint-disable-next-line no-console
139
+ console.log('selected', itemId);
140
+ setSelected(
141
+ selected.includes(itemId) ? selected.filter((selection) => selection !== itemId) : [...selected, itemId]
142
+ );
143
+ }
144
+ }
145
+
146
+ textInputRef.current?.focus();
147
+ };
148
+
149
+ const toggle = (toggleRef: React.Ref<MenuToggleElement>) => (
150
+ <MenuToggle variant="typeahead" onClick={onToggleClick} innerRef={toggleRef} isExpanded={isOpen} isFullWidth>
151
+ <TextInputGroup isPlain>
152
+ <TextInputGroupMain
153
+ value={inputValue}
154
+ onClick={onToggleClick}
155
+ onChange={onTextInputChange}
156
+ onKeyDown={onInputKeyDown}
157
+ id="multi-create-typeahead-select-input"
158
+ autoComplete="off"
159
+ innerRef={textInputRef}
160
+ placeholder="Select a state"
161
+ {...(activeItem && { 'aria-activedescendant': activeItem })}
162
+ role="combobox"
163
+ isExpanded={isOpen}
164
+ aria-controls="select-multi-create-typeahead-listbox"
165
+ >
166
+ <ChipGroup aria-label="Current selections">
167
+ {selected.map((selection, index) => (
168
+ <Chip
169
+ key={index}
170
+ onClick={(ev) => {
171
+ ev.stopPropagation();
172
+ onSelect(selection);
173
+ }}
174
+ >
175
+ {selection}
176
+ </Chip>
177
+ ))}
178
+ </ChipGroup>
179
+ </TextInputGroupMain>
180
+ <TextInputGroupUtilities>
181
+ {selected.length > 0 && (
182
+ <Button
183
+ variant="plain"
184
+ onClick={() => {
185
+ setInputValue('');
186
+ setSelected([]);
187
+ textInputRef?.current?.focus();
188
+ }}
189
+ aria-label="Clear input value"
190
+ >
191
+ <TimesIcon aria-hidden />
192
+ </Button>
193
+ )}
194
+ </TextInputGroupUtilities>
195
+ </TextInputGroup>
196
+ </MenuToggle>
197
+ );
198
+
199
+ return (
200
+ <Select
201
+ id="multi-create-typeahead-select"
202
+ isOpen={isOpen}
203
+ selected={selected}
204
+ onSelect={(ev, selection) => onSelect(selection as string)}
205
+ onOpenChange={() => setIsOpen(false)}
206
+ toggle={toggle}
207
+ >
208
+ <SelectList isAriaMultiselectable id="select-multi-create-typeahead-listbox">
209
+ {selectOptions.map((option, index) => (
210
+ <SelectOption
211
+ key={option.itemId || option.children}
212
+ isFocused={focusedItemIndex === index}
213
+ className={option.className}
214
+ id={`select-multi-create-typeahead-${option.itemId.replace(' ', '-')}`}
215
+ {...option}
216
+ ref={null}
217
+ />
218
+ ))}
219
+ </SelectList>
220
+ </Select>
221
+ );
222
+ };
@@ -0,0 +1,70 @@
1
+ import React from 'react';
2
+ import { Select, SelectOption, SelectList, MenuToggle, MenuToggleElement } from '@patternfly/react-core';
3
+ import BellIcon from '@patternfly/react-icons/dist/esm/icons/bell-icon';
4
+
5
+ export const SelectOptionVariations: React.FunctionComponent = () => {
6
+ const [isOpen, setIsOpen] = React.useState(false);
7
+ const [selected, setSelected] = React.useState<string>('Select a value');
8
+
9
+ const onToggleClick = () => {
10
+ setIsOpen(!isOpen);
11
+ };
12
+
13
+ const onSelect = (_event: React.MouseEvent<Element, MouseEvent> | undefined, itemId: string | number | undefined) => {
14
+ // eslint-disable-next-line no-console
15
+ console.log('selected', itemId);
16
+
17
+ setSelected(itemId as string);
18
+ setIsOpen(false);
19
+ };
20
+
21
+ const toggle = (toggleRef: React.Ref<MenuToggleElement>) => (
22
+ <MenuToggle
23
+ ref={toggleRef}
24
+ onClick={onToggleClick}
25
+ isExpanded={isOpen}
26
+ style={
27
+ {
28
+ width: '200px'
29
+ } as React.CSSProperties
30
+ }
31
+ >
32
+ {selected}
33
+ </MenuToggle>
34
+ );
35
+
36
+ return (
37
+ <Select
38
+ id="option-variations-select"
39
+ isOpen={isOpen}
40
+ selected={selected}
41
+ onSelect={onSelect}
42
+ onOpenChange={(isOpen) => setIsOpen(isOpen)}
43
+ toggle={toggle}
44
+ shouldFocusToggleOnSelect
45
+ >
46
+ <SelectList>
47
+ <SelectOption itemId="Basic option">Basic option</SelectOption>
48
+ <SelectOption itemId="Option with description" description="This is a description">
49
+ Option with description
50
+ </SelectOption>
51
+ <SelectOption
52
+ to="#"
53
+ // Prevent default clicking functionality for example purposes only
54
+ onClick={(event) => event.preventDefault()}
55
+ itemId="Option with link"
56
+ isExternalLink
57
+ >
58
+ Option with link
59
+ </SelectOption>
60
+ <SelectOption itemId="Option with icon" icon={<BellIcon />}>
61
+ Option with icon
62
+ </SelectOption>
63
+ <SelectOption itemId="Disabled option" isDisabled>
64
+ Disabled option
65
+ </SelectOption>
66
+ <SelectOption itemId="See Menu for additional variations!">See Menu for additional variations!</SelectOption>
67
+ </SelectList>
68
+ </Select>
69
+ );
70
+ };