@patternfly/react-templates 1.1.0-prerelease.27 → 1.1.0-prerelease.29

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 (30) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/components/package.json +1 -1
  3. package/dist/dynamic/components/Dropdown/package.json +1 -1
  4. package/dist/dynamic/components/Select/package.json +1 -1
  5. package/dist/dynamic-modules.json +4 -0
  6. package/dist/esm/components/Select/MultiTypeaheadSelect.d.ts +33 -0
  7. package/dist/esm/components/Select/MultiTypeaheadSelect.d.ts.map +1 -0
  8. package/dist/esm/components/Select/MultiTypeaheadSelect.js +186 -0
  9. package/dist/esm/components/Select/MultiTypeaheadSelect.js.map +1 -0
  10. package/dist/esm/components/Select/index.d.ts +1 -0
  11. package/dist/esm/components/Select/index.d.ts.map +1 -1
  12. package/dist/esm/components/Select/index.js +1 -0
  13. package/dist/esm/components/Select/index.js.map +1 -1
  14. package/dist/js/components/Select/MultiTypeaheadSelect.d.ts +33 -0
  15. package/dist/js/components/Select/MultiTypeaheadSelect.d.ts.map +1 -0
  16. package/dist/js/components/Select/MultiTypeaheadSelect.js +190 -0
  17. package/dist/js/components/Select/MultiTypeaheadSelect.js.map +1 -0
  18. package/dist/js/components/Select/index.d.ts +1 -0
  19. package/dist/js/components/Select/index.d.ts.map +1 -1
  20. package/dist/js/components/Select/index.js +1 -0
  21. package/dist/js/components/Select/index.js.map +1 -1
  22. package/dist/umd/assets/{output-DFpGEInP.css → output-CI6On2mK.css} +7253 -7253
  23. package/dist/umd/react-templates.min.js +1 -1
  24. package/package.json +3 -3
  25. package/src/components/Select/MultiTypeaheadSelect.tsx +348 -0
  26. package/src/components/Select/__tests__/MultiTypeaheadSelect.test.tsx +414 -0
  27. package/src/components/Select/__tests__/__snapshots__/MultiTypeaheadSelect.test.tsx.snap +180 -0
  28. package/src/components/Select/examples/MultiTypeaheadSelectDemo.tsx +35 -0
  29. package/src/components/Select/examples/SelectTemplates.md +7 -1
  30. package/src/components/Select/index.ts +1 -0
