carbon-react 146.4.0 → 146.4.1
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.
- package/esm/components/select/__internal__/utils/are-objects-equal.d.ts +1 -0
- package/esm/components/select/__internal__/utils/are-objects-equal.js +20 -0
- package/esm/components/select/filterable-select/filterable-select.component.js +16 -2
- package/lib/components/select/__internal__/utils/are-objects-equal.d.ts +1 -0
- package/lib/components/select/__internal__/utils/are-objects-equal.js +26 -0
- package/lib/components/select/filterable-select/filterable-select.component.js +16 -2
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function areObjectsEqual(obj1: Record<string, unknown>, obj2: Record<string, unknown>): boolean;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export default function areObjectsEqual(obj1, obj2) {
|
|
2
|
+
// Check if both arguments are objects
|
|
3
|
+
if (typeof obj1 !== "object" || typeof obj2 !== "object" || obj1 === null || obj2 === null) {
|
|
4
|
+
return false;
|
|
5
|
+
}
|
|
6
|
+
// Get the keys of both objects
|
|
7
|
+
const keys1 = Object.keys(obj1);
|
|
8
|
+
const keys2 = Object.keys(obj2);
|
|
9
|
+
// If the number of keys is different, objects aren't equal
|
|
10
|
+
if (keys1.length !== keys2.length) {
|
|
11
|
+
return false;
|
|
12
|
+
} // Compare keys and values
|
|
13
|
+
for (const key of keys1) {
|
|
14
|
+
// Check if obj2 has the key and values are strictly equal
|
|
15
|
+
if (!Object.prototype.hasOwnProperty.call(obj2, key) || obj1[key] !== obj2[key]) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
@@ -9,6 +9,7 @@ import withFilter from "../__internal__/utils/with-filter.hoc";
|
|
|
9
9
|
import StyledSelect from "../select.style";
|
|
10
10
|
import SelectList from "../__internal__/select-list/select-list.component";
|
|
11
11
|
import isExpectedOption from "../__internal__/utils/is-expected-option";
|
|
12
|
+
import areObjectsEqual from "../__internal__/utils/are-objects-equal";
|
|
12
13
|
import isNavigationKey from "../__internal__/utils/is-navigation-key";
|
|
13
14
|
import Logger from "../../../__internal__/utils/logger";
|
|
14
15
|
import useStableCallback from "../../../hooks/__internal__/useStableCallback";
|
|
@@ -69,6 +70,7 @@ const FilterableSelect = /*#__PURE__*/React.forwardRef(({
|
|
|
69
70
|
const [isOpen, setOpen] = useState(false);
|
|
70
71
|
const [textValue, setTextValue] = useState("");
|
|
71
72
|
const [selectedValue, setSelectedValue] = useState(value || defaultValue || "");
|
|
73
|
+
const receivedValue = useRef(value);
|
|
72
74
|
const [highlightedValue, setHighlightedValue] = useState("");
|
|
73
75
|
const [filterText, setFilterText] = useState("");
|
|
74
76
|
const inputId = useRef(id || guid());
|
|
@@ -234,15 +236,27 @@ const FilterableSelect = /*#__PURE__*/React.forwardRef(({
|
|
|
234
236
|
const onListActionMissingMessage = "onListAction prop required when using listActionButton prop";
|
|
235
237
|
!(!hasListActionButton || hasListActionButton && onListAction) ? process.env.NODE_ENV !== "production" ? invariant(false, onListActionMissingMessage) : invariant(false) : void 0;
|
|
236
238
|
}, [listActionButton, onListAction]);
|
|
239
|
+
const isFirstRender = useRef(true);
|
|
237
240
|
useEffect(() => {
|
|
241
|
+
// when we render for the first time, we run setMatchingText to populate the input with the correct text
|
|
242
|
+
if (isFirstRender.current) {
|
|
243
|
+
setMatchingText(selectedValue);
|
|
244
|
+
}
|
|
238
245
|
if (isControlled.current) {
|
|
239
|
-
setMatchingText
|
|
246
|
+
// when value is an object we should only run setMatchingText if the object changes between renders
|
|
247
|
+
if (typeof value === "object" && typeof receivedValue.current === "object") {
|
|
248
|
+
if (!areObjectsEqual(value, receivedValue.current)) {
|
|
249
|
+
setMatchingText(value);
|
|
250
|
+
receivedValue.current = value;
|
|
251
|
+
}
|
|
252
|
+
} else {
|
|
253
|
+
setMatchingText(value);
|
|
254
|
+
}
|
|
240
255
|
}
|
|
241
256
|
// update text value only when children are changing
|
|
242
257
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
243
258
|
}, [value, children]);
|
|
244
259
|
const onFilterChange = useStableCallback(onFilterChangeProp);
|
|
245
|
-
const isFirstRender = useRef(true);
|
|
246
260
|
useEffect(() => {
|
|
247
261
|
if (onFilterChange && !isFirstRender.current) {
|
|
248
262
|
onFilterChange(filterText);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function areObjectsEqual(obj1: Record<string, unknown>, obj2: Record<string, unknown>): boolean;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = areObjectsEqual;
|
|
7
|
+
function areObjectsEqual(obj1, obj2) {
|
|
8
|
+
// Check if both arguments are objects
|
|
9
|
+
if (typeof obj1 !== "object" || typeof obj2 !== "object" || obj1 === null || obj2 === null) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
// Get the keys of both objects
|
|
13
|
+
const keys1 = Object.keys(obj1);
|
|
14
|
+
const keys2 = Object.keys(obj2);
|
|
15
|
+
// If the number of keys is different, objects aren't equal
|
|
16
|
+
if (keys1.length !== keys2.length) {
|
|
17
|
+
return false;
|
|
18
|
+
} // Compare keys and values
|
|
19
|
+
for (const key of keys1) {
|
|
20
|
+
// Check if obj2 has the key and values are strictly equal
|
|
21
|
+
if (!Object.prototype.hasOwnProperty.call(obj2, key) || obj1[key] !== obj2[key]) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
@@ -14,6 +14,7 @@ var _withFilter = _interopRequireDefault(require("../__internal__/utils/with-fil
|
|
|
14
14
|
var _select = _interopRequireDefault(require("../select.style"));
|
|
15
15
|
var _selectList = _interopRequireDefault(require("../__internal__/select-list/select-list.component"));
|
|
16
16
|
var _isExpectedOption = _interopRequireDefault(require("../__internal__/utils/is-expected-option"));
|
|
17
|
+
var _areObjectsEqual = _interopRequireDefault(require("../__internal__/utils/are-objects-equal"));
|
|
17
18
|
var _isNavigationKey = _interopRequireDefault(require("../__internal__/utils/is-navigation-key"));
|
|
18
19
|
var _logger = _interopRequireDefault(require("../../../__internal__/utils/logger"));
|
|
19
20
|
var _useStableCallback = _interopRequireDefault(require("../../../hooks/__internal__/useStableCallback"));
|
|
@@ -78,6 +79,7 @@ const FilterableSelect = exports.FilterableSelect = /*#__PURE__*/_react.default.
|
|
|
78
79
|
const [isOpen, setOpen] = (0, _react.useState)(false);
|
|
79
80
|
const [textValue, setTextValue] = (0, _react.useState)("");
|
|
80
81
|
const [selectedValue, setSelectedValue] = (0, _react.useState)(value || defaultValue || "");
|
|
82
|
+
const receivedValue = (0, _react.useRef)(value);
|
|
81
83
|
const [highlightedValue, setHighlightedValue] = (0, _react.useState)("");
|
|
82
84
|
const [filterText, setFilterText] = (0, _react.useState)("");
|
|
83
85
|
const inputId = (0, _react.useRef)(id || (0, _guid.default)());
|
|
@@ -243,15 +245,27 @@ const FilterableSelect = exports.FilterableSelect = /*#__PURE__*/_react.default.
|
|
|
243
245
|
const onListActionMissingMessage = "onListAction prop required when using listActionButton prop";
|
|
244
246
|
!(!hasListActionButton || hasListActionButton && onListAction) ? process.env.NODE_ENV !== "production" ? (0, _invariant.default)(false, onListActionMissingMessage) : (0, _invariant.default)(false) : void 0;
|
|
245
247
|
}, [listActionButton, onListAction]);
|
|
248
|
+
const isFirstRender = (0, _react.useRef)(true);
|
|
246
249
|
(0, _react.useEffect)(() => {
|
|
250
|
+
// when we render for the first time, we run setMatchingText to populate the input with the correct text
|
|
251
|
+
if (isFirstRender.current) {
|
|
252
|
+
setMatchingText(selectedValue);
|
|
253
|
+
}
|
|
247
254
|
if (isControlled.current) {
|
|
248
|
-
setMatchingText
|
|
255
|
+
// when value is an object we should only run setMatchingText if the object changes between renders
|
|
256
|
+
if (typeof value === "object" && typeof receivedValue.current === "object") {
|
|
257
|
+
if (!(0, _areObjectsEqual.default)(value, receivedValue.current)) {
|
|
258
|
+
setMatchingText(value);
|
|
259
|
+
receivedValue.current = value;
|
|
260
|
+
}
|
|
261
|
+
} else {
|
|
262
|
+
setMatchingText(value);
|
|
263
|
+
}
|
|
249
264
|
}
|
|
250
265
|
// update text value only when children are changing
|
|
251
266
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
252
267
|
}, [value, children]);
|
|
253
268
|
const onFilterChange = (0, _useStableCallback.default)(onFilterChangeProp);
|
|
254
|
-
const isFirstRender = (0, _react.useRef)(true);
|
|
255
269
|
(0, _react.useEffect)(() => {
|
|
256
270
|
if (onFilterChange && !isFirstRender.current) {
|
|
257
271
|
onFilterChange(filterText);
|