@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.
@@ -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("div", {
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 or stepper
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
- onBlur?: (event: React.FocusEvent<HTMLInputElement> | React.FocusEvent<HTMLButtonElement>) => void;
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
- onBlur(e);
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: 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: 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 or stepper
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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright IBM Corp. 2016, 2025
2
+ * Copyright IBM Corp. 2016, 2026
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.
@@ -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
- return;
77
- }
78
- const isOutsideMainContainer = !popover.current?.contains(relatedTarget);
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
- // Only close if focus moved outside both containers
82
- if (isOutsideMainContainer && isOutsideFloating) {
83
- onRequestClose?.();
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: selectedIndex === index && dismissable ? 0 : -1,
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 (!invalid && !warn && !isFluid && helperText) {
238
- ariaDescribedBy = helperId;
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("div", {
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: `${prefix}--toggle-password-tooltip`,
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 || readOnly,
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("div", {
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 or stepper
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
- onBlur?: (event: React.FocusEvent<HTMLInputElement> | React.FocusEvent<HTMLButtonElement>) => void;
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
- onBlur(e);
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: 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: 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 or stepper
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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright IBM Corp. 2016, 2025
2
+ * Copyright IBM Corp. 2016, 2026
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.
@@ -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
- return;
79
- }
80
- const isOutsideMainContainer = !popover.current?.contains(relatedTarget);
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
- // Only close if focus moved outside both containers
84
- if (isOutsideMainContainer && isOutsideFloating) {
85
- onRequestClose?.();
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: selectedIndex === index$1 && dismissable ? 0 : -1,
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 (!invalid && !warn && !isFluid && helperText) {
242
- ariaDescribedBy = helperId;
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("div", {
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: `${prefix}--toggle-password-tooltip`,
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 || readOnly,
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.98.0",
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.72.0",
57
- "@carbon/layout": "^11.45.0",
58
- "@carbon/styles": "^1.97.0",
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.38.0",
83
- "@carbon/themes": "^11.65.0",
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.0.0",
109
- "react-dom": "^19.0.0",
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": "57fdbc7bfad9349b5c4359c7d621e709cd4daa25"
134
+ "gitHead": "8263c72357fc43c00e66c9030698f759ef7977ce"
136
135
  }
package/telemetry.yml CHANGED
@@ -465,6 +465,7 @@ collect:
465
465
  - notificationType
466
466
  # NumberInput
467
467
  - hideSteppers
468
+ - onStepperBlur
468
469
  - stepStartValue
469
470
  - validate
470
471
  # OrderedList