@carbon/ibm-products 2.85.0 → 2.86.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/css/carbon.css +55 -2
- package/css/carbon.css.map +1 -1
- package/css/index-full-carbon.css +615 -410
- package/css/index-full-carbon.css.map +1 -1
- package/css/index-full-carbon.min.css +1 -1
- package/css/index-full-carbon.min.css.map +1 -1
- package/css/index-without-carbon-released-only.css +3225 -3081
- package/css/index-without-carbon-released-only.css.map +1 -1
- package/css/index-without-carbon-released-only.min.css +1 -1
- package/css/index-without-carbon-released-only.min.css.map +1 -1
- package/css/index-without-carbon.css +2958 -2806
- package/css/index-without-carbon.css.map +1 -1
- package/css/index-without-carbon.min.css +1 -1
- package/css/index-without-carbon.min.css.map +1 -1
- package/css/index.css +2202 -2011
- package/css/index.css.map +1 -1
- package/css/index.min.css +1 -1
- package/css/index.min.css.map +1 -1
- package/es/components/ActionSet/ActionSet.d.ts +6 -0
- package/es/components/ActionSet/ActionSet.js +20 -10
- package/es/components/Coachmark/next/Coachmark/ContentBody.js +1 -1
- package/es/components/DataSpreadsheet/utils/moveColumnIndicatorLine.js +2 -2
- package/es/components/EditInPlace/EditInPlace.d.ts +2 -3
- package/es/components/OptionsTile/OptionsTile.js +35 -12
- package/es/components/PageHeader/next/context.js +1 -1
- package/es/components/PageHeader/next/index.js +3 -3
- package/es/components/StringFormatter/StringFormatter.js +1 -1
- package/es/components/TagSet/TagSet.js +1 -1
- package/es/components/Tearsheet/next/StackContext.d.ts +1 -1
- package/es/components/Tearsheet/next/Tearsheet.d.ts +19 -5
- package/es/components/Tearsheet/next/Tearsheet.js +90 -31
- package/es/components/Tearsheet/next/TearsheetBody.js +2 -2
- package/es/components/Tearsheet/next/TearsheetFooter.d.ts +31 -0
- package/es/components/Tearsheet/next/TearsheetFooter.js +39 -0
- package/es/components/Tearsheet/next/TearsheetHeader.d.ts +1 -1
- package/es/components/Tearsheet/next/index.d.ts +2 -1
- package/es/components/index.d.ts +1 -1
- package/es/global/js/hooks/index.d.ts +1 -0
- package/es/global/js/utils/devtools.js +1 -1
- package/es/index.js +8 -8
- package/es/node_modules/@carbon/icons-react/es/generated/bucket-10.js +1184 -1110
- package/es/node_modules/@carbon/icons-react/es/generated/bucket-3.js +1337 -1334
- package/es/node_modules/@floating-ui/dom/dist/floating-ui.dom.js +2 -2
- package/lib/components/ActionSet/ActionSet.d.ts +6 -0
- package/lib/components/ActionSet/ActionSet.js +20 -10
- package/lib/components/Coachmark/next/Coachmark/ContentBody.js +0 -3
- package/lib/components/DataSpreadsheet/utils/moveColumnIndicatorLine.js +2 -2
- package/lib/components/EditInPlace/EditInPlace.d.ts +2 -3
- package/lib/components/OptionsTile/OptionsTile.js +35 -12
- package/lib/components/PageHeader/next/index.js +6 -6
- package/lib/components/TagSet/TagSet.js +0 -3
- package/lib/components/Tearsheet/next/StackContext.d.ts +1 -1
- package/lib/components/Tearsheet/next/Tearsheet.d.ts +19 -5
- package/lib/components/Tearsheet/next/Tearsheet.js +90 -31
- package/lib/components/Tearsheet/next/TearsheetBody.js +2 -2
- package/lib/components/Tearsheet/next/TearsheetFooter.d.ts +31 -0
- package/lib/components/Tearsheet/next/TearsheetFooter.js +43 -0
- package/lib/components/Tearsheet/next/TearsheetHeader.d.ts +1 -1
- package/lib/components/Tearsheet/next/index.d.ts +2 -1
- package/lib/components/index.d.ts +1 -1
- package/lib/global/js/hooks/index.d.ts +1 -0
- package/lib/index.js +50 -50
- package/lib/node_modules/@carbon/icons-react/es/generated/bucket-10.js +1204 -1130
- package/lib/node_modules/@carbon/icons-react/es/generated/bucket-3.js +1351 -1348
- package/package.json +14 -18
- package/scss/components/NotificationsPanel/_notifications-panel.scss +3 -0
- package/scss/components/OptionsTile/_options-tile.scss +28 -7
- package/scss/components/PageHeader/_page-header.scss +14 -4
- package/scss/components/SidePanel/_side-panel.scss +0 -2
- package/scss/components/Tearsheet/_index-with-carbon.scss +2 -1
- package/scss/components/Tearsheet/_index.scss +1 -0
- package/scss/components/Tearsheet/_tearsheet.scss +0 -2
- package/scss/components/Tearsheet/_tearsheet_next.scss +351 -229
- package/telemetry.yml +4 -1
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { offset as offset$1, flip as flip$1, shift as shift$1,
|
|
9
|
-
import { createCoords, rectToClientRect, floor,
|
|
8
|
+
import { offset as offset$1, flip as flip$1, shift as shift$1, computePosition as computePosition$1, arrow as arrow$1 } from '../../core/dist/floating-ui.core.js';
|
|
9
|
+
import { createCoords, rectToClientRect, floor, round, max, min } from '../../utils/dist/floating-ui.utils.js';
|
|
10
10
|
import { getOverflowAncestors, isElement, getDocumentElement, getWindow, getFrameElement, getComputedStyle, isHTMLElement, isWebKit, isTopLayer, getParentNode, isLastTraversableNode, isTableElement, isContainingBlock, getContainingBlock, getNodeName, isOverflowElement, getNodeScroll } from '../../utils/dist/floating-ui.utils.dom.js';
|
|
11
11
|
|
|
12
12
|
function getCssDimensions(element) {
|
|
@@ -27,6 +27,12 @@ export interface ActionSetProps {
|
|
|
27
27
|
* An optional class or classes to be added to the outermost element.
|
|
28
28
|
*/
|
|
29
29
|
className?: string;
|
|
30
|
+
/**
|
|
31
|
+
* When true, prevents automatic stacking of buttons even when size would
|
|
32
|
+
* normally trigger stacking (e.g., 'sm' size or 'md' with 3+ actions).
|
|
33
|
+
* Buttons will remain in a horizontal layout.
|
|
34
|
+
*/
|
|
35
|
+
disableStacking?: boolean;
|
|
30
36
|
/**
|
|
31
37
|
* The size of the action set. Different button arrangements are used at
|
|
32
38
|
* different sizes, to make best use of the available space.
|
|
@@ -46,7 +46,7 @@ ActionSetButton.displayName = 'ActionSetButton';
|
|
|
46
46
|
ActionSetButton.propTypes = {
|
|
47
47
|
/**@ts-ignore*/
|
|
48
48
|
...react.Button.PropTypes,
|
|
49
|
-
kind: index.default.oneOf(['ghost', 'danger--ghost', 'secondary', 'danger', 'primary']),
|
|
49
|
+
kind: index.default.oneOf(['ghost', 'danger--ghost', 'tertiary', 'secondary', 'danger', 'primary']),
|
|
50
50
|
label: index.default.string,
|
|
51
51
|
loading: index.default.bool
|
|
52
52
|
};
|
|
@@ -68,6 +68,7 @@ const validateActionSetProps = _ref2 => {
|
|
|
68
68
|
const countActions = kind => actions.filter(action => (action.kind || defaultKind) === kind).length;
|
|
69
69
|
const primaryActions = countActions('primary');
|
|
70
70
|
const secondaryActions = countActions('secondary');
|
|
71
|
+
const tertiaryActions = countActions('tertiary');
|
|
71
72
|
const dangerActions = countActions('danger');
|
|
72
73
|
const ghostActions = countActions('ghost') + countActions('danger--ghost');
|
|
73
74
|
if (stacking && actions.length > 3) {
|
|
@@ -85,8 +86,8 @@ const validateActionSetProps = _ref2 => {
|
|
|
85
86
|
if (stacking && actions.length > 1 && ghostActions > 0) {
|
|
86
87
|
problems.push(`you cannot have a 'ghost' button in conjunction with other action types in this size of ${componentName}`);
|
|
87
88
|
}
|
|
88
|
-
if (actions.length > primaryActions + secondaryActions + dangerActions + ghostActions) {
|
|
89
|
-
problems.push(`you can only have 'primary', 'danger', 'secondary', 'ghost' and 'danger--ghost' buttons in a ${componentName}`);
|
|
89
|
+
if (actions.length > primaryActions + secondaryActions + tertiaryActions + dangerActions + ghostActions) {
|
|
90
|
+
problems.push(`you can only have 'primary', 'danger', 'secondary', 'tertiary', 'ghost' and 'danger--ghost' buttons in a ${componentName}`);
|
|
90
91
|
}
|
|
91
92
|
return problems.length > 0 ? pconsole.default.error(`Invalid prop \`actions\` supplied to \`${componentName}\`: ${problems.join(', and ')}.`) : null;
|
|
92
93
|
}
|
|
@@ -109,6 +110,7 @@ const ActionSet = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
109
110
|
actions,
|
|
110
111
|
buttonSize,
|
|
111
112
|
className,
|
|
113
|
+
disableStacking = false,
|
|
112
114
|
size = defaults.size,
|
|
113
115
|
...rest
|
|
114
116
|
} = props;
|
|
@@ -119,16 +121,18 @@ const ActionSet = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
119
121
|
const buttons = actions && actions.slice?.(0) || [];
|
|
120
122
|
|
|
121
123
|
// We stack the buttons in a sm set, or if there are three or more in a md set.
|
|
122
|
-
|
|
124
|
+
// Unless disableStacking is true, in which case we never stack.
|
|
125
|
+
const stacking = disableStacking ? false : willStack(size, buttons.length);
|
|
123
126
|
|
|
124
|
-
// Order of button kinds: ghost first, then danger--ghost, then
|
|
125
|
-
// then danger, and finally primary
|
|
127
|
+
// Order of button kinds: ghost first, then danger--ghost, then tertiary,
|
|
128
|
+
// then most other types, then danger, and finally primary
|
|
126
129
|
const buttonOrder = kind => ({
|
|
127
130
|
ghost: 1,
|
|
128
131
|
'danger--ghost': 2,
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
+
tertiary: 3,
|
|
133
|
+
danger: 5,
|
|
134
|
+
primary: 6
|
|
135
|
+
})[kind] ?? 4;
|
|
132
136
|
|
|
133
137
|
// order the actions with ghost/ghost-danger buttons first and primary/danger buttons last
|
|
134
138
|
// (or the opposite way if we're stacking)
|
|
@@ -185,7 +189,7 @@ ActionSet.propTypes = {
|
|
|
185
189
|
actions: propsHelper.allPropTypes([index.default.arrayOf(index.default.shape({
|
|
186
190
|
/**@ts-ignore*/
|
|
187
191
|
...react.Button.propTypes,
|
|
188
|
-
kind: index.default.oneOf(['ghost', 'danger--ghost', 'secondary', 'danger', 'primary']),
|
|
192
|
+
kind: index.default.oneOf(['ghost', 'danger--ghost', 'tertiary', 'secondary', 'danger', 'primary']),
|
|
189
193
|
label: index.default.string,
|
|
190
194
|
loading: index.default.bool,
|
|
191
195
|
// we duplicate this Button prop to improve the DocGen here
|
|
@@ -204,6 +208,12 @@ ActionSet.propTypes = {
|
|
|
204
208
|
* An optional class or classes to be added to the outermost element.
|
|
205
209
|
*/
|
|
206
210
|
className: index.default.string,
|
|
211
|
+
/**
|
|
212
|
+
* When true, prevents automatic stacking of buttons even when size would
|
|
213
|
+
* normally trigger stacking (e.g., 'sm' size or 'md' with 3+ actions).
|
|
214
|
+
* Buttons will remain in a horizontal layout.
|
|
215
|
+
*/
|
|
216
|
+
disableStacking: index.default.bool,
|
|
207
217
|
/**
|
|
208
218
|
* The size of the action set. Different button arrangements are used at
|
|
209
219
|
* different sizes, to make best use of the available space.
|
|
@@ -7,8 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
'use strict';
|
|
9
9
|
|
|
10
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
11
|
-
|
|
12
10
|
var React = require('react');
|
|
13
11
|
var index = require('../../../../_virtual/index.js');
|
|
14
12
|
var cx = require('classnames');
|
|
@@ -39,4 +37,3 @@ ContentBody.propTypes = {
|
|
|
39
37
|
};
|
|
40
38
|
|
|
41
39
|
exports.ContentBody = ContentBody;
|
|
42
|
-
exports.default = ContentBody;
|
|
@@ -40,7 +40,7 @@ const moveColumnIndicatorLine = _ref => {
|
|
|
40
40
|
|
|
41
41
|
// Is near left side of viewport
|
|
42
42
|
if (clientX < leftEdgeThreshold) {
|
|
43
|
-
window.scrollBy(-
|
|
43
|
+
window.scrollBy(-scrollSpeed, 0);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
// Is near right side of viewport
|
|
@@ -50,7 +50,7 @@ const moveColumnIndicatorLine = _ref => {
|
|
|
50
50
|
|
|
51
51
|
// Is near left edge of table
|
|
52
52
|
if (clientX > left && clientX < left + leftEdgeThreshold) {
|
|
53
|
-
listContainer.scrollBy(-
|
|
53
|
+
listContainer.scrollBy(-scrollSpeed, 0);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
// Is near right edge of table
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
import React, { PropsWithChildren } from 'react';
|
|
8
|
-
import PropTypes from 'prop-types';
|
|
9
8
|
type Size = 'sm' | 'md' | 'lg';
|
|
10
9
|
type AlignPropType = 'top' | 'top-left' | 'top-right' | 'bottom' | 'bottom-left' | 'bottom-right' | 'left' | 'right';
|
|
11
10
|
type Shape = {
|
|
@@ -69,11 +68,11 @@ export interface EditInplaceProps extends PropsWithChildren {
|
|
|
69
68
|
/**
|
|
70
69
|
* determines if the input is in readOnly mode
|
|
71
70
|
*/
|
|
72
|
-
readOnly
|
|
71
|
+
readOnly?: boolean;
|
|
73
72
|
/**
|
|
74
73
|
* label for the edit off button that displays when in read only mode
|
|
75
74
|
*/
|
|
76
|
-
readOnlyLabel?:
|
|
75
|
+
readOnlyLabel?: string;
|
|
77
76
|
/**
|
|
78
77
|
* text for the toggletip that displays when in read only mode
|
|
79
78
|
*/
|
|
@@ -142,7 +142,19 @@ const OptionsTile = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
142
142
|
setOpen(false);
|
|
143
143
|
}
|
|
144
144
|
};
|
|
145
|
-
const
|
|
145
|
+
const handleSummaryClick = evt => {
|
|
146
|
+
// Check if the click originated from the toggle button
|
|
147
|
+
const target = evt.target;
|
|
148
|
+
const toggleContainer = target.closest(`.${blockClass}__toggle-container`);
|
|
149
|
+
|
|
150
|
+
// If click is on toggle button, don't handle expand/collapse
|
|
151
|
+
if (toggleContainer) {
|
|
152
|
+
evt.preventDefault();
|
|
153
|
+
evt.stopPropagation();
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Prevent default details toggle behavior
|
|
146
158
|
evt.preventDefault();
|
|
147
159
|
if (open) {
|
|
148
160
|
collapse();
|
|
@@ -195,8 +207,25 @@ const OptionsTile = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
195
207
|
[`${blockClass}--closing`]: closing
|
|
196
208
|
}),
|
|
197
209
|
ref: ref
|
|
198
|
-
}, devtools.getDevtoolsProps(componentName)),
|
|
199
|
-
className: `${blockClass}
|
|
210
|
+
}, devtools.getDevtoolsProps(componentName)), isExpandable ? /*#__PURE__*/React.createElement("details", {
|
|
211
|
+
className: `${blockClass}__details`,
|
|
212
|
+
open: open,
|
|
213
|
+
ref: detailsRef
|
|
214
|
+
}, /*#__PURE__*/React.createElement("summary", {
|
|
215
|
+
className: cx(`${blockClass}__header`, {
|
|
216
|
+
[`${blockClass}__header--has-toggle`]: enabled !== undefined
|
|
217
|
+
}),
|
|
218
|
+
onClick: handleSummaryClick,
|
|
219
|
+
"data-testid": "options-tile-header"
|
|
220
|
+
}, enabled !== undefined &&
|
|
221
|
+
/*#__PURE__*/
|
|
222
|
+
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
|
223
|
+
React.createElement("div", {
|
|
224
|
+
className: `${blockClass}__toggle-container`,
|
|
225
|
+
"data-testid": "options-tile-toggle-container",
|
|
226
|
+
onMouseDown: evt => {
|
|
227
|
+
evt.preventDefault();
|
|
228
|
+
}
|
|
200
229
|
}, /*#__PURE__*/React.createElement(react.Toggle, {
|
|
201
230
|
id: `${titleId}-toggle`,
|
|
202
231
|
className: `${blockClass}__toggle`,
|
|
@@ -206,14 +235,7 @@ const OptionsTile = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
206
235
|
onToggle: onToggle,
|
|
207
236
|
size: "sm",
|
|
208
237
|
disabled: isLocked
|
|
209
|
-
})),
|
|
210
|
-
className: `${blockClass}__details`,
|
|
211
|
-
open: open,
|
|
212
|
-
ref: detailsRef
|
|
213
|
-
}, /*#__PURE__*/React.createElement("summary", {
|
|
214
|
-
className: `${blockClass}__header`,
|
|
215
|
-
onClick: toggle
|
|
216
|
-
}, /*#__PURE__*/React.createElement(icons.ChevronDown, {
|
|
238
|
+
})), /*#__PURE__*/React.createElement(icons.ChevronDown, {
|
|
217
239
|
size: 16,
|
|
218
240
|
className: cx(`${blockClass}__chevron`, {
|
|
219
241
|
[`${blockClass}__chevron--open`]: open,
|
|
@@ -221,7 +243,8 @@ const OptionsTile = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
221
243
|
})
|
|
222
244
|
}), renderTitle()), /*#__PURE__*/React.createElement("div", {
|
|
223
245
|
className: `${blockClass}__content`,
|
|
224
|
-
ref: contentRef
|
|
246
|
+
ref: contentRef,
|
|
247
|
+
"data-testid": "options-tile-content"
|
|
225
248
|
}, /*#__PURE__*/React.createElement(react.Layer, null, isLocked && /*#__PURE__*/React.createElement("p", {
|
|
226
249
|
className: `${blockClass}__locked-text`
|
|
227
250
|
}, _Locked || (_Locked = /*#__PURE__*/React.createElement(icons.Locked, {
|
|
@@ -9,15 +9,15 @@
|
|
|
9
9
|
|
|
10
10
|
var PageHeader = require('./PageHeader.js');
|
|
11
11
|
var PageHeaderBreadcrumbBar = require('./PageHeaderBreadcrumbBar.js');
|
|
12
|
+
var PageHeaderBreadcrumbOverflow = require('./PageHeaderBreadcrumbOverflow.js');
|
|
12
13
|
var PageHeaderContent = require('./PageHeaderContent.js');
|
|
13
14
|
var PageHeaderContentPageActions = require('./PageHeaderContentPageActions.js');
|
|
14
15
|
var PageHeaderContentText = require('./PageHeaderContentText.js');
|
|
15
|
-
var PageHeaderTabBar = require('./PageHeaderTabBar.js');
|
|
16
16
|
var PageHeaderHeroImage = require('./PageHeaderHeroImage.js');
|
|
17
17
|
var PageHeaderScrollButton = require('./PageHeaderScrollButton.js');
|
|
18
|
-
var
|
|
19
|
-
var PageHeaderBreadcrumbOverflow = require('./PageHeaderBreadcrumbOverflow.js');
|
|
18
|
+
var PageHeaderTabBar = require('./PageHeaderTabBar.js');
|
|
20
19
|
var PageHeaderTagOverflow = require('./PageHeaderTagOverflow.js');
|
|
20
|
+
var PageHeaderTitleBreadcrumb = require('./PageHeaderTitleBreadcrumb.js');
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
|
|
@@ -34,12 +34,12 @@ exports.TabBar = PageHeader.TabBar;
|
|
|
34
34
|
exports.TagOverflow = PageHeader.TagOverflow;
|
|
35
35
|
exports.TitleBreadcrumb = PageHeader.TitleBreadcrumb;
|
|
36
36
|
exports.PageHeaderBreadcrumbBar = PageHeaderBreadcrumbBar.PageHeaderBreadcrumbBar;
|
|
37
|
+
exports.PageHeaderBreadcrumbOverflow = PageHeaderBreadcrumbOverflow.PageHeaderBreadcrumbOverflow;
|
|
37
38
|
exports.PageHeaderContent = PageHeaderContent.PageHeaderContent;
|
|
38
39
|
exports.PageHeaderContentPageActions = PageHeaderContentPageActions.PageHeaderContentPageActions;
|
|
39
40
|
exports.PageHeaderContentText = PageHeaderContentText.PageHeaderContentText;
|
|
40
|
-
exports.PageHeaderTabBar = PageHeaderTabBar.PageHeaderTabBar;
|
|
41
41
|
exports.PageHeaderHeroImage = PageHeaderHeroImage.PageHeaderHeroImage;
|
|
42
42
|
exports.PageHeaderScrollButton = PageHeaderScrollButton.PageHeaderScrollButton;
|
|
43
|
-
exports.
|
|
44
|
-
exports.PageHeaderBreadcrumbOverflow = PageHeaderBreadcrumbOverflow.PageHeaderBreadcrumbOverflow;
|
|
43
|
+
exports.PageHeaderTabBar = PageHeaderTabBar.PageHeaderTabBar;
|
|
45
44
|
exports.PageHeaderTagOverflow = PageHeaderTagOverflow.PageHeaderTagOverflow;
|
|
45
|
+
exports.PageHeaderTitleBreadcrumb = PageHeaderTitleBreadcrumb.PageHeaderTitleBreadcrumb;
|
|
@@ -7,8 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
'use strict';
|
|
9
9
|
|
|
10
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
11
|
-
|
|
12
10
|
var _rollupPluginBabelHelpers = require('../../_virtual/_rollupPluginBabelHelpers.js');
|
|
13
11
|
var React = require('react');
|
|
14
12
|
var index = require('../../_virtual/index.js');
|
|
@@ -357,4 +355,3 @@ TagSet.propTypes = {
|
|
|
357
355
|
TagSet.displayName = componentName;
|
|
358
356
|
|
|
359
357
|
exports.TagSet = TagSet;
|
|
360
|
-
exports.default = TagSet;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import React, { ReactNode } from 'react';
|
|
8
8
|
export interface StackContextType {
|
|
9
9
|
stack: string[];
|
|
10
|
-
notifyStack: (id: string, open: boolean, container: HTMLDivElement) => void;
|
|
10
|
+
notifyStack: (id: string, open: boolean, container: HTMLDivElement | null) => void;
|
|
11
11
|
getScaleFactor: (id: string) => number | null;
|
|
12
12
|
getBlockSizeChange: (id: string) => string | null;
|
|
13
13
|
getDepth: (id: string) => number | null;
|
|
@@ -11,6 +11,7 @@ import { TearsheetHeaderProps, TearsheetNavigationBarProps, TearsheetScrollButto
|
|
|
11
11
|
import { TearsheetHeaderContentProps } from './TearsheetHeaderContent';
|
|
12
12
|
import { InfluencerProps, MainContentProps, SummaryContentProps, TearsheetBodyProps } from './TearsheetBody';
|
|
13
13
|
import { TearsheetHeaderActionItemProps, TearsheetHeaderActionsProps } from './TearsheetHeaderActions';
|
|
14
|
+
import { TearsheetFooterProps } from './TearsheetFooter';
|
|
14
15
|
/**
|
|
15
16
|
* ----------
|
|
16
17
|
* Tearsheet
|
|
@@ -75,6 +76,19 @@ export interface TearsheetProps extends ComposedModalProps {
|
|
|
75
76
|
* The DOM element that the tearsheet should be rendered within. Defaults to document.body.
|
|
76
77
|
*/
|
|
77
78
|
portalTarget?: HTMLElement;
|
|
79
|
+
/**
|
|
80
|
+
* Disable the portal behavior and render the tearsheet in the existing DOM structure.
|
|
81
|
+
* This is useful for testing, when you need to inherit React context from parent components,
|
|
82
|
+
* or when you don't need the z-index isolation that portals provide.
|
|
83
|
+
* @default false
|
|
84
|
+
*/
|
|
85
|
+
disablePortal?: boolean;
|
|
86
|
+
/**
|
|
87
|
+
* If true, the tearsheet will remain mounted in the DOM when closed, using CSS to hide it.
|
|
88
|
+
* By default (false), the tearsheet unmounts from the DOM after the exit animation completes.
|
|
89
|
+
* Set to true if you need to preserve component state or avoid remounting overhead.
|
|
90
|
+
*/
|
|
91
|
+
keepMounted?: boolean;
|
|
78
92
|
}
|
|
79
93
|
export type TearsheetComponentType = React.ForwardRefExoticComponent<TearsheetProps & React.RefAttributes<HTMLDivElement>> & {
|
|
80
94
|
Header: FC<TearsheetHeaderProps>;
|
|
@@ -87,10 +101,10 @@ export type TearsheetComponentType = React.ForwardRefExoticComponent<TearsheetPr
|
|
|
87
101
|
MainContent: FC<MainContentProps>;
|
|
88
102
|
SummaryContent: FC<SummaryContentProps>;
|
|
89
103
|
Body: FC<TearsheetBodyProps>;
|
|
90
|
-
Footer: FC<
|
|
104
|
+
Footer: FC<TearsheetFooterProps>;
|
|
91
105
|
};
|
|
106
|
+
/**
|
|
107
|
+
* Wrapper component that handles presence logic and conditionally renders TearsheetInternal.
|
|
108
|
+
* This ensures that all component state and effects are only initialized when the tearsheet is present.
|
|
109
|
+
*/
|
|
92
110
|
export declare const Tearsheet: TearsheetComponentType;
|
|
93
|
-
export interface FooterProps {
|
|
94
|
-
children: ReactNode;
|
|
95
|
-
className?: string;
|
|
96
|
-
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
var _rollupPluginBabelHelpers = require('../../../_virtual/_rollupPluginBabelHelpers.js');
|
|
11
11
|
var React = require('react');
|
|
12
|
+
var ReactDOM = require('react-dom');
|
|
12
13
|
var cx = require('classnames');
|
|
13
14
|
var react = require('@carbon/react');
|
|
14
15
|
var context = require('./context.js');
|
|
@@ -16,11 +17,13 @@ var TearsheetHeader = require('./TearsheetHeader.js');
|
|
|
16
17
|
var TearsheetHeaderContent = require('./TearsheetHeaderContent.js');
|
|
17
18
|
var TearsheetBody = require('./TearsheetBody.js');
|
|
18
19
|
var TearsheetHeaderActions = require('./TearsheetHeaderActions.js');
|
|
20
|
+
var TearsheetFooter = require('./TearsheetFooter.js');
|
|
19
21
|
var layout = require('@carbon/layout');
|
|
20
|
-
var usePortalTarget = require('../../../global/js/hooks/usePortalTarget.js');
|
|
21
22
|
var StackContext = require('./StackContext.js');
|
|
22
23
|
var useMatchMedia = require('../../../global/js/hooks/useMatchMedia.js');
|
|
23
24
|
var useId = require('../../../global/js/utils/useId.js');
|
|
25
|
+
var usePresence = require('../usePresence.js');
|
|
26
|
+
var useMergedRefs = require('../../../global/js/hooks/useMergedRefs.js');
|
|
24
27
|
var useIsomorphicEffect = require('../../../global/js/hooks/useIsomorphicEffect.js');
|
|
25
28
|
|
|
26
29
|
/**
|
|
@@ -29,7 +32,11 @@ var useIsomorphicEffect = require('../../../global/js/hooks/useIsomorphicEffect.
|
|
|
29
32
|
* ----------
|
|
30
33
|
*/
|
|
31
34
|
|
|
32
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Internal component that handles the actual tearsheet rendering.
|
|
37
|
+
* This component is always "present" when mounted - the wrapper handles presence logic.
|
|
38
|
+
*/
|
|
39
|
+
const TearsheetInternal = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
33
40
|
let {
|
|
34
41
|
children,
|
|
35
42
|
variant = 'wide',
|
|
@@ -42,14 +49,18 @@ const Tearsheet = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
42
49
|
selectorPrimaryFocus,
|
|
43
50
|
open = false,
|
|
44
51
|
portalTarget,
|
|
52
|
+
disablePortal = false,
|
|
45
53
|
verticalGap,
|
|
46
54
|
containerClassName,
|
|
55
|
+
keepMounted = false,
|
|
56
|
+
isExiting = false,
|
|
57
|
+
presenceRef,
|
|
47
58
|
...rest
|
|
48
59
|
} = _ref;
|
|
49
60
|
const carbonPrefix = react.usePrefix();
|
|
50
|
-
const localRef = React.useRef(
|
|
61
|
+
const localRef = React.useRef(null);
|
|
51
62
|
const bodyRef = React.useRef(null);
|
|
52
|
-
const
|
|
63
|
+
const mergedRefs = useMergedRefs.useMergedRefs([ref, localRef, presenceRef]);
|
|
53
64
|
const smMediaQuery = `(max-width: ${layout.breakpoints.md.width})`;
|
|
54
65
|
const isSm = useMatchMedia.useMatchMedia(smMediaQuery) || variant === 'narrow';
|
|
55
66
|
const [hasCloseIcon, setHasCloseIcon] = React.useState(true);
|
|
@@ -59,7 +70,7 @@ const Tearsheet = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
59
70
|
const header = arr.find(child => child.type === TearsheetHeader.default);
|
|
60
71
|
const influencer = arr.find(child => child.type === TearsheetBody.Influencer);
|
|
61
72
|
const body = arr.find(child => child.type === TearsheetBody.default);
|
|
62
|
-
const footer = arr.find(child => child.type ===
|
|
73
|
+
const footer = arr.find(child => child.type === TearsheetFooter.default);
|
|
63
74
|
const uniqueId = React.useRef(useId.useId());
|
|
64
75
|
const {
|
|
65
76
|
notifyStack,
|
|
@@ -69,10 +80,17 @@ const Tearsheet = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
69
80
|
getBlockSizeChange
|
|
70
81
|
} = StackContext.useStackContext();
|
|
71
82
|
const [depth, setDepth] = React.useState(0);
|
|
72
|
-
const
|
|
83
|
+
const [mountNode, setMountNode] = React.useState(null);
|
|
84
|
+
|
|
85
|
+
// Set portal mount node using useIsomorphicEffect to avoid SSR issues and double rendering
|
|
86
|
+
useIsomorphicEffect.useIsomorphicEffect(() => {
|
|
87
|
+
if (!disablePortal) {
|
|
88
|
+
setMountNode(portalTarget || document.body);
|
|
89
|
+
}
|
|
90
|
+
}, [portalTarget, disablePortal]);
|
|
73
91
|
useIsomorphicEffect.useIsomorphicEffect(() => {
|
|
74
|
-
const AILabelWidth =
|
|
75
|
-
const headerActionMarginRight = AILabelWidth + 24 + (isSm ? 8 : 0); // 24 is to
|
|
92
|
+
const AILabelWidth = localRef.current?.querySelector(`.${carbonPrefix}--ai-label`)?.clientWidth ?? 0;
|
|
93
|
+
const headerActionMarginRight = AILabelWidth + 24 + (isSm ? 8 : 0); // 24 is to compensate for close button
|
|
76
94
|
document.documentElement.style.setProperty('--tearsheet-header-action-offset', `${headerActionMarginRight}px`);
|
|
77
95
|
if (influencerWidth) {
|
|
78
96
|
document.documentElement.style.setProperty('--tearsheet-influencer-width', `${influencerWidth}`);
|
|
@@ -87,25 +105,30 @@ const Tearsheet = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
87
105
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
88
106
|
}, [isSm, rest.decorator, influencerWidth, summaryContentWidth, verticalGap]);
|
|
89
107
|
useIsomorphicEffect.useIsomorphicEffect(() => {
|
|
90
|
-
|
|
91
|
-
|
|
108
|
+
const id = uniqueId.current;
|
|
109
|
+
if (localRef.current && open) {
|
|
110
|
+
notifyStack?.(id, true, localRef.current);
|
|
92
111
|
}
|
|
93
112
|
|
|
113
|
+
// Cleanup when component unmounts
|
|
114
|
+
return () => {
|
|
115
|
+
notifyStack?.(id, false, null);
|
|
116
|
+
};
|
|
94
117
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
95
|
-
}, [open]);
|
|
118
|
+
}, [localRef.current, open]);
|
|
96
119
|
React.useEffect(() => {
|
|
97
|
-
if (stack?.length > 0) {
|
|
120
|
+
if (stack?.length > 0 && localRef.current) {
|
|
98
121
|
const stackDepth = getDepth?.(uniqueId.current),
|
|
99
122
|
blockSizeChange = getBlockSizeChange?.(uniqueId.current),
|
|
100
123
|
scaleFactor = getScaleFactor?.(uniqueId.current);
|
|
101
124
|
setDepth(stackDepth);
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
125
|
+
localRef.current.style.setProperty('--stack-depth', stackDepth + '');
|
|
126
|
+
localRef.current.style.setProperty('--block-size-change', blockSizeChange);
|
|
127
|
+
localRef.current.style.setProperty('--scale-factor', scaleFactor + '');
|
|
105
128
|
}
|
|
106
129
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
107
130
|
}, [stack]);
|
|
108
|
-
|
|
131
|
+
const content = /*#__PURE__*/React.createElement(context.TearsheetContext.Provider, {
|
|
109
132
|
value: {
|
|
110
133
|
hasCloseIcon,
|
|
111
134
|
setHasCloseIcon,
|
|
@@ -128,29 +151,65 @@ const Tearsheet = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
128
151
|
[`${context.blockClass}--stack-activated`]: stack.length > 1,
|
|
129
152
|
[`${context.blockClass}--has-ai-label`]: !!rest.decorator && rest.decorator['type']?.displayName === 'AILabel',
|
|
130
153
|
[`${context.blockClass}--has-decorator`]: !!rest.decorator && rest.decorator['type']?.displayName !== 'AILabel',
|
|
131
|
-
[`${context.blockClass}--has-close`]: hasCloseIcon
|
|
154
|
+
[`${context.blockClass}--has-close`]: hasCloseIcon,
|
|
155
|
+
['is-visible']: keepMounted ? open : true,
|
|
156
|
+
// When keepMounted, use open prop; otherwise always visible
|
|
157
|
+
[`${context.blockClass}--keep-mounted`]: keepMounted
|
|
132
158
|
}),
|
|
133
159
|
containerClassName: cx(`${context.blockClass}__container`, containerClassName),
|
|
134
160
|
onClose,
|
|
135
|
-
open,
|
|
161
|
+
open: keepMounted ? open : true,
|
|
162
|
+
// When keepMounted, use actual open; otherwise always open
|
|
136
163
|
selectorPrimaryFocus,
|
|
137
|
-
ref:
|
|
164
|
+
ref: mergedRefs,
|
|
138
165
|
selectorsFloatingMenus: [`.${carbonPrefix}--overflow-menu-options`, `.${carbonPrefix}--tooltip`, '.flatpickr-calendar', `.${context.blockClass}__container`, `.${carbonPrefix}--menu`, ...selectorsFloatingMenus],
|
|
139
166
|
isFullWidth: true,
|
|
140
|
-
size: variant === 'narrow' ? 'sm' : ''
|
|
167
|
+
size: variant === 'narrow' ? 'sm' : '',
|
|
168
|
+
"data-tearsheet-exiting": isExiting ? true : undefined
|
|
141
169
|
}), header, /*#__PURE__*/React.createElement(react.ModalBody, {
|
|
142
|
-
className: `${context.blockClass}__body-layout`,
|
|
170
|
+
className: cx(`${context.blockClass}__body-layout`, {
|
|
171
|
+
[`${context.blockClass}__body-layout--has-influencer`]: influencer && !isSm
|
|
172
|
+
}),
|
|
143
173
|
ref: bodyRef
|
|
144
|
-
}, influencer, body, footer))))
|
|
174
|
+
}, influencer, body, footer))));
|
|
175
|
+
|
|
176
|
+
// If portal is disabled, return content directly
|
|
177
|
+
if (disablePortal) {
|
|
178
|
+
return content;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Return portal if mountNode is set, otherwise return content directly (SSR-safe)
|
|
182
|
+
return mountNode ? /*#__PURE__*/ReactDOM.createPortal(content, mountNode) : content;
|
|
145
183
|
});
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Wrapper component that handles presence logic and conditionally renders TearsheetInternal.
|
|
187
|
+
* This ensures that all component state and effects are only initialized when the tearsheet is present.
|
|
188
|
+
*/
|
|
189
|
+
const Tearsheet = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
190
|
+
const {
|
|
191
|
+
open = false,
|
|
192
|
+
keepMounted = false
|
|
193
|
+
} = props;
|
|
194
|
+
const presenceRef = React.useRef(null);
|
|
195
|
+
|
|
196
|
+
// Use presence hook for enter/exit animations (unless keepMounted is true)
|
|
197
|
+
const {
|
|
198
|
+
isPresent,
|
|
199
|
+
isExiting
|
|
200
|
+
} = usePresence.usePresence(presenceRef, keepMounted ? true : open);
|
|
201
|
+
|
|
202
|
+
// Don't render if not present (after exit animation completes) - unless keepMounted is true
|
|
203
|
+
if (!keepMounted && !isPresent) {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// When present, render the internal component with all props
|
|
208
|
+
return /*#__PURE__*/React.createElement(TearsheetInternal, _rollupPluginBabelHelpers.extends({}, props, {
|
|
209
|
+
ref: ref,
|
|
210
|
+
presenceRef: presenceRef,
|
|
211
|
+
isExiting: isExiting
|
|
212
|
+
}));
|
|
154
213
|
});
|
|
155
214
|
Tearsheet.Header = TearsheetHeader.default;
|
|
156
215
|
Tearsheet.HeaderContent = TearsheetHeaderContent.default;
|
|
@@ -158,7 +217,7 @@ Tearsheet.Body = TearsheetBody.default;
|
|
|
158
217
|
Tearsheet.Influencer = TearsheetBody.Influencer;
|
|
159
218
|
Tearsheet.MainContent = TearsheetBody.MainContent;
|
|
160
219
|
Tearsheet.SummaryContent = TearsheetBody.SummaryContent;
|
|
161
|
-
Tearsheet.Footer =
|
|
220
|
+
Tearsheet.Footer = TearsheetFooter.default;
|
|
162
221
|
Tearsheet.NavigationBar = TearsheetHeader.TearsheetNavigationBar;
|
|
163
222
|
Tearsheet.ScrollButton = TearsheetHeader.TearsheetScrollButton;
|
|
164
223
|
Tearsheet.HeaderActions = TearsheetHeaderActions.TearsheetHeaderActions;
|
|
@@ -106,7 +106,7 @@ const SummaryContent = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
|
|
|
106
106
|
size: "sm",
|
|
107
107
|
open: summaryPanelOpen,
|
|
108
108
|
onRequestClose: onSummaryPanelClose,
|
|
109
|
-
className: className
|
|
109
|
+
className: cx(`${context.blockClass}__side-panel`, className)
|
|
110
110
|
}, children);
|
|
111
111
|
});
|
|
112
112
|
const Influencer = /*#__PURE__*/React.forwardRef((_ref4, ref) => {
|
|
@@ -130,7 +130,7 @@ const Influencer = /*#__PURE__*/React.forwardRef((_ref4, ref) => {
|
|
|
130
130
|
open: influencerPanelOpen,
|
|
131
131
|
onRequestClose: onInfluencerPanelClose,
|
|
132
132
|
placement: "left",
|
|
133
|
-
className: className
|
|
133
|
+
className: cx(`${context.blockClass}__side-panel`, className)
|
|
134
134
|
}, children);
|
|
135
135
|
});
|
|
136
136
|
|
|
@@ -0,0 +1,31 @@
|
|
|
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 React, { ReactNode } from 'react';
|
|
8
|
+
import { ButtonProps } from '@carbon/react';
|
|
9
|
+
import { ActionSetProps } from '../../ActionSet';
|
|
10
|
+
export interface TearsheetFooterProps {
|
|
11
|
+
/**
|
|
12
|
+
* Optional children to render in the footer. If provided, children are rendered first,
|
|
13
|
+
* followed by the ActionSet (if actions are provided).
|
|
14
|
+
*/
|
|
15
|
+
children?: ReactNode;
|
|
16
|
+
/**
|
|
17
|
+
* Optional class name to add to the footer element.
|
|
18
|
+
*/
|
|
19
|
+
className?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Optional array of action button configurations. If provided, an ActionSet will be
|
|
22
|
+
* rendered after any children. Each action follows the ActionSet button specification.
|
|
23
|
+
*/
|
|
24
|
+
actions?: ButtonProps<React.ElementType>[];
|
|
25
|
+
/**
|
|
26
|
+
* Optional size for the ActionSet buttons. Defaults to the ActionSet's default size.
|
|
27
|
+
*/
|
|
28
|
+
buttonSize?: ActionSetProps['buttonSize'];
|
|
29
|
+
}
|
|
30
|
+
declare const TearsheetFooter: React.ForwardRefExoticComponent<TearsheetFooterProps & React.RefAttributes<HTMLDivElement>>;
|
|
31
|
+
export default TearsheetFooter;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright IBM Corp. 2020, 2026
|
|
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 cx = require('classnames');
|
|
14
|
+
var ActionSet = require('../../ActionSet/ActionSet.js');
|
|
15
|
+
var context = require('./context.js');
|
|
16
|
+
|
|
17
|
+
const TearsheetFooter = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
18
|
+
let {
|
|
19
|
+
children,
|
|
20
|
+
className,
|
|
21
|
+
actions,
|
|
22
|
+
buttonSize
|
|
23
|
+
} = _ref;
|
|
24
|
+
const {
|
|
25
|
+
variant
|
|
26
|
+
} = React.useContext(context.TearsheetContext);
|
|
27
|
+
const actionCount = actions?.length || 0;
|
|
28
|
+
return /*#__PURE__*/React.createElement("footer", {
|
|
29
|
+
className: cx(`${context.blockClass}__footer`, className, {
|
|
30
|
+
[`${context.blockClass}__footer--three-actions`]: actionCount == 3,
|
|
31
|
+
[`${context.blockClass}__footer--many-actions`]: actionCount > 3
|
|
32
|
+
}),
|
|
33
|
+
ref: ref
|
|
34
|
+
}, children, actions && actions.length > 0 && /*#__PURE__*/React.createElement(ActionSet.ActionSet, {
|
|
35
|
+
actions: actions,
|
|
36
|
+
buttonSize: buttonSize,
|
|
37
|
+
disableStacking: true,
|
|
38
|
+
size: variant == 'wide' ? '2xl' : 'lg'
|
|
39
|
+
}));
|
|
40
|
+
});
|
|
41
|
+
TearsheetFooter.displayName = 'TearsheetFooter';
|
|
42
|
+
|
|
43
|
+
exports.default = TearsheetFooter;
|