@patternfly/react-templates 1.1.0-prerelease.36 → 1.1.0-prerelease.37

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.
@@ -40,6 +40,12 @@ export interface TypeaheadSelectProps extends Omit<SelectProps, 'toggle'> {
40
40
  onClearSelection?: () => void;
41
41
  /** Placeholder text for the select input. */
42
42
  placeholder?: string;
43
+ /** Flag to indicate if the typeahead select allows new items */
44
+ isCreatable?: boolean;
45
+ /** Flag to indicate if create option should be at top of typeahead */
46
+ isCreateOptionOnTop?: boolean;
47
+ /** Message to display to create a new option */
48
+ createOptionMessage?: string | ((newValue: string) => string);
43
49
  /** Message to display when no options are available. */
44
50
  noOptionsAvailableMessage?: string;
45
51
  /** Message to display when no options match the filter. */
@@ -52,6 +58,9 @@ export interface TypeaheadSelectProps extends Omit<SelectProps, 'toggle'> {
52
58
  toggleProps?: MenuToggleProps;
53
59
  }
54
60
 
61
+ const defaultNoOptionsFoundMessage = (filter: string) => `No results found for "${filter}"`;
62
+ const defaultCreateOptionMessage = (newValue: string) => `Create "${newValue}"`;
63
+
55
64
  export const TypeaheadSelectBase: React.FunctionComponent<TypeaheadSelectProps> = ({
56
65
  innerRef,
57
66
  initialOptions,
@@ -61,7 +70,10 @@ export const TypeaheadSelectBase: React.FunctionComponent<TypeaheadSelectProps>
61
70
  onClearSelection,
62
71
  placeholder = 'Select an option',
63
72
  noOptionsAvailableMessage = 'No options are available',
64
- noOptionsFoundMessage = (filter) => `No results found for "${filter}"`,
73
+ noOptionsFoundMessage = defaultNoOptionsFoundMessage,
74
+ isCreatable = false,
75
+ isCreateOptionOnTop = false,
76
+ createOptionMessage = defaultCreateOptionMessage,
65
77
  isDisabled,
66
78
  toggleWidth,
67
79
  toggleProps,
@@ -89,6 +101,20 @@ export const TypeaheadSelectBase: React.FunctionComponent<TypeaheadSelectProps>
89
101
  String(option.content).toLowerCase().includes(filterValue.toLowerCase())
90
102
  );
91
103
 
104
+ if (
105
+ isCreatable &&
106
+ filterValue &&
107
+ !initialOptions.find((o) => String(o.content).toLowerCase() === filterValue.toLowerCase())
108
+ ) {
109
+ const createOption = {
110
+ content: typeof createOptionMessage === 'string' ? createOptionMessage : createOptionMessage(filterValue),
111
+ value: filterValue
112
+ };
113
+ newSelectOptions = isCreateOptionOnTop
114
+ ? [createOption, ...newSelectOptions]
115
+ : [...newSelectOptions, createOption];
116
+ }
117
+
92
118
  // When no options are found after filtering, display 'No results found'
93
119
  if (!newSelectOptions.length) {
94
120
  newSelectOptions = [
@@ -102,9 +128,7 @@ export const TypeaheadSelectBase: React.FunctionComponent<TypeaheadSelectProps>
102
128
  }
103
129
 
104
130
  // Open the menu when the input value changes and the new value is not empty
105
- if (!isOpen) {
106
- openMenu();
107
- }
131
+ openMenu();
108
132
  }
109
133
 
110
134
  // When no options are available, display 'No options available'
@@ -119,7 +143,15 @@ export const TypeaheadSelectBase: React.FunctionComponent<TypeaheadSelectProps>
119
143
  }
120
144
 
121
145
  setSelectOptions(newSelectOptions);
122
- }, [filterValue, initialOptions]);
146
+ }, [
147
+ filterValue,
148
+ initialOptions,
149
+ noOptionsFoundMessage,
150
+ isCreatable,
151
+ isCreateOptionOnTop,
152
+ createOptionMessage,
153
+ noOptionsAvailableMessage
154
+ ]);
123
155
 
