@carbon/react 1.80.0 → 1.80.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/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +916 -916
- package/es/components/ComposedModal/ComposedModal.js +16 -8
- package/es/components/Modal/Modal.js +17 -5
- package/lib/components/ComposedModal/ComposedModal.js +14 -6
- package/lib/components/Modal/Modal.js +15 -3
- package/package.json +3 -3
|
@@ -17,14 +17,15 @@ import mergeRefs from '../../tools/mergeRefs.js';
|
|
|
17
17
|
import cx from 'classnames';
|
|
18
18
|
import toggleClass from '../../tools/toggleClass.js';
|
|
19
19
|
import requiredIfGivenPropIsTruthy from '../../prop-types/requiredIfGivenPropIsTruthy.js';
|
|
20
|
-
import wrapFocus, { elementOrParentIsFloatingMenu } from '../../internal/wrapFocus.js';
|
|
20
|
+
import wrapFocus, { wrapFocusWithoutSentinels, elementOrParentIsFloatingMenu } from '../../internal/wrapFocus.js';
|
|
21
21
|
import { usePrefix } from '../../internal/usePrefix.js';
|
|
22
|
-
import { Escape } from '../../internal/keyboard/keys.js';
|
|
22
|
+
import { Escape, Tab } from '../../internal/keyboard/keys.js';
|
|
23
23
|
import { match } from '../../internal/keyboard/match.js';
|
|
24
24
|
import { useFeatureFlag } from '../FeatureFlags/index.js';
|
|
25
25
|
import { composeEventHandlers } from '../../tools/events.js';
|
|
26
26
|
import deprecate from '../../prop-types/deprecate.js';
|
|
27
27
|
import { unstable__Dialog } from '../Dialog/index.js';
|
|
28
|
+
import { warning } from '../../internal/warning.js';
|
|
28
29
|
import { debounce } from '../../node_modules/es-toolkit/dist/compat/function/debounce.mjs.js';
|
|
29
30
|
|
|
30
31
|
const ModalBody = /*#__PURE__*/React__default.forwardRef(function ModalBody(_ref, ref) {
|
|
@@ -121,9 +122,9 @@ const ComposedModal = /*#__PURE__*/React__default.forwardRef(function ComposedMo
|
|
|
121
122
|
const startSentinel = useRef(null);
|
|
122
123
|
const endSentinel = useRef(null);
|
|
123
124
|
const onMouseDownTarget = useRef(null);
|
|
124
|
-
const enableDialogElement =
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
const enableDialogElement = useFeatureFlag('enable-dialog-element');
|
|
126
|
+
const focusTrapWithoutSentinels = useFeatureFlag('enable-experimental-focus-wrap-without-sentinels');
|
|
127
|
+
process.env.NODE_ENV !== "production" ? warning(!(focusTrapWithoutSentinels && enableDialogElement), '`<Modal>` detected both `focusTrapWithoutSentinels` and ' + '`enableDialogElement` feature flags are enabled. The native dialog ' + 'element handles focus, so `enableDialogElement` must be off for ' + '`focusTrapWithoutSentinels` to have any effect.') : void 0;
|
|
127
128
|
|
|
128
129
|
// Keep track of modal open/close state
|
|
129
130
|
// and propagate it to the document.body
|
|
@@ -149,6 +150,13 @@ const ComposedModal = /*#__PURE__*/React__default.forwardRef(function ComposedMo
|
|
|
149
150
|
if (match(event, Escape)) {
|
|
150
151
|
closeModal(event);
|
|
151
152
|
}
|
|
153
|
+
if (focusTrapWithoutSentinels && open && match(event, Tab) && innerModal.current) {
|
|
154
|
+
wrapFocusWithoutSentinels({
|
|
155
|
+
containerNode: innerModal.current,
|
|
156
|
+
currentActiveNode: event.target,
|
|
157
|
+
event: event
|
|
158
|
+
});
|
|
159
|
+
}
|
|
152
160
|
}
|
|
153
161
|
onKeyDown?.(event);
|
|
154
162
|
}
|
|
@@ -283,7 +291,7 @@ const ComposedModal = /*#__PURE__*/React__default.forwardRef(function ComposedMo
|
|
|
283
291
|
"aria-modal": "true",
|
|
284
292
|
"aria-label": ariaLabel ? ariaLabel : generatedAriaLabel,
|
|
285
293
|
"aria-labelledby": ariaLabelledBy
|
|
286
|
-
}, /*#__PURE__*/React__default.createElement("button", {
|
|
294
|
+
}, !focusTrapWithoutSentinels && /*#__PURE__*/React__default.createElement("button", {
|
|
287
295
|
type: "button",
|
|
288
296
|
ref: startSentinel,
|
|
289
297
|
className: `${prefix}--visually-hidden`
|
|
@@ -292,7 +300,7 @@ const ComposedModal = /*#__PURE__*/React__default.forwardRef(function ComposedMo
|
|
|
292
300
|
className: `${prefix}--modal-container-body`
|
|
293
301
|
}, slug ? normalizedDecorator : decorator ? /*#__PURE__*/React__default.createElement("div", {
|
|
294
302
|
className: `${prefix}--modal--inner__decorator`
|
|
295
|
-
}, normalizedDecorator) : '', childrenWithProps), /*#__PURE__*/React__default.createElement("button", {
|
|
303
|
+
}, normalizedDecorator) : '', childrenWithProps), !focusTrapWithoutSentinels && /*#__PURE__*/React__default.createElement("button", {
|
|
296
304
|
type: "button",
|
|
297
305
|
ref: endSentinel,
|
|
298
306
|
className: `${prefix}--visually-hidden`
|
|
@@ -302,7 +310,7 @@ const ComposedModal = /*#__PURE__*/React__default.forwardRef(function ComposedMo
|
|
|
302
310
|
role: "presentation",
|
|
303
311
|
ref: ref,
|
|
304
312
|
"aria-hidden": !open,
|
|
305
|
-
onBlur: !enableDialogElement ? handleBlur : () => {},
|
|
313
|
+
onBlur: !enableDialogElement && !focusTrapWithoutSentinels ? handleBlur : () => {},
|
|
306
314
|
onClick: composeEventHandlers([rest?.onClick, handleOnClick]),
|
|
307
315
|
onMouseDown: composeEventHandlers([rest?.onMouseDown, handleOnMouseDown]),
|
|
308
316
|
onKeyDown: handleKeyDown,
|
|
@@ -17,11 +17,11 @@ import ButtonSet from '../ButtonSet/ButtonSet.js';
|
|
|
17
17
|
import InlineLoading from '../InlineLoading/InlineLoading.js';
|
|
18
18
|
import { Layer } from '../Layer/index.js';
|
|
19
19
|
import requiredIfGivenPropIsTruthy from '../../prop-types/requiredIfGivenPropIsTruthy.js';
|
|
20
|
-
import wrapFocus, { elementOrParentIsFloatingMenu } from '../../internal/wrapFocus.js';
|
|
20
|
+
import wrapFocus, { wrapFocusWithoutSentinels, elementOrParentIsFloatingMenu } from '../../internal/wrapFocus.js';
|
|
21
21
|
import useIsomorphicEffect from '../../internal/useIsomorphicEffect.js';
|
|
22
22
|
import { useId } from '../../internal/useId.js';
|
|
23
23
|
import { usePrefix } from '../../internal/usePrefix.js';
|
|
24
|
-
import { Escape, Enter } from '../../internal/keyboard/keys.js';
|
|
24
|
+
import { Escape, Enter, Tab } from '../../internal/keyboard/keys.js';
|
|
25
25
|
import { match } from '../../internal/keyboard/match.js';
|
|
26
26
|
import { IconButton } from '../IconButton/index.js';
|
|
27
27
|
import { noopFn } from '../../internal/noopFn.js';
|
|
@@ -30,6 +30,7 @@ import { useFeatureFlag } from '../FeatureFlags/index.js';
|
|
|
30
30
|
import { composeEventHandlers } from '../../tools/events.js';
|
|
31
31
|
import deprecate from '../../prop-types/deprecate.js';
|
|
32
32
|
import { unstable__Dialog } from '../Dialog/index.js';
|
|
33
|
+
import { warning } from '../../internal/warning.js';
|
|
33
34
|
import { debounce } from '../../node_modules/es-toolkit/dist/compat/function/debounce.mjs.js';
|
|
34
35
|
import { Text } from '../Text/Text.js';
|
|
35
36
|
|
|
@@ -87,7 +88,9 @@ const Modal = /*#__PURE__*/React__default.forwardRef(function Modal(_ref, ref) {
|
|
|
87
88
|
[`${prefix}--btn--loading`]: loadingStatus !== 'inactive'
|
|
88
89
|
});
|
|
89
90
|
const loadingActive = loadingStatus !== 'inactive';
|
|
90
|
-
const
|
|
91
|
+
const focusTrapWithoutSentinels = useFeatureFlag('enable-experimental-focus-wrap-without-sentinels');
|
|
92
|
+
const enableDialogElement = useFeatureFlag('enable-dialog-element');
|
|
93
|
+
process.env.NODE_ENV !== "production" ? warning(!(focusTrapWithoutSentinels && enableDialogElement), '`<Modal>` detected both `focusTrapWithoutSentinels` and ' + '`enableDialogElement` feature flags are enabled. The native dialog ' + 'element handles focus, so `enableDialogElement` must be off for ' + '`focusTrapWithoutSentinels` to have any effect.') : void 0;
|
|
91
94
|
function isCloseButton(element) {
|
|
92
95
|
return !onSecondarySubmit && element === secondaryButton.current || element.classList.contains(modalCloseButtonClass);
|
|
93
96
|
}
|
|
@@ -100,6 +103,15 @@ const Modal = /*#__PURE__*/React__default.forwardRef(function Modal(_ref, ref) {
|
|
|
100
103
|
if (match(evt, Enter) && shouldSubmitOnEnter && !isCloseButton(evt.target)) {
|
|
101
104
|
onRequestSubmit(evt);
|
|
102
105
|
}
|
|
106
|
+
if (focusTrapWithoutSentinels && !enableDialogElement && match(evt, Tab) && innerModal.current) {
|
|
107
|
+
wrapFocusWithoutSentinels({
|
|
108
|
+
containerNode: innerModal.current,
|
|
109
|
+
currentActiveNode: evt.target,
|
|
110
|
+
// TODO: Delete type assertion following util rewrite.
|
|
111
|
+
// https://github.com/carbon-design-system/carbon/pull/18913
|
|
112
|
+
event: evt
|
|
113
|
+
});
|
|
114
|
+
}
|
|
103
115
|
}
|
|
104
116
|
}
|
|
105
117
|
function handleOnClick(evt) {
|
|
@@ -326,7 +338,7 @@ const Modal = /*#__PURE__*/React__default.forwardRef(function Modal(_ref, ref) {
|
|
|
326
338
|
iconDescription: loadingIconDescription,
|
|
327
339
|
className: `${prefix}--inline-loading--btn`,
|
|
328
340
|
onSuccess: onLoadingSuccess
|
|
329
|
-
})))) : /*#__PURE__*/React__default.createElement(React__default.Fragment, null, !enableDialogElement && /*#__PURE__*/React__default.createElement("span", {
|
|
341
|
+
})))) : /*#__PURE__*/React__default.createElement(React__default.Fragment, null, !enableDialogElement && !focusTrapWithoutSentinels && /*#__PURE__*/React__default.createElement("span", {
|
|
330
342
|
ref: startTrap,
|
|
331
343
|
tabIndex: 0,
|
|
332
344
|
role: "link",
|
|
@@ -385,7 +397,7 @@ const Modal = /*#__PURE__*/React__default.forwardRef(function Modal(_ref, ref) {
|
|
|
385
397
|
iconDescription: loadingIconDescription,
|
|
386
398
|
className: `${prefix}--inline-loading--btn`,
|
|
387
399
|
onSuccess: onLoadingSuccess
|
|
388
|
-
})))), !enableDialogElement && /*#__PURE__*/React__default.createElement("span", {
|
|
400
|
+
})))), !enableDialogElement && !focusTrapWithoutSentinels && /*#__PURE__*/React__default.createElement("span", {
|
|
389
401
|
ref: endTrap,
|
|
390
402
|
tabIndex: 0,
|
|
391
403
|
role: "link",
|
|
@@ -29,6 +29,7 @@ var index$1 = require('../FeatureFlags/index.js');
|
|
|
29
29
|
var events = require('../../tools/events.js');
|
|
30
30
|
var deprecate = require('../../prop-types/deprecate.js');
|
|
31
31
|
var index$2 = require('../Dialog/index.js');
|
|
32
|
+
var warning = require('../../internal/warning.js');
|
|
32
33
|
var debounce = require('../../node_modules/es-toolkit/dist/compat/function/debounce.mjs.js');
|
|
33
34
|
|
|
34
35
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
@@ -131,9 +132,9 @@ const ComposedModal = /*#__PURE__*/React__default["default"].forwardRef(function
|
|
|
131
132
|
const startSentinel = React.useRef(null);
|
|
132
133
|
const endSentinel = React.useRef(null);
|
|
133
134
|
const onMouseDownTarget = React.useRef(null);
|
|
134
|
-
const enableDialogElement =
|
|
135
|
-
|
|
136
|
-
|
|
135
|
+
const enableDialogElement = index$1.useFeatureFlag('enable-dialog-element');
|
|
136
|
+
const focusTrapWithoutSentinels = index$1.useFeatureFlag('enable-experimental-focus-wrap-without-sentinels');
|
|
137
|
+
process.env.NODE_ENV !== "production" ? warning.warning(!(focusTrapWithoutSentinels && enableDialogElement), '`<Modal>` detected both `focusTrapWithoutSentinels` and ' + '`enableDialogElement` feature flags are enabled. The native dialog ' + 'element handles focus, so `enableDialogElement` must be off for ' + '`focusTrapWithoutSentinels` to have any effect.') : void 0;
|
|
137
138
|
|
|
138
139
|
// Keep track of modal open/close state
|
|
139
140
|
// and propagate it to the document.body
|
|
@@ -159,6 +160,13 @@ const ComposedModal = /*#__PURE__*/React__default["default"].forwardRef(function
|
|
|
159
160
|
if (match.match(event, keys.Escape)) {
|
|
160
161
|
closeModal(event);
|
|
161
162
|
}
|
|
163
|
+
if (focusTrapWithoutSentinels && open && match.match(event, keys.Tab) && innerModal.current) {
|
|
164
|
+
wrapFocus.wrapFocusWithoutSentinels({
|
|
165
|
+
containerNode: innerModal.current,
|
|
166
|
+
currentActiveNode: event.target,
|
|
167
|
+
event: event
|
|
168
|
+
});
|
|
169
|
+
}
|
|
162
170
|
}
|
|
163
171
|
onKeyDown?.(event);
|
|
164
172
|
}
|
|
@@ -293,7 +301,7 @@ const ComposedModal = /*#__PURE__*/React__default["default"].forwardRef(function
|
|
|
293
301
|
"aria-modal": "true",
|
|
294
302
|
"aria-label": ariaLabel ? ariaLabel : generatedAriaLabel,
|
|
295
303
|
"aria-labelledby": ariaLabelledBy
|
|
296
|
-
}, /*#__PURE__*/React__default["default"].createElement("button", {
|
|
304
|
+
}, !focusTrapWithoutSentinels && /*#__PURE__*/React__default["default"].createElement("button", {
|
|
297
305
|
type: "button",
|
|
298
306
|
ref: startSentinel,
|
|
299
307
|
className: `${prefix}--visually-hidden`
|
|
@@ -302,7 +310,7 @@ const ComposedModal = /*#__PURE__*/React__default["default"].forwardRef(function
|
|
|
302
310
|
className: `${prefix}--modal-container-body`
|
|
303
311
|
}, slug ? normalizedDecorator : decorator ? /*#__PURE__*/React__default["default"].createElement("div", {
|
|
304
312
|
className: `${prefix}--modal--inner__decorator`
|
|
305
|
-
}, normalizedDecorator) : '', childrenWithProps), /*#__PURE__*/React__default["default"].createElement("button", {
|
|
313
|
+
}, normalizedDecorator) : '', childrenWithProps), !focusTrapWithoutSentinels && /*#__PURE__*/React__default["default"].createElement("button", {
|
|
306
314
|
type: "button",
|
|
307
315
|
ref: endSentinel,
|
|
308
316
|
className: `${prefix}--visually-hidden`
|
|
@@ -312,7 +320,7 @@ const ComposedModal = /*#__PURE__*/React__default["default"].forwardRef(function
|
|
|
312
320
|
role: "presentation",
|
|
313
321
|
ref: ref,
|
|
314
322
|
"aria-hidden": !open,
|
|
315
|
-
onBlur: !enableDialogElement ? handleBlur : () => {},
|
|
323
|
+
onBlur: !enableDialogElement && !focusTrapWithoutSentinels ? handleBlur : () => {},
|
|
316
324
|
onClick: events.composeEventHandlers([rest?.onClick, handleOnClick]),
|
|
317
325
|
onMouseDown: events.composeEventHandlers([rest?.onMouseDown, handleOnMouseDown]),
|
|
318
326
|
onKeyDown: handleKeyDown,
|
|
@@ -34,6 +34,7 @@ var index = require('../FeatureFlags/index.js');
|
|
|
34
34
|
var events = require('../../tools/events.js');
|
|
35
35
|
var deprecate = require('../../prop-types/deprecate.js');
|
|
36
36
|
var index$1 = require('../Dialog/index.js');
|
|
37
|
+
var warning = require('../../internal/warning.js');
|
|
37
38
|
var debounce = require('../../node_modules/es-toolkit/dist/compat/function/debounce.mjs.js');
|
|
38
39
|
var Text = require('../Text/Text.js');
|
|
39
40
|
|
|
@@ -97,7 +98,9 @@ const Modal = /*#__PURE__*/React__default["default"].forwardRef(function Modal(_
|
|
|
97
98
|
[`${prefix}--btn--loading`]: loadingStatus !== 'inactive'
|
|
98
99
|
});
|
|
99
100
|
const loadingActive = loadingStatus !== 'inactive';
|
|
100
|
-
const
|
|
101
|
+
const focusTrapWithoutSentinels = index.useFeatureFlag('enable-experimental-focus-wrap-without-sentinels');
|
|
102
|
+
const enableDialogElement = index.useFeatureFlag('enable-dialog-element');
|
|
103
|
+
process.env.NODE_ENV !== "production" ? warning.warning(!(focusTrapWithoutSentinels && enableDialogElement), '`<Modal>` detected both `focusTrapWithoutSentinels` and ' + '`enableDialogElement` feature flags are enabled. The native dialog ' + 'element handles focus, so `enableDialogElement` must be off for ' + '`focusTrapWithoutSentinels` to have any effect.') : void 0;
|
|
101
104
|
function isCloseButton(element) {
|
|
102
105
|
return !onSecondarySubmit && element === secondaryButton.current || element.classList.contains(modalCloseButtonClass);
|
|
103
106
|
}
|
|
@@ -110,6 +113,15 @@ const Modal = /*#__PURE__*/React__default["default"].forwardRef(function Modal(_
|
|
|
110
113
|
if (match.match(evt, keys.Enter) && shouldSubmitOnEnter && !isCloseButton(evt.target)) {
|
|
111
114
|
onRequestSubmit(evt);
|
|
112
115
|
}
|
|
116
|
+
if (focusTrapWithoutSentinels && !enableDialogElement && match.match(evt, keys.Tab) && innerModal.current) {
|
|
117
|
+
wrapFocus.wrapFocusWithoutSentinels({
|
|
118
|
+
containerNode: innerModal.current,
|
|
119
|
+
currentActiveNode: evt.target,
|
|
120
|
+
// TODO: Delete type assertion following util rewrite.
|
|
121
|
+
// https://github.com/carbon-design-system/carbon/pull/18913
|
|
122
|
+
event: evt
|
|
123
|
+
});
|
|
124
|
+
}
|
|
113
125
|
}
|
|
114
126
|
}
|
|
115
127
|
function handleOnClick(evt) {
|
|
@@ -336,7 +348,7 @@ const Modal = /*#__PURE__*/React__default["default"].forwardRef(function Modal(_
|
|
|
336
348
|
iconDescription: loadingIconDescription,
|
|
337
349
|
className: `${prefix}--inline-loading--btn`,
|
|
338
350
|
onSuccess: onLoadingSuccess
|
|
339
|
-
})))) : /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, !enableDialogElement && /*#__PURE__*/React__default["default"].createElement("span", {
|
|
351
|
+
})))) : /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, !enableDialogElement && !focusTrapWithoutSentinels && /*#__PURE__*/React__default["default"].createElement("span", {
|
|
340
352
|
ref: startTrap,
|
|
341
353
|
tabIndex: 0,
|
|
342
354
|
role: "link",
|
|
@@ -395,7 +407,7 @@ const Modal = /*#__PURE__*/React__default["default"].forwardRef(function Modal(_
|
|
|
395
407
|
iconDescription: loadingIconDescription,
|
|
396
408
|
className: `${prefix}--inline-loading--btn`,
|
|
397
409
|
onSuccess: onLoadingSuccess
|
|
398
|
-
})))), !enableDialogElement && /*#__PURE__*/React__default["default"].createElement("span", {
|
|
410
|
+
})))), !enableDialogElement && !focusTrapWithoutSentinels && /*#__PURE__*/React__default["default"].createElement("span", {
|
|
399
411
|
ref: endTrap,
|
|
400
412
|
tabIndex: 0,
|
|
401
413
|
role: "link",
|
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.80.
|
|
4
|
+
"version": "1.80.1",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "lib/index.d.ts",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"@carbon/feature-flags": "^0.26.0",
|
|
56
56
|
"@carbon/icons-react": "^11.58.0",
|
|
57
57
|
"@carbon/layout": "^11.32.0",
|
|
58
|
-
"@carbon/styles": "^1.79.
|
|
58
|
+
"@carbon/styles": "^1.79.1",
|
|
59
59
|
"@floating-ui/react": "^0.27.4",
|
|
60
60
|
"@ibm/telemetry-js": "^1.5.0",
|
|
61
61
|
"classnames": "2.5.1",
|
|
@@ -147,5 +147,5 @@
|
|
|
147
147
|
"**/*.scss",
|
|
148
148
|
"**/*.css"
|
|
149
149
|
],
|
|
150
|
-
"gitHead": "
|
|
150
|
+
"gitHead": "1fcbf602a0c0a9e33987b3b63e7a7a8b39af47d0"
|
|
151
151
|
}
|