carbon-react 146.4.0 → 146.4.2

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.
@@ -49,9 +49,11 @@ const SelectList = /*#__PURE__*/React.forwardRef(({
49
49
  }, listContainerRef) => {
50
50
  const [currentOptionsListIndex, setCurrentOptionsListIndex] = useState(-1);
51
51
  const [scrollbarWidth, setScrollbarWidth] = useState(0);
52
+ const [actualPlacement, setActualPlacement] = useState(listPlacement);
52
53
  const lastFilter = useRef("");
53
54
  const listRef = useRef(null);
54
55
  const tableRef = useRef(null);
56
+ const listWrapperRef = useRef(null);
55
57
  const listActionButtonRef = useRef(null);
56
58
  const {
57
59
  blockScroll,
@@ -386,6 +388,21 @@ const SelectList = /*#__PURE__*/React.forwardRef(({
386
388
  }), ...(flipEnabled ? [flip({
387
389
  fallbackStrategy: "initialPlacement"
388
390
  })] : /* istanbul ignore next: covered by Playwright tests for reliable positioning in a real browser */[])], [listWidth, flipEnabled]);
391
+
392
+ // set the placement of the list based on the floating placement
393
+ const setPlacement = useCallback(() => {
394
+ if (isOpen) {
395
+ const floatingPlacement = listWrapperRef.current?.getAttribute("data-floating-placement");
396
+ setActualPlacement(floatingPlacement);
397
+ }
398
+ }, [isOpen]);
399
+ useEffect(() => {
400
+ setPlacement();
401
+ window.addEventListener("resize", setPlacement);
402
+ return () => {
403
+ window.removeEventListener("resize", setPlacement);
404
+ };
405
+ }, [setPlacement]);
389
406
  const loader = isLoading ? /*#__PURE__*/React.createElement(StyledSelectLoaderContainer, {
390
407
  key: "loader"
391
408
  }, /*#__PURE__*/React.createElement(Loader, null)) : undefined;
@@ -424,9 +441,11 @@ const SelectList = /*#__PURE__*/React.forwardRef(({
424
441
  disableBackgroundUI: true,
425
442
  animationFrame: true
426
443
  }, /*#__PURE__*/React.createElement(StyledSelectListContainer, _extends({
444
+ ref: listWrapperRef,
427
445
  "data-element": "select-list-wrapper",
428
446
  "data-role": "select-list-wrapper",
429
- isLoading: isLoading
447
+ isLoading: isLoading,
448
+ placement: actualPlacement
430
449
  }, listProps), /*#__PURE__*/React.createElement(StyledScrollableContainer, {
431
450
  ref: listContainerRef,
432
451
  maxHeight: listMaxHeight,
@@ -1,4 +1,3 @@
1
- import { SelectListProps } from ".";
2
1
  interface StyledSelectListProps {
3
2
  listHeight?: number;
4
3
  }
@@ -10,7 +9,11 @@ interface StyledSelectListTableHeaderProps {
10
9
  }
11
10
  declare const StyledSelectListTableHeader: import("styled-components").StyledComponent<"thead", any, StyledSelectListTableHeaderProps, never>;
12
11
  declare const StyledSelectListTableBody: import("styled-components").StyledComponent<"tbody", any, StyledSelectListProps, never>;
13
- declare const StyledSelectListContainer: import("styled-components").StyledComponent<"div", any, Pick<SelectListProps, "isLoading">, never>;
12
+ interface StyledSelectListContainerProps {
13
+ isLoading?: boolean;
14
+ placement?: string;
15
+ }
16
+ declare const StyledSelectListContainer: import("styled-components").StyledComponent<"div", any, StyledSelectListContainerProps, never>;
14
17
  declare const StyledScrollableContainer: import("styled-components").StyledComponent<"div", any, {
15
18
  maxHeight: number;
16
19
  hasActionButton: boolean;
@@ -94,7 +94,9 @@ const StyledSelectListTableBody = styled.tbody`
94
94
  `;
95
95
  const StyledSelectListContainer = styled.div`
96
96
  background-color: white;
97
- box-shadow: var(--boxShadow100);
97
+ box-shadow: ${({
98
+ placement
99
+ }) => placement?.includes("top") ? "0 -5px 5px 0 #00141e33, 0 -10px 10px 0 #00141e1a" : "var(--boxShadow100)"};
98
100
  animation: fadeIn 250ms ease-out;
99
101
  position: absolute;
100
102
  z-index: ${({
@@ -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(value);
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);
@@ -58,9 +58,11 @@ const SelectList = /*#__PURE__*/_react.default.forwardRef(({
58
58
  }, listContainerRef) => {
59
59
  const [currentOptionsListIndex, setCurrentOptionsListIndex] = (0, _react.useState)(-1);
60
60
  const [scrollbarWidth, setScrollbarWidth] = (0, _react.useState)(0);
61
+ const [actualPlacement, setActualPlacement] = (0, _react.useState)(listPlacement);
61
62
  const lastFilter = (0, _react.useRef)("");
62
63
  const listRef = (0, _react.useRef)(null);
63
64
  const tableRef = (0, _react.useRef)(null);
65
+ const listWrapperRef = (0, _react.useRef)(null);
64
66
  const listActionButtonRef = (0, _react.useRef)(null);
65
67
  const {
66
68
  blockScroll,
@@ -395,6 +397,21 @@ const SelectList = /*#__PURE__*/_react.default.forwardRef(({
395
397
  }), ...(flipEnabled ? [(0, _dom.flip)({
396
398
  fallbackStrategy: "initialPlacement"
397
399
  })] : /* istanbul ignore next: covered by Playwright tests for reliable positioning in a real browser */[])], [listWidth, flipEnabled]);
400
+
401
+ // set the placement of the list based on the floating placement
402
+ const setPlacement = (0, _react.useCallback)(() => {
403
+ if (isOpen) {
404
+ const floatingPlacement = listWrapperRef.current?.getAttribute("data-floating-placement");
405
+ setActualPlacement(floatingPlacement);
406
+ }
407
+ }, [isOpen]);
408
+ (0, _react.useEffect)(() => {
409
+ setPlacement();
410
+ window.addEventListener("resize", setPlacement);
411
+ return () => {
412
+ window.removeEventListener("resize", setPlacement);
413
+ };
414
+ }, [setPlacement]);
398
415
  const loader = isLoading ? /*#__PURE__*/_react.default.createElement(_selectList.StyledSelectLoaderContainer, {
399
416
  key: "loader"
400
417
  }, /*#__PURE__*/_react.default.createElement(_loader.default, null)) : undefined;
@@ -433,9 +450,11 @@ const SelectList = /*#__PURE__*/_react.default.forwardRef(({
433
450
  disableBackgroundUI: true,
434
451
  animationFrame: true
435
452
  }, /*#__PURE__*/_react.default.createElement(_selectList.StyledSelectListContainer, _extends({
453
+ ref: listWrapperRef,
436
454
  "data-element": "select-list-wrapper",
437
455
  "data-role": "select-list-wrapper",
438
- isLoading: isLoading
456
+ isLoading: isLoading,
457
+ placement: actualPlacement
439
458
  }, listProps), /*#__PURE__*/_react.default.createElement(_selectList.StyledScrollableContainer, {
440
459
  ref: listContainerRef,
441
460
  maxHeight: listMaxHeight,
@@ -1,4 +1,3 @@
1
- import { SelectListProps } from ".";
2
1
  interface StyledSelectListProps {
3
2
  listHeight?: number;
4
3
  }
@@ -10,7 +9,11 @@ interface StyledSelectListTableHeaderProps {
10
9
  }
11
10
  declare const StyledSelectListTableHeader: import("styled-components").StyledComponent<"thead", any, StyledSelectListTableHeaderProps, never>;
12
11
  declare const StyledSelectListTableBody: import("styled-components").StyledComponent<"tbody", any, StyledSelectListProps, never>;
13
- declare const StyledSelectListContainer: import("styled-components").StyledComponent<"div", any, Pick<SelectListProps, "isLoading">, never>;
12
+ interface StyledSelectListContainerProps {
13
+ isLoading?: boolean;
14
+ placement?: string;
15
+ }
16
+ declare const StyledSelectListContainer: import("styled-components").StyledComponent<"div", any, StyledSelectListContainerProps, never>;
14
17
  declare const StyledScrollableContainer: import("styled-components").StyledComponent<"div", any, {
15
18
  maxHeight: number;
16
19
  hasActionButton: boolean;
@@ -102,7 +102,9 @@ const StyledSelectListTableBody = exports.StyledSelectListTableBody = _styledCom
102
102
  `;
103
103
  const StyledSelectListContainer = exports.StyledSelectListContainer = _styledComponents.default.div`
104
104
  background-color: white;
105
- box-shadow: var(--boxShadow100);
105
+ box-shadow: ${({
106
+ placement
107
+ }) => placement?.includes("top") ? "0 -5px 5px 0 #00141e33, 0 -10px 10px 0 #00141e1a" : "var(--boxShadow100)"};
106
108
  animation: fadeIn 250ms ease-out;
107
109
  position: absolute;
108
110
  z-index: ${({
@@ -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(value);
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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "carbon-react",
3
- "version": "146.4.0",
3
+ "version": "146.4.2",
4
4
  "description": "A library of reusable React components for easily building user interfaces.",
5
5
  "files": [
6
6
  "lib",