124
156
  React.useEffect(() => {
125
157
  const selectedOption = initialOptions.find((o) => o.selected);
@@ -138,8 +170,10 @@ export const TypeaheadSelectBase: React.FunctionComponent<TypeaheadSelectProps>
138
170
  };
139
171
 
140
172
  const openMenu = () => {
141
- onToggle && onToggle(true);
142
- setIsOpen(true);
173
+ if (!isOpen) {
174
+ onToggle && onToggle(true);
175
+ setIsOpen(true);
176
+ }
143
177
  };
144
178
 
145
179
  const closeMenu = () => {
@@ -191,9 +225,7 @@ export const TypeaheadSelectBase: React.FunctionComponent<TypeaheadSelectProps>
191
225
  const handleMenuArrowKeys = (key: string) => {
192
226
  let indexToFocus = 0;
193
227
 
194
- if (!isOpen) {
195
- openMenu();
196
- }
228
+ openMenu();
197
229
 
198
230
  if (selectOptions.every((option) => option.isDisabled)) {
199
231
  return;
@@ -245,10 +277,7 @@ export const TypeaheadSelectBase: React.FunctionComponent<TypeaheadSelectProps>
245
277
  selectOption(event, focusedItem);
246
278
  }
247
279
 
248
- if (!isOpen) {
249
- onToggle && onToggle(true);
250
- setIsOpen(true);
251
- }
280
+ openMenu();
252
281
 
253
282
  break;
254
283
  case 'ArrowUp':
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import { TypeaheadSelect, TypeaheadSelectOption } from '@patternfly/react-templates';
3
+ import { Checkbox } from '@patternfly/react-core';
3
4
 
4
5
  const Options = [
5
6
  { content: 'Alabama', value: 'option1' },
@@ -13,10 +14,13 @@ const Options = [
13
14
  /* eslint-disable no-console */
14
15
  export const SelectTypeaheadDemo: React.FunctionComponent = () => {
15
16
  const [selected, setSelected] = React.useState<string | undefined>();
17
+ const [options, setOptions] = React.useState(Options);
18
+ const [isCreatable, setIsCreatable] = React.useState<boolean>(false);
19
+ const [isCreateOptionOnTop, setIsCreateOptionOnTop] = React.useState<boolean>(false);
16
20
 
17
21
  const initialOptions = React.useMemo<TypeaheadSelectOption[]>(
18
- () => Options.map((o) => ({ ...o, selected: o.value === selected })),
19
- [selected]
22
+ () => options.map((o) => ({ ...o, selected: o.value === selected })),
23
+ [options, selected]
20
24
  );
21
25
 
22
26
  React.useEffect(() => {
@@ -24,12 +28,38 @@ export const SelectTypeaheadDemo: React.FunctionComponent = () => {
24
28
  }, [selected]);
25
29
 
26
30
  return (
27
- <TypeaheadSelect
28
- initialOptions={initialOptions}
29
- placeholder="Select a state"
30
- noOptionsFoundMessage={(filter) => `No state was found for "${filter}"`}
31
- onClearSelection={() => setSelected(undefined)}
32
- onSelect={(_ev, selection) => setSelected(String(selection))}
33
- />
31
+ <>
32
+ <TypeaheadSelect
33
+ initialOptions={initialOptions}
34
+ placeholder="Select a state"
35
+ noOptionsFoundMessage={(filter) => `No state was found for "${filter}"`}
36
+ onClearSelection={() => setSelected(undefined)}
37
+ onSelect={(_ev, selection) => {
38
+ if (!options.find((o) => o.content === selection)) {
39
+ setOptions([...options, { content: String(selection), value: String(selection) }]);
40
+ }
41
+ setSelected(String(selection));
42
+ }}
43
+ isCreatable={isCreatable}
44
+ isCreateOptionOnTop={isCreateOptionOnTop}
45
+ />
46
+ <Checkbox
47
+ className="pf-u-mt-sm"
48
+ label="isCreatable"
49
+ isChecked={isCreatable}
50
+ onChange={(_event, checked) => setIsCreatable(checked)}
51
+ aria-label="toggle creatable checkbox"
52
+ id="toggle-creatable-typeahead"
53
+ name="toggle-creatable-typeahead"
54
+ />
55
+ <Checkbox
56
+ label="isCreateOptionOnTop"
57
+ isChecked={isCreateOptionOnTop}
58
+ onChange={(_event, checked) => setIsCreateOptionOnTop(checked)}
59
+ aria-label="toggle createOptionOnTop checkbox"
60
+ id="toggle-create-option-on-top-typeahead"
61
+ name="toggle-create-option-on-top-typeahead"
62
+ />
63
+ </>
34
64
  );
35
65
  };