@carbon/react 1.84.0-rc.0 → 1.84.0

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 (39) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +883 -883
  2. package/es/components/ComposedModal/ComposedModal.js +19 -2
  3. package/es/components/Modal/Modal.js +19 -2
  4. package/es/components/MultiSelect/FilterableMultiSelect.js +21 -0
  5. package/es/components/OverflowMenu/OverflowMenu.js +4 -5
  6. package/es/components/PageHeader/PageHeader.d.ts +10 -9
  7. package/es/components/PageHeader/PageHeader.js +92 -32
  8. package/es/components/PageHeader/index.d.ts +2 -2
  9. package/es/components/PageHeader/index.js +1 -1
  10. package/es/components/Search/Search.js +0 -1
  11. package/es/components/Slider/Slider.js +6 -0
  12. package/es/components/TextArea/TextArea.js +4 -4
  13. package/es/components/TileGroup/TileGroup.d.ts +4 -4
  14. package/es/components/TileGroup/TileGroup.js +45 -53
  15. package/es/components/TileGroup/index.d.ts +3 -3
  16. package/es/components/UIShell/HeaderMenuItem.js +2 -1
  17. package/es/index.js +1 -1
  18. package/es/internal/useOverflowItems.d.ts +29 -0
  19. package/es/internal/useOverflowItems.js +122 -0
  20. package/lib/components/ComposedModal/ComposedModal.js +19 -2
  21. package/lib/components/Modal/Modal.js +19 -2
  22. package/lib/components/MultiSelect/FilterableMultiSelect.js +21 -0
  23. package/lib/components/OverflowMenu/OverflowMenu.js +4 -5
  24. package/lib/components/PageHeader/PageHeader.d.ts +10 -9
  25. package/lib/components/PageHeader/PageHeader.js +90 -32
  26. package/lib/components/PageHeader/index.d.ts +2 -2
  27. package/lib/components/PageHeader/index.js +0 -2
  28. package/lib/components/Search/Search.js +0 -1
  29. package/lib/components/Slider/Slider.js +6 -0
  30. package/lib/components/TextArea/TextArea.js +4 -4
  31. package/lib/components/TileGroup/TileGroup.d.ts +4 -4
  32. package/lib/components/TileGroup/TileGroup.js +44 -52
  33. package/lib/components/TileGroup/index.d.ts +3 -3
  34. package/lib/components/UIShell/HeaderMenuItem.js +2 -1
  35. package/lib/index.js +1 -1
  36. package/lib/internal/useOverflowItems.d.ts +29 -0
  37. package/lib/internal/useOverflowItems.js +126 -0
  38. package/package.json +9 -9
  39. package/telemetry.yml +2 -0
@@ -21,35 +21,37 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
21
21
  var PropTypes__default = /*#__PURE__*/_interopDefaultLegacy(PropTypes);
22
22
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
23
23
 