@@ -0,0 +1,414 @@
1
+ import * as React from 'react';
2
+ import { render, screen, waitForElementToBeRemoved } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import { MultiTypeaheadSelect } from '../MultiTypeaheadSelect';
5
+ import styles from '@patternfly/react-styles/css/components/Menu/menu';
6
+
7
+ const getToggle = () => screen.getByRole('button', { name: 'Multi select Typeahead menu toggle' });
8
+
9
+ describe('MultiTypeaheadSelect', () => {
10
+ it('renders MultiTypeaheadSelect with options', async () => {
11
+ const initialOptions = [
12
+ { content: 'Option 1', value: 'option1' },
13
+ { content: 'Option 2', value: 'option2' },
14
+ { content: 'Option 3', value: 'option3' }
15
+ ];
16
+
17
+ const user = userEvent.setup();
18
+
19
+ render(<MultiTypeaheadSelect initialOptions={initialOptions} />);
20
+
21
+ const toggle = getToggle();
22
+
23
+ await user.click(toggle);
24
+
25
+ const option1 = screen.getByText('Option 1');
26
+ const option2 = screen.getByText('Option 2');
27
+ const option3 = screen.getByText('Option 3');
28
+
29
+ expect(option1).toBeInTheDocument();
30
+ expect(option2).toBeInTheDocument();
31
+ expect(option3).toBeInTheDocument();
32
+ });
33
+
34
+ it('selects options when clicked', async () => {
35
+ const initialOptions = [
36
+ { content: 'Option 1', value: 'option1' },
37
+ { content: 'Option 2', value: 'option2' },
38
+ { content: 'Option 3', value: 'option3' }
39
+ ];
40
+
41
+ const user = userEvent.setup();
42
+
43
+ render(<MultiTypeaheadSelect initialOptions={initialOptions} />);
44
+
45
+ const toggle = getToggle();
46
+
47
+ await user.click(toggle);
48
+
49
+ const option1 = screen.getByRole('option', { name: 'Option 1' });
50
+
51
+ expect(option1).not.toHaveClass(styles.modifiers.selected);
52
+
53
+ await user.click(option1);
54
+
55
+ expect(option1).toHaveClass(styles.modifiers.selected);
56
+ });
57
+
58
+ it('calls the onSelectionChange callback with the selected value when an option is selected', async () => {
59
+ const initialOptions = [
60
+ { content: 'Option 1', value: 'option1' },
61
+ { content: 'Option 2', value: 'option2' },
62
+ { content: 'Option 3', value: 'option3' }
63
+ ];
64
+
65
+ const user = userEvent.setup();
66
+ const onSelectionChangeMock = jest.fn();
67
+
68
+ render(<MultiTypeaheadSelect initialOptions={initialOptions} onSelect={onSelectionChangeMock} />);
69
+
70
+ const toggle = getToggle();
71
+
72
+ await user.click(toggle);
73
+
74
+ expect(onSelectionChangeMock).not.toHaveBeenCalled();
75
+
76
+ const option1 = screen.getByRole('option', { name: 'Option 1' });
77
+
78
+ await user.click(option1);
79
+
80
+ expect(onSelectionChangeMock).toHaveBeenCalledTimes(1);
81
+ expect(onSelectionChangeMock).toHaveBeenCalledWith(expect.anything(), 'option1');
82
+ });
83
+
84
+ it('deselects options when clear button is clicked', async () => {
85
+ const initialOptions = [
86
+ { content: 'Option 1', value: 'option1' },
87
+ { content: 'Option 2', value: 'option2' },
88
+ { content: 'Option 3', value: 'option3' }
89
+ ];
90
+
91
+ const user = userEvent.setup();
92
+
93
+ render(<MultiTypeaheadSelect initialOptions={initialOptions} />);
94
+
95
+ const toggle = getToggle();
96
+
97
+ await user.click(toggle);
98
+
99
+ const option1 = screen.getByRole('option', { name: 'Option 1' });
100
+ await user.click(option1);
101
+ expect(option1).toHaveClass(styles.modifiers.selected);
102
+
103
+ const input = screen.getByRole('combobox');
104
+
105
+ const clearButton = screen.getByRole('button', { name: 'Clear input value' });
106
+ await user.click(clearButton);
107
+
108
+ expect(input).toHaveValue('');
109
+
110
+ await user.click(toggle);
111
+ expect(screen.getByRole('option', { name: 'Option 1' })).not.toHaveClass(styles.modifiers.selected);
112
+ });
113
+
114
+ it('toggles the select menu when the toggle button is clicked', async () => {
115
+ const initialOptions = [
116
+ { content: 'Option 1', value: 'option1' },
117
+ { content: 'Option 2', value: 'option2' },
118
+ { content: 'Option 3', value: 'option3' }
119
+ ];
120
+
121
+ const user = userEvent.setup();
122
+
123
+ render(<MultiTypeaheadSelect initialOptions={initialOptions} />);
124
+
125
+ const toggle = getToggle();
126
+
127
+ await user.click(toggle);
128
+
129
+ const menu = screen.getByRole('listbox');
130
+ expect(menu).toBeInTheDocument();
131
+
132
+ await user.click(toggle);
133
+
134
+ await waitForElementToBeRemoved(menu);
135
+
136
+ expect(screen.queryByRole('listbox')).not.toBeInTheDocument();
137
+ });
138
+
139
+ it('calls the onToggle callback when the toggle is clicked', async () => {
140
+ const initialOptions = [
141
+ { content: 'Option 1', value: 'option1' },
142
+ { content: 'Option 2', value: 'option2' },
143
+ { content: 'Option 3', value: 'option3' }
144
+ ];
145
+
146
+ const user = userEvent.setup();
147
+ const onToggleMock = jest.fn();
148
+
149
+ render(<MultiTypeaheadSelect initialOptions={initialOptions} onToggle={onToggleMock} />);
150
+
151
+ const toggle = getToggle();
152
+
153
+ expect(onToggleMock).not.toHaveBeenCalled();
154
+
155
+ await user.click(toggle);
156
+
157
+ expect(onToggleMock).toHaveBeenCalledTimes(1);
158
+ expect(onToggleMock).toHaveBeenCalledWith(true);
159
+
160
+ await user.click(toggle);
161
+
162
+ expect(onToggleMock).toHaveBeenCalledTimes(2);
163
+ expect(onToggleMock).toHaveBeenCalledWith(false);
164
+ });
165
+
166
+ it('Passes toggleWidth', () => {
167
+ const initialOptions = [
168
+ { content: 'Option 1', value: 'option1' },
169
+ { content: 'Option 2', value: 'option2' },
170
+ { content: 'Option 3', value: 'option3' }
171
+ ];
172
+
173
+ render(<MultiTypeaheadSelect initialOptions={initialOptions} toggleWidth="500px" />);
174
+
175
+ const toggle = getToggle();
176
+ expect(toggle.parentElement).toHaveAttribute('style', 'width: 500px;');
177
+ });
178
+
179
+ it('Passes additional toggleProps', () => {
180
+ const initialOptions = [
181
+ { content: 'Option 1', value: 'option1' },
182
+ { content: 'Option 2', value: 'option2' },
183
+ { content: 'Option 3', value: 'option3' }
184
+ ];
185
+
186
+ render(<MultiTypeaheadSelect initialOptions={initialOptions} toggleProps={{ id: 'toggle' }} />);
187
+
188
+ const toggle = getToggle();
189
+ expect(toggle.parentElement).toHaveAttribute('id', 'toggle');
190
+ });
191
+
192
+ it('passes custom placeholder text', async () => {
193
+ const initialOptions = [
194
+ { content: 'Option 1', value: 'option1' },
195
+ { content: 'Option 2', value: 'option2' },
196
+ { content: 'Option 3', value: 'option3' }
197
+ ];
198
+
199
+ render(<MultiTypeaheadSelect initialOptions={initialOptions} placeholder="custom" />);
200
+
201
+ const input = screen.getByRole('combobox');
202
+
203
+ expect(input).toHaveAttribute('placeholder', 'custom');
204
+ });
205
+
206
+ it('displays noOptionsFoundMessage when filter returns no results', async () => {
207
+ const initialOptions = [
208
+ { content: 'Option 1', value: 'option1' },
209
+ { content: 'Option 2', value: 'option2' },
210
+ { content: 'Option 3', value: 'option3' }
211
+ ];
212
+ const user = userEvent.setup();
213
+
214
+ render(<MultiTypeaheadSelect initialOptions={initialOptions} />);
215
+
216
+ const toggle = getToggle();
217
+ const input = screen.getByRole('combobox');
218
+
219
+ expect(input).toHaveAttribute('placeholder', 'Select an option');
220
+
221
+ await user.click(toggle);
222
+
223
+ const option1 = screen.getByRole('option', { name: 'Option 1' });
224
+ const option2 = screen.getByRole('option', { name: 'Option 2' });
225
+ const option3 = screen.getByRole('option', { name: 'Option 3' });
226
+
227
+ expect(option1).toBeInTheDocument();
228
+ expect(option2).toBeInTheDocument();
229
+ expect(option3).toBeInTheDocument();
230
+
231
+ await user.type(input, '9');
232
+ expect(input).toHaveValue('9');
233
+
234
+ expect(option1).not.toBeInTheDocument();
235
+ expect(option2).not.toBeInTheDocument();
236
+ expect(option3).not.toBeInTheDocument();
237
+ expect(screen.getByRole('option', { name: 'No results found for "9"' })).toBeInTheDocument();
238
+ });
239
+
240
+ it('displays custom noOptionsFoundMessage', async () => {
241
+ const initialOptions = [
242
+ { content: 'Option 1', value: 'option1' },
243
+ { content: 'Option 2', value: 'option2' },
244
+ { content: 'Option 3', value: 'option3' }
245
+ ];
246
+ const user = userEvent.setup();
247
+
248
+ render(<MultiTypeaheadSelect initialOptions={initialOptions} noOptionsFoundMessage="custom" />);
249
+
250
+ const toggle = getToggle();
251
+ const input = screen.getByRole('combobox');
252
+
253
+ expect(input).toHaveAttribute('placeholder', 'Select an option');
254
+
255
+ await user.click(toggle);
256
+
257
+ const option1 = screen.getByRole('option', { name: 'Option 1' });
258
+ const option2 = screen.getByRole('option', { name: 'Option 2' });
259
+ const option3 = screen.getByRole('option', { name: 'Option 3' });
260
+
261
+ expect(option1).toBeInTheDocument();
262
+ expect(option2).toBeInTheDocument();
263
+ expect(option3).toBeInTheDocument();
264
+
265
+ await user.type(input, '9');
266
+ expect(input).toHaveValue('9');
267
+
268
+ expect(option1).not.toBeInTheDocument();
269
+ expect(option2).not.toBeInTheDocument();
270
+ expect(option3).not.toBeInTheDocument();
271
+ expect(screen.getByRole('option', { name: 'custom' })).toBeInTheDocument();
272
+ });
273
+
274
+ it('disables the select when isDisabled prop is true', async () => {
275
+ const initialOptions = [
276
+ { content: 'Option 1', value: 'option1' },
277
+ { content: 'Option 2', value: 'option2' },
278
+ { content: 'Option 3', value: 'option3' }
279
+ ];
280
+
281
+ const user = userEvent.setup();
282
+
283
+ render(<MultiTypeaheadSelect initialOptions={initialOptions} isDisabled={true} />);
284
+
285
+ const toggle = getToggle();
286
+
287
+ expect(toggle.parentElement).toHaveClass(styles.modifiers.disabled);
288
+
289
+ await user.click(toggle);
290
+
291
+ expect(screen.queryByRole('menu')).not.toBeInTheDocument();
292
+ });
293
+
294
+ it('passes other SelectOption props to the SelectOption component', async () => {
295
+ const initialOptions = [{ content: 'Option 1', value: 'option1', isDisabled: true }];
296
+
297
+ const user = userEvent.setup();
298
+
299
+ render(<MultiTypeaheadSelect initialOptions={initialOptions} />);
300
+
301
+ const toggle = getToggle();
302
+
303
+ await user.click(toggle);
304
+
305
+ const option1 = screen.getByRole('option', { name: 'Option 1' });
306
+ expect(option1).toBeDisabled();
307
+ });
308
+
309
+ it('displays the option in chip when option is selected', async () => {
310
+ const initialOptions = [
311
+ { content: 'Option 1', value: 'option1' },
312
+ { content: 'Option 2', value: 'option2' },
313
+ { content: 'Option 3', value: 'option3' }
314
+ ];
315
+
316
+ const user = userEvent.setup();
317
+
318
+ render(<MultiTypeaheadSelect initialOptions={initialOptions} />);
319
+
320
+ const toggle = getToggle();
321
+ const input = screen.getByRole('combobox');
322
+
323
+ expect(input).toHaveAttribute('placeholder', 'Select an option');
324
+
325
+ await user.click(toggle);
326
+
327
+ const option1 = screen.getByRole('option', { name: 'Option 1' });
328
+
329
+ await user.click(option1);
330
+
331
+ await user.click(toggle);
332
+
333
+ // TODO: How to find the chips?
334
+
335
+ const clearButton = screen.getByRole('button', { name: 'Clear input value' });
336
+ await user.click(clearButton);
337
+
338
+ // TODO: How to find the chips?
339
+ });
340
+
341
+ it('typing in input filters options', async () => {
342
+ const initialOptions = [
343
+ { content: 'Option 1', value: 'option1' },
344
+ { content: 'Option 2', value: 'option2' },
345
+ { content: 'Option 3', value: 'option3' }
346
+ ];
347
+
348
+ const user = userEvent.setup();
349
+
350
+ render(<MultiTypeaheadSelect initialOptions={initialOptions} />);
351
+
352
+ const toggle = getToggle();
353
+ const input = screen.getByRole('combobox');
354
+
355
+ expect(input).toHaveAttribute('placeholder', 'Select an option');
356
+
357
+ await user.click(toggle);
358
+
359
+ const option1 = screen.getByRole('option', { name: 'Option 1' });
360
+ const option2 = screen.getByRole('option', { name: 'Option 2' });
361
+ const option3 = screen.getByRole('option', { name: 'Option 3' });
362
+
363
+ expect(option1).toBeInTheDocument();
364
+ expect(option2).toBeInTheDocument();
365
+ expect(option3).toBeInTheDocument();
366
+
367
+ await user.type(input, '1');
368
+ expect(input).toHaveValue('1');
369
+
370
+ expect(option1).toBeInTheDocument();
371
+ expect(option2).not.toBeInTheDocument();
372
+ expect(option3).not.toBeInTheDocument();
373
+ });
374
+
375
+ it('typing in input triggers onInputChange callback', async () => {
376
+ const initialOptions = [
377
+ { content: 'Option 1', value: 'option1' },
378
+ { content: 'Option 2', value: 'option2' },
379
+ { content: 'Option 3', value: 'option3' }
380
+ ];
381
+
382
+ const user = userEvent.setup();
383
+ const onInputChangeMock = jest.fn();
384
+
385
+ render(<MultiTypeaheadSelect initialOptions={initialOptions} onInputChange={onInputChangeMock} />);
386
+
387
+ const input = screen.getByRole('combobox');
388
+
389
+ expect(input).toHaveAttribute('placeholder', 'Select an option');
390
+
391
+ await user.type(input, '1');
392
+
393
+ expect(input).toHaveValue('1');
394
+ expect(onInputChangeMock).toHaveBeenCalledTimes(1);
395
+ expect(onInputChangeMock).toHaveBeenCalledWith('1');
396
+ });
397
+
398
+ it('Matches snapshot', async () => {
399
+ const initialOptions = [
400
+ { content: 'Option 1', value: 'option1' },
401
+ { content: 'Option 2', value: 'option2' },
402
+ { content: 'Option 3', value: 'option3' }
403
+ ];
404
+
405
+ const user = userEvent.setup();
406
+
407
+ const { asFragment } = render(<MultiTypeaheadSelect initialOptions={initialOptions} />);
408
+
409
+ const toggle = getToggle();
410
+ await user.click(toggle);
411
+
412
+ expect(asFragment()).toMatchSnapshot();
413
+ });
414
+ });
@@ -0,0 +1,180 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`MultiTypeaheadSelect Matches snapshot 1`] = `
4
+ <DocumentFragment>
5
+ <div
6
+ class="pf-v5-c-menu-toggle pf-m-expanded pf-m-full-width pf-m-typeahead"
7
+ >
8
+ <div
9
+ class="pf-v5-c-text-input-group pf-m-plain"
10
+ >
11
+ <div
12
+ autocomplete="off"
13
+ class="pf-v5-c-text-input-group__main"
14
+ >
15
+ <span
16
+ class="pf-v5-c-text-input-group__text"
17
+ >
18
+ <input
19
+ aria-controls="select-typeahead-listbox"
20
+ aria-expanded="true"
21
+ aria-label="Type to filter"
22
+ class="pf-v5-c-text-input-group__text-input"
23
+ placeholder="Select an option"
24
+ role="combobox"
25
+ type="text"
26
+ value=""
27
+ />
28
+ </span>
29
+ </div>
30
+ <div
31
+ class="pf-v5-c-text-input-group__utilities"
32
+ style="display: none;"
33
+ >
34
+ <button
35
+ aria-disabled="false"
36
+ aria-label="Clear input value"
37
+ class="pf-v5-c-button pf-m-plain"
38
+ data-ouia-component-id="OUIA-Generated-Button-plain-20"
39
+ data-ouia-component-type="PF5/Button"
40
+ data-ouia-safe="true"
41
+ type="button"
42
+ >
43
+ <svg
44
+ aria-hidden="true"
45
+ class="pf-v5-svg"
46
+ fill="currentColor"
47
+ height="1em"
48
+ role="img"
49
+ viewBox="0 0 352 512"
50
+ width="1em"
51
+ >
52
+ <path
53
+ d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"
54
+ />
55
+ </svg>
56
+ </button>
57
+ </div>
58
+ </div>
59
+ <button
60
+ aria-expanded="true"
61
+ aria-label="Multi select Typeahead menu toggle"
62
+ class="pf-v5-c-menu-toggle__button"
63
+ data-ouia-component-id="OUIA-Generated-MenuToggle-typeahead-17"
64
+ data-ouia-component-type="PF5/MenuToggle"
65
+ data-ouia-safe="true"
66
+ tabindex="-1"
67
+ type="button"
68
+ >
69
+ <span
70
+ class="pf-v5-c-menu-toggle__controls"
71
+ >
72
+ <span
73
+ class="pf-v5-c-menu-toggle__toggle-icon"
74
+ >
75
+ <svg
76
+ aria-hidden="true"
77
+ class="pf-v5-svg"
78
+ fill="currentColor"
79
+ height="1em"
80
+ role="img"
81
+ viewBox="0 0 320 512"
82
+ width="1em"
83
+ >
84
+ <path
85
+ d="M31.3 192h257.3c17.8 0 26.7 21.5 14.1 34.1L174.1 354.8c-7.8 7.8-20.5 7.8-28.3 0L17.2 226.1C4.6 213.5 13.5 192 31.3 192z"
86
+ />
87
+ </svg>
88
+ </span>
89
+ </span>
90
+ </button>
91
+ </div>
92
+ <div
93
+ class="pf-v5-c-menu"
94
+ data-ouia-component-id="OUIA-Generated-Select-68"
95
+ data-ouia-component-type="PF5/Select"
96
+ data-ouia-safe="true"
97
+ data-popper-escaped="true"
98
+ data-popper-placement="bottom-start"
99
+ data-popper-reference-hidden="true"
100
+ style="position: absolute; left: 0px; top: 0px; z-index: 9999; opacity: 1; transition: opacity 0ms cubic-bezier(.54, 1.5, .38, 1.11); min-width: 0px; transform: translate(0px, 0px);"
101
+ >
102
+ <div
103
+ class="pf-v5-c-menu__content"
104
+ >
105
+ <ul
106
+ aria-multiselectable="false"
107
+ class="pf-v5-c-menu__list"
108
+ role="listbox"
109
+ >
110
+ <li
111
+ class="pf-v5-c-menu__list-item"
112
+ role="none"
113
+ >
114
+ <button
115
+ aria-selected="false"
116
+ class="pf-v5-c-menu__item"
117
+ role="option"
118
+ tabindex="0"
119
+ type="button"
120
+ >
121
+ <span
122
+ class="pf-v5-c-menu__item-main"
123
+ >
124
+ <span
125
+ class="pf-v5-c-menu__item-text"
126
+ >
127
+ Option 1
128
+ </span>
129
+ </span>
130
+ </button>
131
+ </li>
132
+ <li
133
+ class="pf-v5-c-menu__list-item"
134
+ role="none"
135
+ >
136
+ <button
137
+ aria-selected="false"
138
+ class="pf-v5-c-menu__item"
139
+ role="option"
140
+ tabindex="-1"
141
+ type="button"
142
+ >
143
+ <span
144
+ class="pf-v5-c-menu__item-main"
145
+ >
146
+ <span
147
+ class="pf-v5-c-menu__item-text"
148
+ >
149
+ Option 2
150
+ </span>
151
+ </span>
152
+ </button>
153
+ </li>
154
+ <li
155
+ class="pf-v5-c-menu__list-item"
156
+ role="none"
157
+ >
158
+ <button
159
+ aria-selected="false"
160
+ class="pf-v5-c-menu__item"
161
+ role="option"
162
+ tabindex="-1"
163
+ type="button"
164
+ >
165
+ <span
166
+ class="pf-v5-c-menu__item-main"
167
+ >
168
+ <span
169
+ class="pf-v5-c-menu__item-text"
170
+ >
171
+ Option 3
172
+ </span>
173
+ </span>
174
+ </button>
175
+ </li>
176
+ </ul>
177
+ </div>
178
+ </div>
179
+ </DocumentFragment>
180
+ `;
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import { MultiTypeaheadSelect, MultiTypeaheadSelectOption } from '@patternfly/react-templates';
3
+
4
+ const Options = [
5
+ { content: 'Alabama', value: 'option1' },
6
+ { content: 'Arizona', value: 'option2' },
7
+ { content: 'California', value: 'option3' },
8
+ { content: 'Florida', value: 'option4' },
9
+ { content: 'Massachusetts', value: 'option5' },
10
+ { content: 'Maine', value: 'option6' },
11
+ { content: 'New Jersey', value: 'option7' },
12
+ { content: 'New Mexico', value: 'option8' },
13
+ { content: 'New York', value: 'option9' },
14
+ { content: 'North Carolina', value: 'option10' }
15
+ ];
16
+
17
+ type SelectionsType = (string | number)[];
18
+
19
+ export const MultiSelectTypeaheadDemo: React.FunctionComponent = () => {
20
+ const [selected, setSelected] = React.useState<SelectionsType>(['option5']);
21
+
22
+ const initialOptions = React.useMemo<MultiTypeaheadSelectOption[]>(
23
+ () => Options.map((o) => ({ ...o, selected: selected.includes(o.value) })),
24
+ [selected]
25
+ );
26
+
27
+ return (
28
+ <MultiTypeaheadSelect
29
+ initialOptions={initialOptions}
30
+ placeholder="Select a state"
31
+ noOptionsFoundMessage={(filter) => `No state was found for "${filter}"`}
32
+ onSelectionChange={(_ev, selections) => setSelected(selections)}
33
+ />
34
+ );
35
+ };
@@ -12,7 +12,7 @@ Note: Templates live in their own package at [@patternfly/react-templates](https
12
12
  For custom use cases, please see the select component suite from [@patternfly/react-core](https://www.npmjs.com/package/@patternfly/react-core).
13
13
 
14
14
  import { Checkbox } from '@patternfly/react-core';
15
- import { SimpleSelect, CheckboxSelect, TypeaheadSelect } from '@patternfly/react-templates';
15
+ import { SimpleSelect, CheckboxSelect, TypeaheadSelect, MultiTypeaheadSelect } from '@patternfly/react-templates';
16
16
 
17
17
  ## Select template examples
18
18
 
@@ -33,3 +33,9 @@ import { SimpleSelect, CheckboxSelect, TypeaheadSelect } from '@patternfly/react
33
33
  ```ts file="TypeaheadSelectDemo.tsx"
34
34
 
35
35
  ```
36
+
37
+ ### Multi-Typeahead
38
+
39
+ ```ts file="MultiTypeaheadSelectDemo.tsx"
40
+
41
+ ```
@@ -1,3 +1,4 @@
1
1
  export * from './SimpleSelect';
2
2
  export * from './CheckboxSelect';
3
3
  export * from './TypeaheadSelect';
4
+ export * from './MultiTypeaheadSelect';