carbon-react 109.3.4 → 109.3.5
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.
|
@@ -64,6 +64,7 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
|
|
|
64
64
|
const [highlightedValue, setHighlightedValue] = useState("");
|
|
65
65
|
const [filterText, setFilterText] = useState("");
|
|
66
66
|
const [placeholderOverride, setPlaceholderOverride] = useState();
|
|
67
|
+
const actualValue = isControlled.current ? value : selectedValue;
|
|
67
68
|
const setOpen = useCallback(() => {
|
|
68
69
|
setOpenState(isAlreadyOpen => {
|
|
69
70
|
if (!isAlreadyOpen && onOpen) {
|
|
@@ -86,6 +87,23 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
|
|
|
86
87
|
};
|
|
87
88
|
return customEvent;
|
|
88
89
|
}, [name, id]);
|
|
90
|
+
/* generic value update function which can be used for both controlled and uncontrolled
|
|
91
|
+
* components, both with and without onChange.
|
|
92
|
+
* It accepts a function to update the value, which is assumed to be have no side effects and therefore
|
|
93
|
+
* be safe to run more than once if needed. */
|
|
94
|
+
|
|
95
|
+
const updateValue = useCallback(updateFunction => {
|
|
96
|
+
const newValue = updateFunction(actualValue); // only call onChange if an option has been selected or deselected
|
|
97
|
+
|
|
98
|
+
if (onChange && newValue.length !== actualValue.length) {
|
|
99
|
+
onChange(createCustomEvent(newValue));
|
|
100
|
+
} // no need to update selectedValue if the component is controlled: onChange should take care of updating the value
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
if (!isControlled.current) {
|
|
104
|
+
setSelectedValue(updateFunction);
|
|
105
|
+
}
|
|
106
|
+
}, [createCustomEvent, onChange, actualValue]);
|
|
89
107
|
const handleTextboxChange = useCallback(event => {
|
|
90
108
|
const newValue = event.target.value;
|
|
91
109
|
const match = findElementWithMatchingText(newValue, children);
|
|
@@ -99,24 +117,17 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
|
|
|
99
117
|
setOpen();
|
|
100
118
|
}, [children, setOpen]);
|
|
101
119
|
const removeSelectedValue = useCallback(index => {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
120
|
+
isClickTriggeredBySelect.current = true;
|
|
121
|
+
updateValue(previousValue => {
|
|
105
122
|
if (!previousValue.length) {
|
|
106
123
|
return previousValue;
|
|
107
124
|
}
|
|
108
125
|
|
|
109
126
|
const newValue = [...previousValue];
|
|
110
127
|
newValue.splice(index, 1);
|
|
111
|
-
|
|
112
|
-
if (onChange) {
|
|
113
|
-
onChange(createCustomEvent(newValue));
|
|
114
|
-
return newValue;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
128
|
return newValue;
|
|
118
129
|
});
|
|
119
|
-
}, [
|
|
130
|
+
}, [updateValue]);
|
|
120
131
|
const handleTextboxKeydown = useCallback(event => {
|
|
121
132
|
const {
|
|
122
133
|
key
|
|
@@ -142,12 +153,12 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
|
|
|
142
153
|
|
|
143
154
|
}, [onKeyDown, readOnly, filterText, textValue, setOpen, removeSelectedValue]);
|
|
144
155
|
const accessibilityLabel = useMemo(() => {
|
|
145
|
-
return
|
|
146
|
-
return
|
|
156
|
+
return actualValue && actualValue.length ? React.Children.map(children, child => {
|
|
157
|
+
return actualValue.includes(child.props.value) ? child.props.text : false;
|
|
147
158
|
}).filter(child => child).reduce((acc, item) => {
|
|
148
159
|
return acc ? `${acc}, ${item}` : item;
|
|
149
160
|
}, "") : null;
|
|
150
|
-
}, [children,
|
|
161
|
+
}, [children, actualValue]);
|
|
151
162
|
const handleGlobalClick = useCallback(event => {
|
|
152
163
|
isMouseDownReported.current = false;
|
|
153
164
|
|
|
@@ -170,11 +181,11 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
|
|
|
170
181
|
const mapValuesToPills = useMemo(() => {
|
|
171
182
|
const canDelete = !disabled && !readOnly;
|
|
172
183
|
|
|
173
|
-
if (!
|
|
184
|
+
if (!actualValue.length) {
|
|
174
185
|
return "";
|
|
175
186
|
}
|
|
176
187
|
|
|
177
|
-
return
|
|
188
|
+
return actualValue.map((singleValue, index) => {
|
|
178
189
|
const matchingOption = React.Children.toArray(children).find(child => isExpectedOption(child, singleValue));
|
|
179
190
|
let pillProps = {};
|
|
180
191
|
|
|
@@ -203,22 +214,18 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
|
|
|
203
214
|
const onChangeMissingMessage = "onChange prop required when using a controlled input element";
|
|
204
215
|
!(isControlled.current === (value !== undefined)) ? process.env.NODE_ENV !== "production" ? invariant(false, modeSwitchedMessage) : invariant(false) : void 0;
|
|
205
216
|
!(!isControlled.current || isControlled.current && onChange) ? process.env.NODE_ENV !== "production" ? invariant(false, onChangeMissingMessage) : invariant(false) : void 0;
|
|
206
|
-
|
|
207
|
-
if (isControlled.current) {
|
|
208
|
-
setSelectedValue(value);
|
|
209
|
-
}
|
|
210
217
|
}, [value, onChange]); // removes placeholder when a value is present
|
|
211
218
|
|
|
212
219
|
useEffect(() => {
|
|
213
220
|
const hasValue = value === null || value === void 0 ? void 0 : value.length;
|
|
214
|
-
const hasSelectedValue =
|
|
221
|
+
const hasSelectedValue = actualValue === null || actualValue === void 0 ? void 0 : actualValue.length;
|
|
215
222
|
|
|
216
223
|
if (hasValue || hasSelectedValue) {
|
|
217
224
|
setPlaceholderOverride(" ");
|
|
218
225
|
} else {
|
|
219
226
|
setPlaceholderOverride(placeholder);
|
|
220
227
|
}
|
|
221
|
-
}, [value,
|
|
228
|
+
}, [value, actualValue, placeholder]);
|
|
222
229
|
useEffect(() => {
|
|
223
230
|
const clickEvent = "click";
|
|
224
231
|
window.addEventListener(clickEvent, handleGlobalClick);
|
|
@@ -335,27 +342,22 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
|
|
|
335
342
|
}
|
|
336
343
|
|
|
337
344
|
setTextValue("");
|
|
338
|
-
const isAlreadySelected =
|
|
345
|
+
const isAlreadySelected = actualValue.findIndex(val => isExpectedValue(val, newValue)) !== -1;
|
|
339
346
|
|
|
340
347
|
if (!isAlreadySelected && isControlled.current && onChange) {
|
|
341
|
-
onChange(createCustomEvent([...
|
|
348
|
+
onChange(createCustomEvent([...actualValue, newValue]));
|
|
342
349
|
}
|
|
343
350
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
351
|
+
textboxRef.focus();
|
|
352
|
+
isMouseDownReported.current = false;
|
|
353
|
+
updateValue(previousValue => {
|
|
348
354
|
if (isAlreadySelected) {
|
|
349
355
|
return previousValue;
|
|
350
356
|
}
|
|
351
357
|
|
|
352
|
-
if (onChange) {
|
|
353
|
-
onChange(createCustomEvent([...previousValue, newValue]));
|
|
354
|
-
}
|
|
355
|
-
|
|
356
358
|
return [...previousValue, newValue];
|
|
357
359
|
});
|
|
358
|
-
}, [createCustomEvent, onChange, textboxRef,
|
|
360
|
+
}, [createCustomEvent, onChange, textboxRef, actualValue, updateValue]);
|
|
359
361
|
|
|
360
362
|
function onSelectListClose() {
|
|
361
363
|
setOpenState(false);
|
|
@@ -389,7 +391,7 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
|
|
|
389
391
|
leftChildren: mapValuesToPills,
|
|
390
392
|
inputRef: assignInput,
|
|
391
393
|
formattedValue: textValue,
|
|
392
|
-
selectedValue,
|
|
394
|
+
selectedValue: actualValue,
|
|
393
395
|
onClick: handleTextboxClick,
|
|
394
396
|
onMouseDown: handleTextboxMouseDown,
|
|
395
397
|
onFocus: handleTextboxFocus,
|
|
@@ -423,7 +425,7 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
|
|
|
423
425
|
listPlacement: listPlacement,
|
|
424
426
|
flipEnabled: flipEnabled,
|
|
425
427
|
loaderDataRole: "multi-select-list-loader",
|
|
426
|
-
multiselectValues:
|
|
428
|
+
multiselectValues: actualValue
|
|
427
429
|
}, children);
|
|
428
430
|
return /*#__PURE__*/React.createElement(StyledSelectMultiSelect, _extends({
|
|
429
431
|
disabled: disabled,
|
|
@@ -91,6 +91,7 @@ const MultiSelect = /*#__PURE__*/_react.default.forwardRef(({
|
|
|
91
91
|
const [highlightedValue, setHighlightedValue] = (0, _react.useState)("");
|
|
92
92
|
const [filterText, setFilterText] = (0, _react.useState)("");
|
|
93
93
|
const [placeholderOverride, setPlaceholderOverride] = (0, _react.useState)();
|
|
94
|
+
const actualValue = isControlled.current ? value : selectedValue;
|
|
94
95
|
const setOpen = (0, _react.useCallback)(() => {
|
|
95
96
|
setOpenState(isAlreadyOpen => {
|
|
96
97
|
if (!isAlreadyOpen && onOpen) {
|
|
@@ -113,6 +114,23 @@ const MultiSelect = /*#__PURE__*/_react.default.forwardRef(({
|
|
|
113
114
|
};
|
|
114
115
|
return customEvent;
|
|
115
116
|
}, [name, id]);
|
|
117
|
+
/* generic value update function which can be used for both controlled and uncontrolled
|
|
118
|
+
* components, both with and without onChange.
|
|
119
|
+
* It accepts a function to update the value, which is assumed to be have no side effects and therefore
|
|
120
|
+
* be safe to run more than once if needed. */
|
|
121
|
+
|
|
122
|
+
const updateValue = (0, _react.useCallback)(updateFunction => {
|
|
123
|
+
const newValue = updateFunction(actualValue); // only call onChange if an option has been selected or deselected
|
|
124
|
+
|
|
125
|
+
if (onChange && newValue.length !== actualValue.length) {
|
|
126
|
+
onChange(createCustomEvent(newValue));
|
|
127
|
+
} // no need to update selectedValue if the component is controlled: onChange should take care of updating the value
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
if (!isControlled.current) {
|
|
131
|
+
setSelectedValue(updateFunction);
|
|
132
|
+
}
|
|
133
|
+
}, [createCustomEvent, onChange, actualValue]);
|
|
116
134
|
const handleTextboxChange = (0, _react.useCallback)(event => {
|
|
117
135
|
const newValue = event.target.value;
|
|
118
136
|
const match = findElementWithMatchingText(newValue, children);
|
|
@@ -126,24 +144,17 @@ const MultiSelect = /*#__PURE__*/_react.default.forwardRef(({
|
|
|
126
144
|
setOpen();
|
|
127
145
|
}, [children, setOpen]);
|
|
128
146
|
const removeSelectedValue = (0, _react.useCallback)(index => {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
147
|
+
isClickTriggeredBySelect.current = true;
|
|
148
|
+
updateValue(previousValue => {
|
|
132
149
|
if (!previousValue.length) {
|
|
133
150
|
return previousValue;
|
|
134
151
|
}
|
|
135
152
|
|
|
136
153
|
const newValue = [...previousValue];
|
|
137
154
|
newValue.splice(index, 1);
|
|
138
|
-
|
|
139
|
-
if (onChange) {
|
|
140
|
-
onChange(createCustomEvent(newValue));
|
|
141
|
-
return newValue;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
155
|
return newValue;
|
|
145
156
|
});
|
|
146
|
-
}, [
|
|
157
|
+
}, [updateValue]);
|
|
147
158
|
const handleTextboxKeydown = (0, _react.useCallback)(event => {
|
|
148
159
|
const {
|
|
149
160
|
key
|
|
@@ -169,12 +180,12 @@ const MultiSelect = /*#__PURE__*/_react.default.forwardRef(({
|
|
|
169
180
|
|
|
170
181
|
}, [onKeyDown, readOnly, filterText, textValue, setOpen, removeSelectedValue]);
|
|
171
182
|
const accessibilityLabel = (0, _react.useMemo)(() => {
|
|
172
|
-
return
|
|
173
|
-
return
|
|
183
|
+
return actualValue && actualValue.length ? _react.default.Children.map(children, child => {
|
|
184
|
+
return actualValue.includes(child.props.value) ? child.props.text : false;
|
|
174
185
|
}).filter(child => child).reduce((acc, item) => {
|
|
175
186
|
return acc ? `${acc}, ${item}` : item;
|
|
176
187
|
}, "") : null;
|
|
177
|
-
}, [children,
|
|
188
|
+
}, [children, actualValue]);
|
|
178
189
|
const handleGlobalClick = (0, _react.useCallback)(event => {
|
|
179
190
|
isMouseDownReported.current = false;
|
|
180
191
|
|
|
@@ -197,11 +208,11 @@ const MultiSelect = /*#__PURE__*/_react.default.forwardRef(({
|
|
|
197
208
|
const mapValuesToPills = (0, _react.useMemo)(() => {
|
|
198
209
|
const canDelete = !disabled && !readOnly;
|
|
199
210
|
|
|
200
|
-
if (!
|
|
211
|
+
if (!actualValue.length) {
|
|
201
212
|
return "";
|
|
202
213
|
}
|
|
203
214
|
|
|
204
|
-
return
|
|
215
|
+
return actualValue.map((singleValue, index) => {
|
|
205
216
|
const matchingOption = _react.default.Children.toArray(children).find(child => (0, _isExpectedOption.default)(child, singleValue));
|
|
206
217
|
|
|
207
218
|
let pillProps = {};
|
|
@@ -231,22 +242,18 @@ const MultiSelect = /*#__PURE__*/_react.default.forwardRef(({
|
|
|
231
242
|
const onChangeMissingMessage = "onChange prop required when using a controlled input element";
|
|
232
243
|
!(isControlled.current === (value !== undefined)) ? process.env.NODE_ENV !== "production" ? (0, _invariant.default)(false, modeSwitchedMessage) : (0, _invariant.default)(false) : void 0;
|
|
233
244
|
!(!isControlled.current || isControlled.current && onChange) ? process.env.NODE_ENV !== "production" ? (0, _invariant.default)(false, onChangeMissingMessage) : (0, _invariant.default)(false) : void 0;
|
|
234
|
-
|
|
235
|
-
if (isControlled.current) {
|
|
236
|
-
setSelectedValue(value);
|
|
237
|
-
}
|
|
238
245
|
}, [value, onChange]); // removes placeholder when a value is present
|
|
239
246
|
|
|
240
247
|
(0, _react.useEffect)(() => {
|
|
241
248
|
const hasValue = value === null || value === void 0 ? void 0 : value.length;
|
|
242
|
-
const hasSelectedValue =
|
|
249
|
+
const hasSelectedValue = actualValue === null || actualValue === void 0 ? void 0 : actualValue.length;
|
|
243
250
|
|
|
244
251
|
if (hasValue || hasSelectedValue) {
|
|
245
252
|
setPlaceholderOverride(" ");
|
|
246
253
|
} else {
|
|
247
254
|
setPlaceholderOverride(placeholder);
|
|
248
255
|
}
|
|
249
|
-
}, [value,
|
|
256
|
+
}, [value, actualValue, placeholder]);
|
|
250
257
|
(0, _react.useEffect)(() => {
|
|
251
258
|
const clickEvent = "click";
|
|
252
259
|
window.addEventListener(clickEvent, handleGlobalClick);
|
|
@@ -363,27 +370,22 @@ const MultiSelect = /*#__PURE__*/_react.default.forwardRef(({
|
|
|
363
370
|
}
|
|
364
371
|
|
|
365
372
|
setTextValue("");
|
|
366
|
-
const isAlreadySelected =
|
|
373
|
+
const isAlreadySelected = actualValue.findIndex(val => (0, _isExpectedValue.default)(val, newValue)) !== -1;
|
|
367
374
|
|
|
368
375
|
if (!isAlreadySelected && isControlled.current && onChange) {
|
|
369
|
-
onChange(createCustomEvent([...
|
|
376
|
+
onChange(createCustomEvent([...actualValue, newValue]));
|
|
370
377
|
}
|
|
371
378
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
379
|
+
textboxRef.focus();
|
|
380
|
+
isMouseDownReported.current = false;
|
|
381
|
+
updateValue(previousValue => {
|
|
376
382
|
if (isAlreadySelected) {
|
|
377
383
|
return previousValue;
|
|
378
384
|
}
|
|
379
385
|
|
|
380
|
-
if (onChange) {
|
|
381
|
-
onChange(createCustomEvent([...previousValue, newValue]));
|
|
382
|
-
}
|
|
383
|
-
|
|
384
386
|
return [...previousValue, newValue];
|
|
385
387
|
});
|
|
386
|
-
}, [createCustomEvent, onChange, textboxRef,
|
|
388
|
+
}, [createCustomEvent, onChange, textboxRef, actualValue, updateValue]);
|
|
387
389
|
|
|
388
390
|
function onSelectListClose() {
|
|
389
391
|
setOpenState(false);
|
|
@@ -417,7 +419,7 @@ const MultiSelect = /*#__PURE__*/_react.default.forwardRef(({
|
|
|
417
419
|
leftChildren: mapValuesToPills,
|
|
418
420
|
inputRef: assignInput,
|
|
419
421
|
formattedValue: textValue,
|
|
420
|
-
selectedValue,
|
|
422
|
+
selectedValue: actualValue,
|
|
421
423
|
onClick: handleTextboxClick,
|
|
422
424
|
onMouseDown: handleTextboxMouseDown,
|
|
423
425
|
onFocus: handleTextboxFocus,
|
|
@@ -451,7 +453,7 @@ const MultiSelect = /*#__PURE__*/_react.default.forwardRef(({
|
|
|
451
453
|
listPlacement: listPlacement,
|
|
452
454
|
flipEnabled: flipEnabled,
|
|
453
455
|
loaderDataRole: "multi-select-list-loader",
|
|
454
|
-
multiselectValues:
|
|
456
|
+
multiselectValues: actualValue
|
|
455
457
|
}, children);
|
|
456
458
|
|
|
457
459
|
return /*#__PURE__*/_react.default.createElement(_multiSelect.StyledSelectMultiSelect, _extends({
|