24
- const TileGroup = props => {
25
- const {
26
- children,
27
- className,
28
- defaultSelected,
29
- disabled,
30
- legend,
31
- name,
32
- onChange = noopFn.noopFn,
33
- valueSelected,
34
- required
35
- } = props;
24
+ const TileGroup = ({
25
+ children,
26
+ className,
27
+ defaultSelected,
28
+ disabled,
29
+ legend,
30
+ name,
31
+ onChange = noopFn.noopFn,
32
+ valueSelected,
33
+ required
34
+ }) => {
36
35
  const prefix = usePrefix.usePrefix();
37
36
  const [selected, setSelected] = React.useState(valueSelected ?? defaultSelected);
38
- const [prevValueSelected, setPrevValueSelected] = React.useState(valueSelected);
37
+ React.useEffect(() => {
38
+ if (typeof valueSelected !== 'undefined' && valueSelected !== selected) {
39
+ setSelected(valueSelected);
40
+ }
41
+ }, [valueSelected, selected]);
42
+ const handleChange = (value, name, evt) => {
43
+ if (value !== selected) {
44
+ setSelected(value);
45
+ onChange(value, name ?? '', evt);
46
+ }
47
+ };
48
+ const getRadioTilesWithWrappers = elements => {
49
+ const traverseAndModifyChildren = elements => {
50
+ return React.Children.map(elements, child => {
51
+ if (! /*#__PURE__*/React.isValidElement(child)) return child;
39
52
 
40
- /**
41
- * prop + state alignment - getDerivedStateFromProps
42
- * only update if selected prop changes
43
- */
44
- if (valueSelected !== prevValueSelected) {
45
- setSelected(valueSelected);
46
- setPrevValueSelected(valueSelected);
47
- }
48
- const getRadioTilesWithWrappers = children => {
49
- const traverseAndModifyChildren = children => {
50
- return React__default["default"].Children.map(children, child => {
51
- // If RadioTile found, return it with necessary props
52
- if (child?.type === RadioTile["default"]) {
53
+ // If a `RadioTile` is found, return it with necessary props,
54
+ if (/*#__PURE__*/React.isValidElement(child) && child.type === RadioTile["default"]) {
53
55
  const {
54
56
  value,
55
57
  ...otherProps
@@ -62,38 +64,29 @@ const TileGroup = props => {
62
64
  onChange: handleChange,
63
65
  checked: value === selected
64
66
  }));
65
- } else if (child?.props?.children) {
66
- // If the child is not RadioTile and has children, recheck the children
67
- return /*#__PURE__*/React__default["default"].cloneElement(child, {
68
- ...child.props,
69
- children: traverseAndModifyChildren(child.props.children)
70
- });
71
- } else {
72
- // If the child is neither a RadioTile nor has children, return it as is
73
- return child;
74
67
  }
68
+
69
+ // If the child is not RadioTile and has children, recheck the children
70
+ const children = child.props.children;
71
+ const hasChildren = React.Children.count(children) > 0;
72
+ if (hasChildren) {
73
+ return /*#__PURE__*/React.cloneElement(child, undefined, traverseAndModifyChildren(children));
74
+ }
75
+
76
+ // If the child is neither a RadioTile nor has children, return it as is
77
+ return child;
75
78
  });
76
79
  };
77
- return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, traverseAndModifyChildren(children));
78
- };
79
- const handleChange = (newSelection, value, evt) => {
80
- if (newSelection !== selected) {
81
- setSelected(newSelection);
82
- onChange(newSelection, name, evt);
83
- }
84
- };
85
- const renderLegend = legend => {
86
- if (legend) {
87
- return /*#__PURE__*/React__default["default"].createElement("legend", {
88
- className: `${prefix}--label`
89
- }, legend);
90
- }
80
+ return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, traverseAndModifyChildren(elements));
91
81
  };
92
82
  return /*#__PURE__*/React__default["default"].createElement("fieldset", {
93
83
  className: className ?? `${prefix}--tile-group`,
94
84
  disabled: disabled
95
- }, renderLegend(legend), /*#__PURE__*/React__default["default"].createElement("div", null, getRadioTilesWithWrappers(children)));
85
+ }, legend && /*#__PURE__*/React__default["default"].createElement("legend", {
86
+ className: `${prefix}--label`
87
+ }, legend), /*#__PURE__*/React__default["default"].createElement("div", null, getRadioTilesWithWrappers(children)));
96
88
  };
89
+ TileGroup.displayName = 'TileGroup';
97
90
  TileGroup.propTypes = {
98
91
  /**
99
92
  * Provide a collection of <RadioTile> components to render in the group
@@ -133,6 +126,5 @@ TileGroup.propTypes = {
133
126
  */
134
127
  valueSelected: PropTypes__default["default"].oneOfType([PropTypes__default["default"].string, PropTypes__default["default"].number])
135
128
  };
136
- TileGroup.displayName = 'TileGroup';
137
129
 
138
- exports["default"] = TileGroup;
130
+ exports.TileGroup = TileGroup;
@@ -1,9 +1,9 @@
1
1
  /**
2
- * Copyright IBM Corp. 2016, 2023
2
+ * Copyright IBM Corp. 2016, 2025
3
3
  *
4
4
  * This source code is licensed under the Apache-2.0 license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
- import TileGroup, { type TileGroupProps } from './TileGroup';
7
+ import { TileGroup } from './TileGroup';
8
8
  export default TileGroup;
9
- export { TileGroup, type TileGroupProps };
9
+ export * from './TileGroup';
@@ -34,6 +34,7 @@ const HeaderMenuItem = /*#__PURE__*/React.forwardRef(function HeaderMenuItem({
34
34
  ...rest
35
35
  }, ref) {
36
36
  const prefix = usePrefix.usePrefix();
37
+ const resolvedTabIndex = tabIndex ?? 0;
37
38
  if (isCurrentPage) {
38
39
  isActive = isCurrentPage;
39
40
  }
@@ -52,7 +53,7 @@ const HeaderMenuItem = /*#__PURE__*/React.forwardRef(function HeaderMenuItem({
52
53
  "aria-current": hasCurrentClass ? true : ariaCurrent,
53
54
  className: linkClassName,
54
55
  ref: ref,
55
- tabIndex: tabIndex
56
+ tabIndex: resolvedTabIndex
56
57
  }), /*#__PURE__*/React__default["default"].createElement("span", {
57
58
  className: `${prefix}--text-truncate--end`
58
59
  }, children)));
package/lib/index.js CHANGED
@@ -424,7 +424,7 @@ exports.SelectableTile = Tile.SelectableTile;
424
424
  exports.Tile = Tile.Tile;
425
425
  exports.TileAboveTheFoldContent = Tile.TileAboveTheFoldContent;
426
426
  exports.TileBelowTheFoldContent = Tile.TileBelowTheFoldContent;
427
- exports.TileGroup = TileGroup["default"];
427
+ exports.TileGroup = TileGroup.TileGroup;
428
428
  exports.TimePicker = TimePicker["default"];
429
429
  exports.TimePickerSelect = TimePickerSelect["default"];
430
430
  exports.Toggle = Toggle.Toggle;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Copyright IBM Corp. 2025, 2025
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import { ReactNode, RefObject } from 'react';
8
+ type Item = {
9
+ id: string;
10
+ };
11
+ /**
12
+ * Manages overflow items in a container by automatically hiding items that don't fit.
13
+ * @param items - Array of items to manage for overflow, each must have an `id` property.
14
+ * @param containerRef - React ref to the container element that holds the items.
15
+ * @param offsetRef - Optional ref to an offset element (like a "more" button) whose width is reserved when calculating available space.
16
+ * @param maxItems - Optional maximum number of visible items. If undefined, only container space constrains visibility.
17
+ * @param onChange - Optional callback called when hidden items change. Receives array of currently hidden items.
18
+ * @returns Object with `visibleItems` (items to display), `hiddenItems` (items that don't fit), and `itemRefHandler` (function to attach refs to items for width measurement).
19
+ */
20
+ declare const useOverflowItems: <T extends Item>(items: T[] | ReactNode, containerRef: RefObject<HTMLDivElement>, offsetRef?: RefObject<HTMLDivElement>, maxItems?: number, onChange?: (hiddenItems: T[]) => void) => {
21
+ visibleItems: T[];
22
+ hiddenItems: T[];
23
+ itemRefHandler: () => void;
24
+ } | {
25
+ visibleItems: T[];
26
+ itemRefHandler: (id: string, node: HTMLDivElement | null) => () => void;
27
+ hiddenItems: T[];
28
+ };
29
+ export default useOverflowItems;
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Copyright IBM Corp. 2016, 2023
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ Object.defineProperty(exports, '__esModule', { value: true });
11
+
12
+ var React = require('react');
13
+ var useResizeObserver = require('./useResizeObserver.js');
14
+ var usePreviousValue = require('./usePreviousValue.js');
15
+
16
+ /**
17
+ * Manages overflow items in a container by automatically hiding items that don't fit.
18
+ * @param items - Array of items to manage for overflow, each must have an `id` property.
19
+ * @param containerRef - React ref to the container element that holds the items.
20
+ * @param offsetRef - Optional ref to an offset element (like a "more" button) whose width is reserved when calculating available space.
21
+ * @param maxItems - Optional maximum number of visible items. If undefined, only container space constrains visibility.
22
+ * @param onChange - Optional callback called when hidden items change. Receives array of currently hidden items.
23
+ * @returns Object with `visibleItems` (items to display), `hiddenItems` (items that don't fit), and `itemRefHandler` (function to attach refs to items for width measurement).
24
+ */
25
+
26
+ const useOverflowItems = (items, containerRef, offsetRef, maxItems, onChange) => {
27
+ const itemsRef = React.useRef(null);
28
+ const [maxWidth, setMaxWidth] = React.useState(0);
29
+ if (!items || !Array.isArray(items)) {
30
+ return {
31
+ visibleItems: [],
32
+ hiddenItems: [],
33
+ itemRefHandler: () => {}
34
+ };
35
+ }
36
+ const handleResize = () => {
37
+ if (containerRef.current) {
38
+ const offset = offsetRef?.current?.offsetWidth || 0;
39
+ const newMax = containerRef.current.offsetWidth - offset;
40
+ setMaxWidth(newMax);
41
+ }
42
+ };
43
+ useResizeObserver.useResizeObserver({
44
+ ref: containerRef,
45
+ onResize: handleResize
46
+ });
47
+ const getMap = () => {
48
+ if (!itemsRef.current) {
49
+ itemsRef.current = new Map();
50
+ }
51
+ return itemsRef.current;
52
+ };
53
+ const itemRefHandler = (id, node) => {
54
+ const map = getMap();
55
+ if (node) {
56
+ const style = getComputedStyle?.(node);
57
+ const totalWidth = node.offsetWidth + parseInt(style.marginLeft) + parseInt(style.marginRight);
58
+ map.set(id, totalWidth);
59
+ }
60
+ return () => {
61
+ map.delete(id);
62
+ };
63
+ };
64
+ const getVisibleItems = () => {
65
+ if (!items || Array.isArray(items) === false) {
66
+ return [];
67
+ }
68
+ if (!containerRef) {
69
+ return items;
70
+ }
71
+ const map = getMap();
72
+ let maxReached = false;
73
+ let accumulatedWidth = 0;
74
+ const visibleItems = items.slice(0, maxItems).reduce((prev, cur) => {
75
+ if (maxReached) {
76
+ return prev;
77
+ }
78
+ const itemWidth = map.get(cur.id) || 0;
79
+ const willFit = accumulatedWidth + itemWidth <= maxWidth;
80
+ if (willFit) {
81
+ accumulatedWidth += itemWidth;
82
+ prev.push(cur);
83
+ } else {
84
+ maxReached = true;
85
+ }
86
+ return prev;
87
+ }, []);
88
+ return visibleItems;
89
+ };
90
+
91
+ // Memoize visible items calculation to avoid recalculating on every render
92
+ const visibleItems = React.useMemo(() => {
93
+ if (!Array.isArray(items)) {
94
+ return [];
95
+ }
96
+ return getVisibleItems();
97
+ }, [items, maxWidth, maxItems]);
98
+
99
+ // Memoize hidden items calculation
100
+ const hiddenItems = React.useMemo(() => {
101
+ if (!Array.isArray(items)) {
102
+ return [];
103
+ }
104
+ return items.slice(visibleItems.length);
105
+ }, [items, visibleItems]);
106
+
107
+ // Use previous value to compare and only call onChange when needed
108
+ const previousHiddenItems = usePreviousValue.usePreviousValue(hiddenItems);
109
+
110
+ // Only call onChange if hidden items actually changed
111
+ React.useEffect(() => {
112
+ if (previousHiddenItems && onChange) {
113
+ const hasChanged = hiddenItems.length !== previousHiddenItems.length || hiddenItems.some((item, index) => item !== previousHiddenItems[index]);
114
+ if (hasChanged) {
115
+ onChange(hiddenItems);
116
+ }
117
+ }
118
+ }, [hiddenItems, previousHiddenItems, onChange]);
119
+ return {
120
+ visibleItems,
121
+ itemRefHandler,
122
+ hiddenItems
123
+ };
124
+ };
125
+
126
+ exports["default"] = useOverflowItems;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@carbon/react",
3
3
  "description": "React components for the Carbon Design System",
4
- "version": "1.84.0-rc.0",
4
+ "version": "1.84.0",
5
5
  "license": "Apache-2.0",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/index.d.ts",
@@ -52,11 +52,11 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "@babel/runtime": "^7.27.3",
55
- "@carbon/feature-flags": "^0.27.0-rc.0",
56
- "@carbon/icons-react": "^11.61.0-rc.0",
57
- "@carbon/layout": "^11.35.0-rc.0",
58
- "@carbon/styles": "^1.83.0-rc.0",
59
- "@carbon/utilities": "^0.7.0-rc.0",
55
+ "@carbon/feature-flags": "^0.27.0",
56
+ "@carbon/icons-react": "^11.61.0",
57
+ "@carbon/layout": "^11.35.0",
58
+ "@carbon/styles": "^1.83.0",
59
+ "@carbon/utilities": "^0.7.0",
60
60
  "@floating-ui/react": "^0.27.4",
61
61
  "@ibm/telemetry-js": "^1.5.0",
62
62
  "classnames": "2.5.1",
@@ -80,7 +80,7 @@
80
80
  "@babel/preset-react": "^7.27.1",
81
81
  "@babel/preset-typescript": "^7.27.1",
82
82
  "@carbon/test-utils": "^10.36.0",
83
- "@carbon/themes": "^11.54.0-rc.0",
83
+ "@carbon/themes": "^11.54.0",
84
84
  "@figma/code-connect": "^1.3.2",
85
85
  "@rollup/plugin-babel": "^6.0.0",
86
86
  "@rollup/plugin-commonjs": "^28.0.0",
@@ -103,7 +103,7 @@
103
103
  "autoprefixer": "^10.4.0",
104
104
  "babel-loader": "^9.0.0",
105
105
  "babel-plugin-dev-expression": "^0.2.3",
106
- "babel-preset-carbon": "^0.7.0-rc.0",
106
+ "babel-preset-carbon": "^0.7.0",
107
107
  "browserify-zlib": "^0.2.0",
108
108
  "browserslist-config-carbon": "^11.2.0",
109
109
  "clipboardy": "^2.1.0",
@@ -148,5 +148,5 @@
148
148
  "**/*.scss",
149
149
  "**/*.css"
150
150
  ],
151
- "gitHead": "fcae2645f1b5a1a01b5629926df471ec1945d1e6"
151
+ "gitHead": "f6debacbfe06fa5c31f70809e15762dc30096d70"
152
152
  }
package/telemetry.yml CHANGED
@@ -474,6 +474,8 @@ collect:
474
474
  # PageHeaderContentPageActions
475
475
  - actions
476
476
  - menuButtonLabel
477
+ # PageHeaderTabBar
478
+ - tags
477
479
  # PageSelector
478
480
  - currentPage
479
481
  - totalPages