@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.
- package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +883 -883
- package/es/components/ComposedModal/ComposedModal.js +19 -2
- package/es/components/Modal/Modal.js +19 -2
- package/es/components/MultiSelect/FilterableMultiSelect.js +21 -0
- package/es/components/OverflowMenu/OverflowMenu.js +4 -5
- package/es/components/PageHeader/PageHeader.d.ts +10 -9
- package/es/components/PageHeader/PageHeader.js +92 -32
- package/es/components/PageHeader/index.d.ts +2 -2
- package/es/components/PageHeader/index.js +1 -1
- package/es/components/Search/Search.js +0 -1
- package/es/components/Slider/Slider.js +6 -0
- package/es/components/TextArea/TextArea.js +4 -4
- package/es/components/TileGroup/TileGroup.d.ts +4 -4
- package/es/components/TileGroup/TileGroup.js +45 -53
- package/es/components/TileGroup/index.d.ts +3 -3
- package/es/components/UIShell/HeaderMenuItem.js +2 -1
- package/es/index.js +1 -1
- package/es/internal/useOverflowItems.d.ts +29 -0
- package/es/internal/useOverflowItems.js +122 -0
- package/lib/components/ComposedModal/ComposedModal.js +19 -2
- package/lib/components/Modal/Modal.js +19 -2
- package/lib/components/MultiSelect/FilterableMultiSelect.js +21 -0
- package/lib/components/OverflowMenu/OverflowMenu.js +4 -5
- package/lib/components/PageHeader/PageHeader.d.ts +10 -9
- package/lib/components/PageHeader/PageHeader.js +90 -32
- package/lib/components/PageHeader/index.d.ts +2 -2
- package/lib/components/PageHeader/index.js +0 -2
- package/lib/components/Search/Search.js +0 -1
- package/lib/components/Slider/Slider.js +6 -0
- package/lib/components/TextArea/TextArea.js +4 -4
- package/lib/components/TileGroup/TileGroup.d.ts +4 -4
- package/lib/components/TileGroup/TileGroup.js +44 -52
- package/lib/components/TileGroup/index.d.ts +3 -3
- package/lib/components/UIShell/HeaderMenuItem.js +2 -1
- package/lib/index.js +1 -1
- package/lib/internal/useOverflowItems.d.ts +29 -0
- package/lib/internal/useOverflowItems.js +126 -0
- package/package.json +9 -9
- 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 =
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
},
|
|
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
|
|
130
|
+
exports.TileGroup = TileGroup;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright IBM Corp. 2016,
|
|
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
|
|
7
|
+
import { TileGroup } from './TileGroup';
|
|
8
8
|
export default TileGroup;
|
|
9
|
-
export
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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": "
|
|
151
|
+
"gitHead": "f6debacbfe06fa5c31f70809e15762dc30096d70"
|
|
152
152
|
}
|