@carbon/react 1.98.0 → 1.99.0-rc.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 +1007 -1007
- package/es/components/Dropdown/Dropdown.js +4 -0
- package/es/components/Link/Link.js +1 -1
- package/es/components/MultiSelect/FilterableMultiSelect.js +1 -0
- package/es/components/MultiSelect/MultiSelect.js +1 -0
- package/es/components/NumberInput/NumberInput.d.ts +6 -2
- package/es/components/NumberInput/NumberInput.js +17 -5
- package/es/components/Popover/index.d.ts +1 -1
- package/es/components/Popover/index.js +27 -13
- package/es/components/Tabs/Tabs.js +1 -1
- package/es/components/TextArea/TextArea.js +14 -4
- package/es/components/TextInput/PasswordInput.js +3 -2
- package/lib/components/Dropdown/Dropdown.js +4 -0
- package/lib/components/Link/Link.js +1 -1
- package/lib/components/MultiSelect/FilterableMultiSelect.js +1 -0
- package/lib/components/MultiSelect/MultiSelect.js +1 -0
- package/lib/components/NumberInput/NumberInput.d.ts +6 -2
- package/lib/components/NumberInput/NumberInput.js +17 -5
- package/lib/components/Popover/index.d.ts +1 -1
- package/lib/components/Popover/index.js +27 -13
- package/lib/components/Tabs/Tabs.js +1 -1
- package/lib/components/TextArea/TextArea.js +14 -4
- package/lib/components/TextInput/PasswordInput.js +3 -2
- package/package.json +9 -10
- package/telemetry.yml +1 -0
|
@@ -342,7 +342,11 @@ const Dropdown = /*#__PURE__*/React.forwardRef(({
|
|
|
342
342
|
size: size$1,
|
|
343
343
|
className: className,
|
|
344
344
|
invalid: normalizedProps.invalid,
|
|
345
|
+
invalidText: isFluid ? invalidText : undefined,
|
|
346
|
+
invalidTextId: normalizedProps.invalidId,
|
|
345
347
|
warn: normalizedProps.warn,
|
|
348
|
+
warnText: isFluid ? warnText : undefined,
|
|
349
|
+
warnTextId: normalizedProps.warnId,
|
|
346
350
|
light: light,
|
|
347
351
|
isOpen: isOpen,
|
|
348
352
|
ref: enableFloatingStyles || autoAlign ? refs.setReference : null,
|
|
@@ -67,7 +67,7 @@ const LinkBase = /*#__PURE__*/React.forwardRef(({
|
|
|
67
67
|
ref: ref
|
|
68
68
|
}, linkProps, rest, {
|
|
69
69
|
onClick: handleOnClick
|
|
70
|
-
}), children, !inline && Icon && /*#__PURE__*/React.createElement("
|
|
70
|
+
}), children, !inline && Icon && /*#__PURE__*/React.createElement("span", {
|
|
71
71
|
className: `${prefix}--link__icon`
|
|
72
72
|
}, /*#__PURE__*/React.createElement(Icon, null)));
|
|
73
73
|
});
|
|
@@ -724,6 +724,7 @@ const FilterableMultiSelect = /*#__PURE__*/forwardRef(function FilterableMultiSe
|
|
|
724
724
|
return /*#__PURE__*/React.createElement(ListBox.MenuItem, _extends({
|
|
725
725
|
key: itemProps.id,
|
|
726
726
|
"aria-label": itemText,
|
|
727
|
+
"aria-checked": isIndeterminate ? 'mixed' : isChecked,
|
|
727
728
|
isActive: isChecked && !item['isSelectAll'],
|
|
728
729
|
isHighlighted: highlightedIndex === index,
|
|
729
730
|
title: itemText,
|
|
@@ -509,6 +509,7 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
|
|
|
509
509
|
key: itemProps.id,
|
|
510
510
|
isActive: isChecked && !item['isSelectAll'],
|
|
511
511
|
"aria-label": itemText,
|
|
512
|
+
"aria-checked": isIndeterminate ? 'mixed' : isChecked,
|
|
512
513
|
isHighlighted: highlightedIndex === index,
|
|
513
514
|
title: itemText,
|
|
514
515
|
disabled: itemProps['aria-disabled']
|
|
@@ -135,10 +135,14 @@ export interface NumberInputProps extends Omit<React.InputHTMLAttributes<HTMLInp
|
|
|
135
135
|
*/
|
|
136
136
|
min?: number;
|
|
137
137
|
/**
|
|
138
|
-
* Provide an optional handler that is called when the input
|
|
138
|
+
* Provide an optional handler that is called when the input is blurred.
|
|
139
|
+
*/
|
|
140
|
+
onBlur?: (event: React.FocusEvent<HTMLInputElement>, value?: string | number) => void;
|
|
141
|
+
/**
|
|
142
|
+
* Provide an optional handler that is called when the stepper
|
|
139
143
|
* buttons are blurred.
|
|
140
144
|
*/
|
|
141
|
-
|
|
145
|
+
onStepperBlur?: (event: React.FocusEvent<HTMLButtonElement>) => void;
|
|
142
146
|
/**
|
|
143
147
|
* Provide an optional handler that is called when the internal state of
|
|
144
148
|
* NumberInput changes. This handler is called with event and state info.
|
|
@@ -126,6 +126,7 @@ const NumberInput = /*#__PURE__*/React.forwardRef((props, forwardRef) => {
|
|
|
126
126
|
max,
|
|
127
127
|
min,
|
|
128
128
|
onBlur,
|
|
129
|
+
onStepperBlur,
|
|
129
130
|
onChange,
|
|
130
131
|
onClick,
|
|
131
132
|
onKeyUp,
|
|
@@ -426,6 +427,7 @@ const NumberInput = /*#__PURE__*/React.forwardRef((props, forwardRef) => {
|
|
|
426
427
|
if (disableWheelProp) {
|
|
427
428
|
e.target.removeEventListener('wheel', disableWheel);
|
|
428
429
|
}
|
|
430
|
+
let parsedValueForBlur;
|
|
429
431
|
if (type === 'text') {
|
|
430
432
|
// When isControlled, the current inputValue needs re-parsed
|
|
431
433
|
// because the consumer's onChange hasn't been called yet and
|
|
@@ -441,6 +443,7 @@ const NumberInput = /*#__PURE__*/React.forwardRef((props, forwardRef) => {
|
|
|
441
443
|
// causing the _numberValue to mismatch the formatted value in
|
|
442
444
|
// the input. To avoid this, formattedValue is re-parsed.
|
|
443
445
|
const parsedFormattedNewValue = numberParser.parse(formattedValue);
|
|
446
|
+
parsedValueForBlur = parsedFormattedNewValue;
|
|
444
447
|
if (onChange && isValid) {
|
|
445
448
|
const state = {
|
|
446
449
|
value: parsedFormattedNewValue,
|
|
@@ -466,7 +469,12 @@ const NumberInput = /*#__PURE__*/React.forwardRef((props, forwardRef) => {
|
|
|
466
469
|
}
|
|
467
470
|
}
|
|
468
471
|
if (onBlur) {
|
|
469
|
-
|
|
472
|
+
if (type === 'number') {
|
|
473
|
+
onBlur(e, value);
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
const parsedTextValue = parsedValueForBlur ?? (isControlled ? numberParser.parse(inputValue) : numberValue);
|
|
477
|
+
onBlur(e, parsedTextValue);
|
|
470
478
|
}
|
|
471
479
|
},
|
|
472
480
|
pattern: pattern,
|
|
@@ -486,7 +494,7 @@ const NumberInput = /*#__PURE__*/React.forwardRef((props, forwardRef) => {
|
|
|
486
494
|
className: `${prefix}--number__control-btn down-icon`,
|
|
487
495
|
disabled: disabled || readOnly,
|
|
488
496
|
onClick: event => handleStepperClick(event, 'down'),
|
|
489
|
-
onBlur:
|
|
497
|
+
onBlur: onStepperBlur,
|
|
490
498
|
tabIndex: -1,
|
|
491
499
|
title: decrementNumLabel || iconDescription,
|
|
492
500
|
type: "button"
|
|
@@ -499,7 +507,7 @@ const NumberInput = /*#__PURE__*/React.forwardRef((props, forwardRef) => {
|
|
|
499
507
|
className: `${prefix}--number__control-btn up-icon`,
|
|
500
508
|
disabled: disabled || readOnly,
|
|
501
509
|
onClick: event => handleStepperClick(event, 'up'),
|
|
502
|
-
onBlur:
|
|
510
|
+
onBlur: onStepperBlur,
|
|
503
511
|
tabIndex: -1,
|
|
504
512
|
title: incrementNumLabel || iconDescription,
|
|
505
513
|
type: "button"
|
|
@@ -610,10 +618,14 @@ NumberInput.propTypes = {
|
|
|
610
618
|
*/
|
|
611
619
|
stepStartValue: PropTypes.number,
|
|
612
620
|
/**
|
|
613
|
-
* Provide an optional handler that is called when the input
|
|
614
|
-
* buttons are blurred.
|
|
621
|
+
* Provide an optional handler that is called when the input is blurred.
|
|
615
622
|
*/
|
|
616
623
|
onBlur: PropTypes.func,
|
|
624
|
+
/**
|
|
625
|
+
* Provide an optional handler that is called when the stepper
|
|
626
|
+
* buttons are blurred.
|
|
627
|
+
*/
|
|
628
|
+
onStepperBlur: PropTypes.func,
|
|
617
629
|
/**
|
|
618
630
|
* Provide an optional handler that is called when the internal state of
|
|
619
631
|
* NumberInput changes. This handler is called with event and state info.
|
|
@@ -60,27 +60,41 @@ forwardRef) {
|
|
|
60
60
|
const caretRef = useRef(null);
|
|
61
61
|
const popover = useRef(null);
|
|
62
62
|
const enableFloatingStyles = useFeatureFlag('enable-v12-dynamic-floating-styles') || autoAlign;
|
|
63
|
+
const lastClickWasInsidePopoverContent = useRef(false);
|
|
63
64
|
let align = mapPopoverAlign(initialAlign);
|
|
64
65
|
|
|
66
|
+
// Tracks clicks inside PopoverContent to prevent it from closing when clicked, this handles an edge
|
|
67
|
+
// case where the popover will close when clicking non-focusable elements (e.g. text)
|
|
68
|
+
useEvent(popover, 'mousedown', event => {
|
|
69
|
+
const target = event.target;
|
|
70
|
+
lastClickWasInsidePopoverContent.current = refs.floating.current?.contains(target) || false;
|
|
71
|
+
|
|
72
|
+
// reset flag
|
|
73
|
+
if (lastClickWasInsidePopoverContent.current) {
|
|
74
|
+
setTimeout(() => {
|
|
75
|
+
lastClickWasInsidePopoverContent.current = false;
|
|
76
|
+
}, 0);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
65
80
|
// The `Popover` should close whenever it and its children loses focus
|
|
66
81
|
useEvent(popover, 'focusout', event => {
|
|
67
82
|
const relatedTarget = event.relatedTarget;
|
|
68
|
-
if (isTabTip) {
|
|
69
|
-
if (relatedTarget && !popover.current?.contains(relatedTarget)) {
|
|
70
|
-
onRequestClose?.();
|
|
71
|
-
}
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
83
|
if (!relatedTarget) {
|
|
84
|
+
// do not close if PopoverContent was clicked
|
|
85
|
+
if (lastClickWasInsidePopoverContent.current) {
|
|
86
|
+
lastClickWasInsidePopoverContent.current = false;
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
75
89
|
onRequestClose?.();
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const isOutsideFloating = enableFloatingStyles && refs.floating.current ? !refs.floating.current.contains(relatedTarget) : true;
|
|
90
|
+
} else if (relatedTarget && !popover.current?.contains(relatedTarget)) {
|
|
91
|
+
const isOutsideFloating = enableFloatingStyles && refs.floating.current ? !refs.floating.current.contains(relatedTarget) : true;
|
|
92
|
+
const isFocusableWrapper = relatedTarget && popover.current && relatedTarget.contains(popover.current);
|
|
80
93
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
94
|
+
// Only close if focus moved outside both containers and not to an interactive parent wrapper
|
|
95
|
+
if (isOutsideFloating && !isFocusableWrapper) {
|
|
96
|
+
onRequestClose?.();
|
|
97
|
+
}
|
|
84
98
|
}
|
|
85
99
|
});
|
|
86
100
|
useWindowEvent('click', ({
|
|
@@ -886,7 +886,7 @@ const Tab = /*#__PURE__*/forwardRef(({
|
|
|
886
886
|
})
|
|
887
887
|
}, /*#__PURE__*/React.createElement("button", {
|
|
888
888
|
type: "button",
|
|
889
|
-
tabIndex:
|
|
889
|
+
tabIndex: -1,
|
|
890
890
|
"aria-disabled": disabled,
|
|
891
891
|
"aria-hidden": selectedIndex === index && dismissable ? 'false' : 'true',
|
|
892
892
|
disabled: disabled,
|
|
@@ -202,8 +202,10 @@ const TextArea = frFn((props, forwardRef) => {
|
|
|
202
202
|
}, labelText) : null;
|
|
203
203
|
const counter = enableCounter && maxCount && (counterMode === 'character' || counterMode === 'word') ? /*#__PURE__*/React.createElement(Text, {
|
|
204
204
|
as: "div",
|
|
205
|
-
className: counterClasses
|
|
205
|
+
className: counterClasses,
|
|
206
|
+
"aria-hidden": "true"
|
|
206
207
|
}, `${textCount}/${maxCount}`) : null;
|
|
208
|
+
const counterDescriptionId = enableCounter && maxCount ? `${id}-counter-desc` : undefined;
|
|
207
209
|
const helperId = !helperText ? undefined : `text-area-helper-text-${textAreaInstanceId}`;
|
|
208
210
|
const helper = helperText ? /*#__PURE__*/React.createElement(Text, {
|
|
209
211
|
as: "div",
|
|
@@ -234,8 +236,13 @@ const TextArea = frFn((props, forwardRef) => {
|
|
|
234
236
|
let ariaDescribedBy;
|
|
235
237
|
if (invalid) {
|
|
236
238
|
ariaDescribedBy = errorId;
|
|
237
|
-
} else if (
|
|
238
|
-
ariaDescribedBy =
|
|
239
|
+
} else if (warn && !isFluid) {
|
|
240
|
+
ariaDescribedBy = warnId;
|
|
241
|
+
} else {
|
|
242
|
+
const ids = [];
|
|
243
|
+
if (!isFluid && helperText && helperId) ids.push(helperId);
|
|
244
|
+
if (counterDescriptionId) ids.push(counterDescriptionId);
|
|
245
|
+
ariaDescribedBy = ids.length > 0 ? ids.join(' ') : undefined;
|
|
239
246
|
}
|
|
240
247
|
if (enableCounter) {
|
|
241
248
|
// handle different counter mode
|
|
@@ -292,7 +299,10 @@ const TextArea = frFn((props, forwardRef) => {
|
|
|
292
299
|
className: formItemClasses
|
|
293
300
|
}, /*#__PURE__*/React.createElement("div", {
|
|
294
301
|
className: `${prefix}--text-area__label-wrapper`
|
|
295
|
-
}, label, counter), /*#__PURE__*/React.createElement("
|
|
302
|
+
}, label, counter), enableCounter && maxCount && /*#__PURE__*/React.createElement("span", {
|
|
303
|
+
id: counterDescriptionId,
|
|
304
|
+
className: `${prefix}--visually-hidden`
|
|
305
|
+
}, counterMode === 'word' ? `Word limit ${maxCount}` : `Character limit ${maxCount}`), /*#__PURE__*/React.createElement("div", {
|
|
296
306
|
ref: wrapperRef,
|
|
297
307
|
className: textAreaWrapperClasses,
|
|
298
308
|
"data-invalid": invalid || null
|
|
@@ -135,6 +135,7 @@ const PasswordInput = /*#__PURE__*/React.forwardRef(({
|
|
|
135
135
|
[`${prefix}--tooltip--${tooltipPosition}`]: tooltipPosition,
|
|
136
136
|
[`${prefix}--tooltip--align-${tooltipAlignment}`]: tooltipAlignment
|
|
137
137
|
});
|
|
138
|
+
const tooltipClasses = cx(`${prefix}--toggle-password-tooltip`, `${prefix}--icon-tooltip`);
|
|
138
139
|
let align = undefined;
|
|
139
140
|
if (tooltipPosition === 'top' || tooltipPosition === 'bottom') {
|
|
140
141
|
if (tooltipAlignment === 'center') {
|
|
@@ -172,12 +173,12 @@ const PasswordInput = /*#__PURE__*/React.forwardRef(({
|
|
|
172
173
|
className: `${prefix}--text-input__divider`
|
|
173
174
|
}), /*#__PURE__*/React.createElement(Tooltip, {
|
|
174
175
|
align: align,
|
|
175
|
-
className:
|
|
176
|
+
className: tooltipClasses,
|
|
176
177
|
label: passwordIsVisible ? hidePasswordLabel : showPasswordLabel
|
|
177
178
|
}, /*#__PURE__*/React.createElement("button", {
|
|
178
179
|
type: "button",
|
|
179
180
|
className: passwordVisibilityToggleClasses,
|
|
180
|
-
disabled: disabled
|
|
181
|
+
disabled: disabled,
|
|
181
182
|
onClick: handleTogglePasswordVisibility
|
|
182
183
|
}, passwordVisibilityIcon)));
|
|
183
184
|
useEffect(() => {
|
|
@@ -346,7 +346,11 @@ const Dropdown = /*#__PURE__*/React.forwardRef(({
|
|
|
346
346
|
size: size,
|
|
347
347
|
className: className,
|
|
348
348
|
invalid: normalizedProps.invalid,
|
|
349
|
+
invalidText: isFluid ? invalidText : undefined,
|
|
350
|
+
invalidTextId: normalizedProps.invalidId,
|
|
349
351
|
warn: normalizedProps.warn,
|
|
352
|
+
warnText: isFluid ? warnText : undefined,
|
|
353
|
+
warnTextId: normalizedProps.warnId,
|
|
350
354
|
light: light,
|
|
351
355
|
isOpen: isOpen,
|
|
352
356
|
ref: enableFloatingStyles || autoAlign ? refs.setReference : null,
|
|
@@ -71,7 +71,7 @@ const LinkBase = /*#__PURE__*/React.forwardRef(({
|
|
|
71
71
|
ref: ref
|
|
72
72
|
}, linkProps, rest, {
|
|
73
73
|
onClick: handleOnClick
|
|
74
|
-
}), children, !inline && Icon && /*#__PURE__*/React.createElement("
|
|
74
|
+
}), children, !inline && Icon && /*#__PURE__*/React.createElement("span", {
|
|
75
75
|
className: `${prefix}--link__icon`
|
|
76
76
|
}, /*#__PURE__*/React.createElement(Icon, null)));
|
|
77
77
|
});
|
|
@@ -726,6 +726,7 @@ const FilterableMultiSelect = /*#__PURE__*/React.forwardRef(function FilterableM
|
|
|
726
726
|
return /*#__PURE__*/React.createElement(index$1.default.MenuItem, _rollupPluginBabelHelpers.extends({
|
|
727
727
|
key: itemProps.id,
|
|
728
728
|
"aria-label": itemText,
|
|
729
|
+
"aria-checked": isIndeterminate ? 'mixed' : isChecked,
|
|
729
730
|
isActive: isChecked && !item['isSelectAll'],
|
|
730
731
|
isHighlighted: highlightedIndex === index,
|
|
731
732
|
title: itemText,
|
|
@@ -511,6 +511,7 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
|
|
|
511
511
|
key: itemProps.id,
|
|
512
512
|
isActive: isChecked && !item['isSelectAll'],
|
|
513
513
|
"aria-label": itemText,
|
|
514
|
+
"aria-checked": isIndeterminate ? 'mixed' : isChecked,
|
|
514
515
|
isHighlighted: highlightedIndex === index,
|
|
515
516
|
title: itemText,
|
|
516
517
|
disabled: itemProps['aria-disabled']
|
|
@@ -135,10 +135,14 @@ export interface NumberInputProps extends Omit<React.InputHTMLAttributes<HTMLInp
|
|
|
135
135
|
*/
|
|
136
136
|
min?: number;
|
|
137
137
|
/**
|
|
138
|
-
* Provide an optional handler that is called when the input
|
|
138
|
+
* Provide an optional handler that is called when the input is blurred.
|
|
139
|
+
*/
|
|
140
|
+
onBlur?: (event: React.FocusEvent<HTMLInputElement>, value?: string | number) => void;
|
|
141
|
+
/**
|
|
142
|
+
* Provide an optional handler that is called when the stepper
|
|
139
143
|
* buttons are blurred.
|
|
140
144
|
*/
|
|
141
|
-
|
|
145
|
+
onStepperBlur?: (event: React.FocusEvent<HTMLButtonElement>) => void;
|
|
142
146
|
/**
|
|
143
147
|
* Provide an optional handler that is called when the internal state of
|
|
144
148
|
* NumberInput changes. This handler is called with event and state info.
|
|
@@ -128,6 +128,7 @@ const NumberInput = /*#__PURE__*/React.forwardRef((props, forwardRef) => {
|
|
|
128
128
|
max,
|
|
129
129
|
min,
|
|
130
130
|
onBlur,
|
|
131
|
+
onStepperBlur,
|
|
131
132
|
onChange,
|
|
132
133
|
onClick,
|
|
133
134
|
onKeyUp,
|
|
@@ -428,6 +429,7 @@ const NumberInput = /*#__PURE__*/React.forwardRef((props, forwardRef) => {
|
|
|
428
429
|
if (disableWheelProp) {
|
|
429
430
|
e.target.removeEventListener('wheel', disableWheel);
|
|
430
431
|
}
|
|
432
|
+
let parsedValueForBlur;
|
|
431
433
|
if (type === 'text') {
|
|
432
434
|
// When isControlled, the current inputValue needs re-parsed
|
|
433
435
|
// because the consumer's onChange hasn't been called yet and
|
|
@@ -443,6 +445,7 @@ const NumberInput = /*#__PURE__*/React.forwardRef((props, forwardRef) => {
|
|
|
443
445
|
// causing the _numberValue to mismatch the formatted value in
|
|
444
446
|
// the input. To avoid this, formattedValue is re-parsed.
|
|
445
447
|
const parsedFormattedNewValue = numberParser.parse(formattedValue);
|
|
448
|
+
parsedValueForBlur = parsedFormattedNewValue;
|
|
446
449
|
if (onChange && isValid) {
|
|
447
450
|
const state = {
|
|
448
451
|
value: parsedFormattedNewValue,
|
|
@@ -468,7 +471,12 @@ const NumberInput = /*#__PURE__*/React.forwardRef((props, forwardRef) => {
|
|
|
468
471
|
}
|
|
469
472
|
}
|
|
470
473
|
if (onBlur) {
|
|
471
|
-
|
|
474
|
+
if (type === 'number') {
|
|
475
|
+
onBlur(e, value);
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
const parsedTextValue = parsedValueForBlur ?? (isControlled ? numberParser.parse(inputValue) : numberValue);
|
|
479
|
+
onBlur(e, parsedTextValue);
|
|
472
480
|
}
|
|
473
481
|
},
|
|
474
482
|
pattern: pattern,
|
|
@@ -488,7 +496,7 @@ const NumberInput = /*#__PURE__*/React.forwardRef((props, forwardRef) => {
|
|
|
488
496
|
className: `${prefix}--number__control-btn down-icon`,
|
|
489
497
|
disabled: disabled || readOnly,
|
|
490
498
|
onClick: event => handleStepperClick(event, 'down'),
|
|
491
|
-
onBlur:
|
|
499
|
+
onBlur: onStepperBlur,
|
|
492
500
|
tabIndex: -1,
|
|
493
501
|
title: decrementNumLabel || iconDescription,
|
|
494
502
|
type: "button"
|
|
@@ -501,7 +509,7 @@ const NumberInput = /*#__PURE__*/React.forwardRef((props, forwardRef) => {
|
|
|
501
509
|
className: `${prefix}--number__control-btn up-icon`,
|
|
502
510
|
disabled: disabled || readOnly,
|
|
503
511
|
onClick: event => handleStepperClick(event, 'up'),
|
|
504
|
-
onBlur:
|
|
512
|
+
onBlur: onStepperBlur,
|
|
505
513
|
tabIndex: -1,
|
|
506
514
|
title: incrementNumLabel || iconDescription,
|
|
507
515
|
type: "button"
|
|
@@ -612,10 +620,14 @@ NumberInput.propTypes = {
|
|
|
612
620
|
*/
|
|
613
621
|
stepStartValue: PropTypes.number,
|
|
614
622
|
/**
|
|
615
|
-
* Provide an optional handler that is called when the input
|
|
616
|
-
* buttons are blurred.
|
|
623
|
+
* Provide an optional handler that is called when the input is blurred.
|
|
617
624
|
*/
|
|
618
625
|
onBlur: PropTypes.func,
|
|
626
|
+
/**
|
|
627
|
+
* Provide an optional handler that is called when the stepper
|
|
628
|
+
* buttons are blurred.
|
|
629
|
+
*/
|
|
630
|
+
onStepperBlur: PropTypes.func,
|
|
619
631
|
/**
|
|
620
632
|
* Provide an optional handler that is called when the internal state of
|
|
621
633
|
* NumberInput changes. This handler is called with event and state info.
|
|
@@ -62,27 +62,41 @@ forwardRef) {
|
|
|
62
62
|
const caretRef = React.useRef(null);
|
|
63
63
|
const popover = React.useRef(null);
|
|
64
64
|
const enableFloatingStyles = index.useFeatureFlag('enable-v12-dynamic-floating-styles') || autoAlign;
|
|
65
|
+
const lastClickWasInsidePopoverContent = React.useRef(false);
|
|
65
66
|
let align = mapPopoverAlign.mapPopoverAlign(initialAlign);
|
|
66
67
|
|
|
68
|
+
// Tracks clicks inside PopoverContent to prevent it from closing when clicked, this handles an edge
|
|
69
|
+
// case where the popover will close when clicking non-focusable elements (e.g. text)
|
|
70
|
+
useEvent.useEvent(popover, 'mousedown', event => {
|
|
71
|
+
const target = event.target;
|
|
72
|
+
lastClickWasInsidePopoverContent.current = refs.floating.current?.contains(target) || false;
|
|
73
|
+
|
|
74
|
+
// reset flag
|
|
75
|
+
if (lastClickWasInsidePopoverContent.current) {
|
|
76
|
+
setTimeout(() => {
|
|
77
|
+
lastClickWasInsidePopoverContent.current = false;
|
|
78
|
+
}, 0);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
67
82
|
// The `Popover` should close whenever it and its children loses focus
|
|
68
83
|
useEvent.useEvent(popover, 'focusout', event => {
|
|
69
84
|
const relatedTarget = event.relatedTarget;
|
|
70
|
-
if (isTabTip) {
|
|
71
|
-
if (relatedTarget && !popover.current?.contains(relatedTarget)) {
|
|
72
|
-
onRequestClose?.();
|
|
73
|
-
}
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
85
|
if (!relatedTarget) {
|
|
86
|
+
// do not close if PopoverContent was clicked
|
|
87
|
+
if (lastClickWasInsidePopoverContent.current) {
|
|
88
|
+
lastClickWasInsidePopoverContent.current = false;
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
77
91
|
onRequestClose?.();
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const isOutsideFloating = enableFloatingStyles && refs.floating.current ? !refs.floating.current.contains(relatedTarget) : true;
|
|
92
|
+
} else if (relatedTarget && !popover.current?.contains(relatedTarget)) {
|
|
93
|
+
const isOutsideFloating = enableFloatingStyles && refs.floating.current ? !refs.floating.current.contains(relatedTarget) : true;
|
|
94
|
+
const isFocusableWrapper = relatedTarget && popover.current && relatedTarget.contains(popover.current);
|
|
82
95
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
96
|
+
// Only close if focus moved outside both containers and not to an interactive parent wrapper
|
|
97
|
+
if (isOutsideFloating && !isFocusableWrapper) {
|
|
98
|
+
onRequestClose?.();
|
|
99
|
+
}
|
|
86
100
|
}
|
|
87
101
|
});
|
|
88
102
|
useEvent.useWindowEvent('click', ({
|
|
@@ -888,7 +888,7 @@ const Tab = /*#__PURE__*/React.forwardRef(({
|
|
|
888
888
|
})
|
|
889
889
|
}, /*#__PURE__*/React.createElement("button", {
|
|
890
890
|
type: "button",
|
|
891
|
-
tabIndex:
|
|
891
|
+
tabIndex: -1,
|
|
892
892
|
"aria-disabled": disabled,
|
|
893
893
|
"aria-hidden": selectedIndex === index$1 && dismissable ? 'false' : 'true',
|
|
894
894
|
disabled: disabled,
|
|
@@ -206,8 +206,10 @@ const TextArea = frFn((props, forwardRef) => {
|
|
|
206
206
|
}, labelText) : null;
|
|
207
207
|
const counter = enableCounter && maxCount && (counterMode === 'character' || counterMode === 'word') ? /*#__PURE__*/React.createElement(Text.Text, {
|
|
208
208
|
as: "div",
|
|
209
|
-
className: counterClasses
|
|
209
|
+
className: counterClasses,
|
|
210
|
+
"aria-hidden": "true"
|
|
210
211
|
}, `${textCount}/${maxCount}`) : null;
|
|
212
|
+
const counterDescriptionId = enableCounter && maxCount ? `${id}-counter-desc` : undefined;
|
|
211
213
|
const helperId = !helperText ? undefined : `text-area-helper-text-${textAreaInstanceId}`;
|
|
212
214
|
const helper = helperText ? /*#__PURE__*/React.createElement(Text.Text, {
|
|
213
215
|
as: "div",
|
|
@@ -238,8 +240,13 @@ const TextArea = frFn((props, forwardRef) => {
|
|
|
238
240
|
let ariaDescribedBy;
|
|
239
241
|
if (invalid) {
|
|
240
242
|
ariaDescribedBy = errorId;
|
|
241
|
-
} else if (
|
|
242
|
-
ariaDescribedBy =
|
|
243
|
+
} else if (warn && !isFluid) {
|
|
244
|
+
ariaDescribedBy = warnId;
|
|
245
|
+
} else {
|
|
246
|
+
const ids = [];
|
|
247
|
+
if (!isFluid && helperText && helperId) ids.push(helperId);
|
|
248
|
+
if (counterDescriptionId) ids.push(counterDescriptionId);
|
|
249
|
+
ariaDescribedBy = ids.length > 0 ? ids.join(' ') : undefined;
|
|
243
250
|
}
|
|
244
251
|
if (enableCounter) {
|
|
245
252
|
// handle different counter mode
|
|
@@ -296,7 +303,10 @@ const TextArea = frFn((props, forwardRef) => {
|
|
|
296
303
|
className: formItemClasses
|
|
297
304
|
}, /*#__PURE__*/React.createElement("div", {
|
|
298
305
|
className: `${prefix}--text-area__label-wrapper`
|
|
299
|
-
}, label, counter), /*#__PURE__*/React.createElement("
|
|
306
|
+
}, label, counter), enableCounter && maxCount && /*#__PURE__*/React.createElement("span", {
|
|
307
|
+
id: counterDescriptionId,
|
|
308
|
+
className: `${prefix}--visually-hidden`
|
|
309
|
+
}, counterMode === 'word' ? `Word limit ${maxCount}` : `Character limit ${maxCount}`), /*#__PURE__*/React.createElement("div", {
|
|
300
310
|
ref: wrapperRef,
|
|
301
311
|
className: textAreaWrapperClasses,
|
|
302
312
|
"data-invalid": invalid || null
|
|
@@ -139,6 +139,7 @@ const PasswordInput = /*#__PURE__*/React.forwardRef(({
|
|
|
139
139
|
[`${prefix}--tooltip--${tooltipPosition}`]: tooltipPosition,
|
|
140
140
|
[`${prefix}--tooltip--align-${tooltipAlignment}`]: tooltipAlignment
|
|
141
141
|
});
|
|
142
|
+
const tooltipClasses = cx(`${prefix}--toggle-password-tooltip`, `${prefix}--icon-tooltip`);
|
|
142
143
|
let align = undefined;
|
|
143
144
|
if (tooltipPosition === 'top' || tooltipPosition === 'bottom') {
|
|
144
145
|
if (tooltipAlignment === 'center') {
|
|
@@ -176,12 +177,12 @@ const PasswordInput = /*#__PURE__*/React.forwardRef(({
|
|
|
176
177
|
className: `${prefix}--text-input__divider`
|
|
177
178
|
}), /*#__PURE__*/React.createElement(Tooltip.Tooltip, {
|
|
178
179
|
align: align,
|
|
179
|
-
className:
|
|
180
|
+
className: tooltipClasses,
|
|
180
181
|
label: passwordIsVisible ? hidePasswordLabel : showPasswordLabel
|
|
181
182
|
}, /*#__PURE__*/React.createElement("button", {
|
|
182
183
|
type: "button",
|
|
183
184
|
className: passwordVisibilityToggleClasses,
|
|
184
|
-
disabled: disabled
|
|
185
|
+
disabled: disabled,
|
|
185
186
|
onClick: handleTogglePasswordVisibility
|
|
186
187
|
}, passwordVisibilityIcon)));
|
|
187
188
|
React.useEffect(() => {
|
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.
|
|
4
|
+
"version": "1.99.0-rc.0",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "lib/index.d.ts",
|
|
@@ -53,9 +53,9 @@
|
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@babel/runtime": "^7.27.3",
|
|
55
55
|
"@carbon/feature-flags": ">=0.32.0",
|
|
56
|
-
"@carbon/icons-react": "^11.
|
|
57
|
-
"@carbon/layout": "^11.
|
|
58
|
-
"@carbon/styles": "^1.
|
|
56
|
+
"@carbon/icons-react": "^11.73.0-rc.0",
|
|
57
|
+
"@carbon/layout": "^11.46.0-rc.0",
|
|
58
|
+
"@carbon/styles": "^1.98.0-rc.0",
|
|
59
59
|
"@carbon/utilities": "^0.14.0",
|
|
60
60
|
"@floating-ui/react": "^0.27.4",
|
|
61
61
|
"@ibm/telemetry-js": "^1.5.0",
|
|
@@ -67,7 +67,6 @@
|
|
|
67
67
|
"invariant": "^2.2.3",
|
|
68
68
|
"prop-types": "^15.8.1",
|
|
69
69
|
"react-fast-compare": "^3.2.2",
|
|
70
|
-
"storybook-addon-accessibility-checker": "^9.2.0-rc.3",
|
|
71
70
|
"tabbable": "^6.2.0"
|
|
72
71
|
},
|
|
73
72
|
"devDependencies": {
|
|
@@ -79,8 +78,8 @@
|
|
|
79
78
|
"@babel/preset-env": "^7.27.2",
|
|
80
79
|
"@babel/preset-react": "^7.27.1",
|
|
81
80
|
"@babel/preset-typescript": "^7.27.1",
|
|
82
|
-
"@carbon/test-utils": "^10.
|
|
83
|
-
"@carbon/themes": "^11.
|
|
81
|
+
"@carbon/test-utils": "^10.39.0-rc.0",
|
|
82
|
+
"@carbon/themes": "^11.66.0-rc.0",
|
|
84
83
|
"@figma/code-connect": "^1.3.5",
|
|
85
84
|
"@rollup/plugin-babel": "^6.0.0",
|
|
86
85
|
"@rollup/plugin-commonjs": "^28.0.3",
|
|
@@ -105,8 +104,8 @@
|
|
|
105
104
|
"fs-extra": "^11.0.0",
|
|
106
105
|
"process": "^0.11.10",
|
|
107
106
|
"prop-types": "^15.8.1",
|
|
108
|
-
"react": "^19.
|
|
109
|
-
"react-dom": "^19.
|
|
107
|
+
"react": "^19.2.3",
|
|
108
|
+
"react-dom": "^19.2.3",
|
|
110
109
|
"react-is": "^16.13.1 || ^17.0.2 || ^18.3.1 || ^19.0.0",
|
|
111
110
|
"remark-gfm": "^4.0.0",
|
|
112
111
|
"rimraf": "^6.0.1",
|
|
@@ -132,5 +131,5 @@
|
|
|
132
131
|
"**/*.scss",
|
|
133
132
|
"**/*.css"
|
|
134
133
|
],
|
|
135
|
-
"gitHead": "
|
|
134
|
+
"gitHead": "8263c72357fc43c00e66c9030698f759ef7977ce"
|
|
136
135
|
}
|