@carbon/react 1.91.0 → 1.92.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.
Files changed (163) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +989 -1014
  2. package/es/components/Accordion/AccordionItem.d.ts +12 -1
  3. package/es/components/Accordion/AccordionItem.js +9 -2
  4. package/es/components/Breadcrumb/BreadcrumbItem.js +1 -1
  5. package/es/components/Checkbox/Checkbox.js +2 -2
  6. package/es/components/ComboBox/ComboBox.js +39 -23
  7. package/es/components/ComboButton/index.js +1 -1
  8. package/es/components/ComposedModal/ComposedModal.js +66 -17
  9. package/es/components/ComposedModal/ComposedModalPresence.d.ts +34 -0
  10. package/es/components/ComposedModal/ComposedModalPresence.js +42 -0
  11. package/es/components/ComposedModal/index.d.ts +1 -0
  12. package/es/components/ComposedModal/useComposedModalState.d.ts +7 -0
  13. package/es/components/ComposedModal/useComposedModalState.js +24 -0
  14. package/es/components/DataTable/TableBatchActions.js +2 -2
  15. package/es/components/DatePicker/DatePicker.js +14 -6
  16. package/es/components/DatePickerInput/DatePickerInput.js +3 -3
  17. package/es/components/Dialog/Dialog.js +2 -2
  18. package/es/components/Dropdown/Dropdown.js +5 -5
  19. package/es/components/ExpandableSearch/ExpandableSearch.d.ts +1 -1
  20. package/es/components/ExpandableSearch/ExpandableSearch.js +1 -1
  21. package/es/components/FeatureFlags/index.d.ts +2 -1
  22. package/es/components/FeatureFlags/index.js +3 -1
  23. package/es/components/FileUploader/FileUploader.js +2 -2
  24. package/es/components/FileUploader/FileUploaderItem.js +2 -2
  25. package/es/components/FluidTextInput/FluidPasswordInput.js +24 -5
  26. package/es/components/FluidTextInput/index.js +1 -1
  27. package/es/components/FormLabel/FormLabel.js +1 -1
  28. package/es/components/ListBox/ListBox.d.ts +1 -1
  29. package/es/components/ListBox/ListBox.js +1 -2
  30. package/es/components/ListItem/ListItem.js +1 -1
  31. package/es/components/Menu/MenuItem.js +2 -2
  32. package/es/components/MenuButton/index.d.ts +2 -2
  33. package/es/components/MenuButton/index.js +2 -2
  34. package/es/components/Modal/Modal.js +60 -10
  35. package/es/components/Modal/ModalPresence.d.ts +32 -0
  36. package/es/components/Modal/ModalPresence.js +37 -0
  37. package/es/components/Modal/index.d.ts +2 -1
  38. package/es/components/Modal/index.js +1 -0
  39. package/es/components/MultiSelect/FilterableMultiSelect.js +3 -3
  40. package/es/components/MultiSelect/MultiSelect.js +6 -5
  41. package/es/components/Notification/Notification.js +2 -2
  42. package/es/components/NumberInput/NumberInput.d.ts +21 -11
  43. package/es/components/NumberInput/NumberInput.js +40 -26
  44. package/es/components/OverflowMenu/OverflowMenu.js +2 -3
  45. package/es/components/OverflowMenu/next/index.js +1 -1
  46. package/es/components/OverflowMenuItem/OverflowMenuItem.js +1 -1
  47. package/es/components/PageHeader/PageHeader.js +2 -2
  48. package/es/components/ProgressIndicator/ProgressIndicator.js +1 -1
  49. package/es/components/RadioButton/RadioButton.js +3 -3
  50. package/es/components/RadioButtonGroup/RadioButtonGroup.js +2 -2
  51. package/es/components/RadioTile/RadioTile.js +2 -2
  52. package/es/components/Select/Select.js +2 -2
  53. package/es/components/Slider/Slider.js +2 -2
  54. package/es/components/StructuredList/StructuredList.js +2 -2
  55. package/es/components/Tabs/Tabs.js +2 -2
  56. package/es/components/Tag/DismissibleTag.js +3 -3
  57. package/es/components/Tag/OperationalTag.js +3 -3
  58. package/es/components/Tag/SelectableTag.js +3 -3
  59. package/es/components/Tag/Tag.js +2 -2
  60. package/es/components/Text/Text.d.ts +1 -1
  61. package/es/components/Text/Text.js +0 -1
  62. package/es/components/Text/TextDirection.d.ts +1 -1
  63. package/es/components/Text/TextDirection.js +0 -1
  64. package/es/components/Text/createTextComponent.d.ts +2 -8
  65. package/es/components/Text/createTextComponent.js +2 -2
  66. package/es/components/Text/index.d.ts +0 -8
  67. package/es/components/TextArea/TextArea.js +2 -2
  68. package/es/components/TextInput/TextInput.js +2 -2
  69. package/es/components/Tile/Tile.js +2 -2
  70. package/es/components/Toggle/Toggle.js +2 -2
  71. package/es/components/UIShell/Switcher.js +0 -26
  72. package/es/index.d.ts +1 -1
  73. package/es/index.js +6 -4
  74. package/es/internal/useNormalizedInputProps.js +2 -2
  75. package/es/internal/usePresence.d.ts +17 -0
  76. package/es/internal/usePresence.js +66 -0
  77. package/es/internal/usePresenceContext.d.ts +25 -0
  78. package/es/internal/usePresenceContext.js +46 -0
  79. package/es/tools/mergeRefs.d.ts +5 -5
  80. package/es/tools/mergeRefs.js +16 -12
  81. package/lib/components/Accordion/AccordionItem.d.ts +12 -1
  82. package/lib/components/Accordion/AccordionItem.js +9 -2
  83. package/lib/components/Breadcrumb/BreadcrumbItem.js +1 -1
  84. package/lib/components/Checkbox/Checkbox.js +2 -2
  85. package/lib/components/ComboBox/ComboBox.js +39 -23
  86. package/lib/components/ComboButton/index.js +1 -1
  87. package/lib/components/ComposedModal/ComposedModal.js +65 -16
  88. package/lib/components/ComposedModal/ComposedModalPresence.d.ts +34 -0
  89. package/lib/components/ComposedModal/ComposedModalPresence.js +46 -0
  90. package/lib/components/ComposedModal/index.d.ts +1 -0
  91. package/lib/components/ComposedModal/useComposedModalState.d.ts +7 -0
  92. package/lib/components/ComposedModal/useComposedModalState.js +26 -0
  93. package/lib/components/DataTable/TableBatchActions.js +2 -2
  94. package/lib/components/DatePicker/DatePicker.js +14 -6
  95. package/lib/components/DatePickerInput/DatePickerInput.js +3 -3
  96. package/lib/components/Dialog/Dialog.js +2 -2
  97. package/lib/components/Dropdown/Dropdown.js +3 -3
  98. package/lib/components/ExpandableSearch/ExpandableSearch.d.ts +1 -1
  99. package/lib/components/ExpandableSearch/ExpandableSearch.js +1 -1
  100. package/lib/components/FeatureFlags/index.d.ts +2 -1
  101. package/lib/components/FeatureFlags/index.js +3 -1
  102. package/lib/components/FileUploader/FileUploader.js +2 -2
  103. package/lib/components/FileUploader/FileUploaderItem.js +2 -2
  104. package/lib/components/FluidTextInput/FluidPasswordInput.js +26 -5
  105. package/lib/components/FluidTextInput/index.js +2 -1
  106. package/lib/components/FormLabel/FormLabel.js +1 -1
  107. package/lib/components/ListBox/ListBox.d.ts +1 -1
  108. package/lib/components/ListBox/ListBox.js +1 -2
  109. package/lib/components/ListItem/ListItem.js +1 -1
  110. package/lib/components/Menu/MenuItem.js +2 -2
  111. package/lib/components/MenuButton/index.d.ts +2 -2
  112. package/lib/components/MenuButton/index.js +2 -2
  113. package/lib/components/Modal/Modal.js +59 -9
  114. package/lib/components/Modal/ModalPresence.d.ts +32 -0
  115. package/lib/components/Modal/ModalPresence.js +41 -0
  116. package/lib/components/Modal/index.d.ts +2 -1
  117. package/lib/components/Modal/index.js +1 -0
  118. package/lib/components/MultiSelect/FilterableMultiSelect.js +3 -3
  119. package/lib/components/MultiSelect/MultiSelect.js +4 -3
  120. package/lib/components/Notification/Notification.js +2 -2
  121. package/lib/components/NumberInput/NumberInput.d.ts +21 -11
  122. package/lib/components/NumberInput/NumberInput.js +40 -26
  123. package/lib/components/OverflowMenu/OverflowMenu.js +2 -3
  124. package/lib/components/OverflowMenu/next/index.js +1 -1
  125. package/lib/components/OverflowMenuItem/OverflowMenuItem.js +1 -1
  126. package/lib/components/PageHeader/PageHeader.js +2 -2
  127. package/lib/components/ProgressIndicator/ProgressIndicator.js +1 -1
  128. package/lib/components/RadioButton/RadioButton.js +3 -3
  129. package/lib/components/RadioButtonGroup/RadioButtonGroup.js +3 -3
  130. package/lib/components/RadioTile/RadioTile.js +2 -2
  131. package/lib/components/Select/Select.js +2 -2
  132. package/lib/components/Slider/Slider.js +2 -2
  133. package/lib/components/StructuredList/StructuredList.js +2 -2
  134. package/lib/components/Tabs/Tabs.js +2 -2
  135. package/lib/components/Tag/DismissibleTag.js +3 -3
  136. package/lib/components/Tag/OperationalTag.js +3 -3
  137. package/lib/components/Tag/SelectableTag.js +3 -3
  138. package/lib/components/Tag/Tag.js +2 -2
  139. package/lib/components/Text/Text.d.ts +1 -1
  140. package/lib/components/Text/Text.js +0 -1
  141. package/lib/components/Text/TextDirection.d.ts +1 -1
  142. package/lib/components/Text/TextDirection.js +0 -1
  143. package/lib/components/Text/createTextComponent.d.ts +2 -8
  144. package/lib/components/Text/createTextComponent.js +2 -2
  145. package/lib/components/Text/index.d.ts +0 -8
  146. package/lib/components/TextArea/TextArea.js +2 -2
  147. package/lib/components/TextInput/TextInput.js +2 -2
  148. package/lib/components/Tile/Tile.js +2 -2
  149. package/lib/components/Toggle/Toggle.js +2 -2
  150. package/lib/components/UIShell/Switcher.js +0 -26
  151. package/lib/index.d.ts +1 -1
  152. package/lib/index.js +13 -8
  153. package/lib/internal/useNormalizedInputProps.js +2 -2
  154. package/lib/internal/usePresence.d.ts +17 -0
  155. package/lib/internal/usePresence.js +68 -0
  156. package/lib/internal/usePresenceContext.d.ts +25 -0
  157. package/lib/internal/usePresenceContext.js +48 -0
  158. package/lib/tools/mergeRefs.d.ts +5 -5
  159. package/lib/tools/mergeRefs.js +16 -14
  160. package/package.json +7 -7
  161. package/telemetry.yml +4 -0
  162. package/es/components/Text/index.js +0 -16
  163. package/lib/components/Text/index.js +0 -20
@@ -6,13 +6,13 @@
6
6
  */
7
7
 
8
8
  import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
9
- import React, { useEffect, useContext, useCallback, useMemo, useState, isValidElement, cloneElement } from 'react';
9
+ import React, { useEffect, useContext, useCallback, useMemo, useState, useRef, isValidElement, cloneElement } from 'react';
10
10
  import { useSelect } from 'downshift';
11
11
  import cx from 'classnames';
12
12
  import PropTypes from 'prop-types';
13
13
  import { WarningFilled, WarningAltFilled, Checkmark } from '@carbon/icons-react';
14
14
  import ListBox from '../ListBox/index.js';
15
- import mergeRefs from '../../tools/mergeRefs.js';
15
+ import { mergeRefs } from '../../tools/mergeRefs.js';
16
16
  import { deprecate } from '../../prop-types/deprecate.js';
17
17
  import { usePrefix } from '../../internal/usePrefix.js';
18
18
  import '../FluidForm/FluidForm.js';
@@ -251,7 +251,8 @@ const Dropdown = /*#__PURE__*/React.forwardRef(({
251
251
  const handleFocus = evt => {
252
252
  setIsFocused(evt.type === 'focus' && !selectedItem ? true : false);
253
253
  };
254
- const mergedRef = mergeRefs(toggleButtonProps.ref, ref);
254
+ const buttonRef = useRef(null);
255
+ const mergedRef = mergeRefs(toggleButtonProps.ref, ref, buttonRef);
255
256
  const [currTimer, setCurrTimer] = useState();
256
257
  const [isTyping, setIsTyping] = useState(false);
257
258
  const onKeyDownHandler = useCallback(evt => {
@@ -287,7 +288,7 @@ const Dropdown = /*#__PURE__*/React.forwardRef(({
287
288
  // NOTE: does not prevent click
288
289
  evt.preventDefault();
289
290
  // focus on the element as per readonly input behavior
290
- mergedRef?.current?.focus();
291
+ buttonRef.current?.focus();
291
292
  },
292
293
  onKeyDown: evt => {
293
294
  const selectAccessKeys = ['ArrowDown', 'ArrowUp', ' ', 'Enter'];
@@ -302,7 +303,6 @@ const Dropdown = /*#__PURE__*/React.forwardRef(({
302
303
  onKeyDown: onKeyDownHandler
303
304
  };
304
305
  }
305
- // eslint-disable-next-line react-hooks/exhaustive-deps -- https://github.com/carbon-design-system/carbon/issues/20071
306
306
  }, [readOnly, onKeyDownHandler]);
307
307
  const menuProps = useMemo(() => getMenuProps({
308
308
  ref: enableFloatingStyles || autoAlign ? refs.setFloating : null
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright IBM Corp. 2021
2
+ * Copyright IBM Corp. 2021, 2025
3
3
  *
4
4
  * This source code is licensed under the Apache-2.0 license found in the
5
5
  * LICENSE file in the root directory of this source tree.
@@ -14,7 +14,7 @@ import { usePrefix } from '../../internal/usePrefix.js';
14
14
  import { composeEventHandlers } from '../../tools/events.js';
15
15
  import { Escape } from '../../internal/keyboard/keys.js';
16
16
  import { match } from '../../internal/keyboard/match.js';
17
- import mergeRefs from '../../tools/mergeRefs.js';
17
+ import { mergeRefs } from '../../tools/mergeRefs.js';
18
18
 
19
19
  const ExpandableSearch = /*#__PURE__*/React.forwardRef(function ExpandableSearch({
20
20
  onBlur,
@@ -17,6 +17,7 @@ export interface FeatureFlagsProps {
17
17
  enableDialogElement?: boolean;
18
18
  enableV12DynamicFloatingStyles?: boolean;
19
19
  enableEnhancedFileUploader?: boolean;
20
+ enablePresence?: boolean;
20
21
  }
21
22
  /**
22
23
  * Our FeatureFlagContext is used alongside the FeatureFlags component to enable
@@ -28,7 +29,7 @@ declare const FeatureFlagContext: React.Context<any>;
28
29
  * along with the current `FeatureFlagContext` to provide consumers to check if
29
30
  * a feature flag is enabled or disabled in a given React tree
30
31
  */
31
- declare function FeatureFlags({ children, flags, enableV12TileDefaultIcons, enableV12TileRadioIcons, enableV12Overflowmenu, enableTreeviewControllable, enableExperimentalFocusWrapWithoutSentinels, enableDialogElement, enableV12DynamicFloatingStyles, enableEnhancedFileUploader, }: FeatureFlagsProps): JSX.Element;
32
+ declare function FeatureFlags({ children, flags, enableV12TileDefaultIcons, enableV12TileRadioIcons, enableV12Overflowmenu, enableTreeviewControllable, enableExperimentalFocusWrapWithoutSentinels, enableDialogElement, enableV12DynamicFloatingStyles, enableEnhancedFileUploader, enablePresence, }: FeatureFlagsProps): JSX.Element;
32
33
  declare namespace FeatureFlags {
33
34
  var propTypes: {
34
35
  children: PropTypes.Requireable<PropTypes.ReactNodeLike>;
@@ -32,7 +32,8 @@ function FeatureFlags({
32
32
  enableExperimentalFocusWrapWithoutSentinels = false,
33
33
  enableDialogElement = false,
34
34
  enableV12DynamicFloatingStyles = false,
35
- enableEnhancedFileUploader = false
35
+ enableEnhancedFileUploader = false,
36
+ enablePresence = false
36
37
  }) {
37
38
  const parentScope = useContext(FeatureFlagContext);
38
39
  const [prevParentScope, setPrevParentScope] = useState(parentScope);
@@ -45,6 +46,7 @@ function FeatureFlags({
45
46
  'enable-dialog-element': enableDialogElement,
46
47
  'enable-v12-dynamic-floating-styles': enableV12DynamicFloatingStyles,
47
48
  'enable-enhanced-file-uploader': enableEnhancedFileUploader,
49
+ 'enable-presence': enablePresence,
48
50
  ...flags
49
51
  };
50
52
  const [scope, updateScope] = useState(() => {
@@ -15,10 +15,10 @@ import { ButtonKinds } from '../Button/Button.js';
15
15
  import { Enter, Space } from '../../internal/keyboard/keys.js';
16
16
  import { matches } from '../../internal/keyboard/match.js';
17
17
  import { usePrefix } from '../../internal/usePrefix.js';
18
- import '../Text/index.js';
18
+ import { Text } from '../Text/Text.js';
19
+ import '../Text/TextDirection.js';
19
20
  import { useId } from '../../internal/useId.js';
20
21
  import { useFeatureFlag } from '../FeatureFlags/index.js';
21
- import { Text } from '../Text/Text.js';
22
22
 
23
23
  // eslint-disable-next-line react/display-name -- https://github.com/carbon-design-system/carbon/issues/20071
24
24
  const FileUploader = /*#__PURE__*/React.forwardRef(({
@@ -15,10 +15,10 @@ import { matches } from '../../internal/keyboard/match.js';
15
15
  import { useId } from '../../internal/useId.js';
16
16
  import { usePrefix } from '../../internal/usePrefix.js';
17
17
  import { noopFn } from '../../internal/noopFn.js';
18
- import '../Text/index.js';
18
+ import { Text } from '../Text/Text.js';
19
+ import '../Text/TextDirection.js';
19
20
  import '../Tooltip/DefinitionTooltip.js';
20
21
  import { Tooltip } from '../Tooltip/Tooltip.js';
21
- import { Text } from '../Text/Text.js';
22
22
 
23
23
  function FileUploaderItem({
24
24
  uuid,
@@ -5,13 +5,30 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
+ import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
8
9
  import PropTypes from 'prop-types';
9
- import 'react';
10
- import 'classnames';
10
+ import React from 'react';
11
+ import cx from 'classnames';
11
12
  import '../TextInput/ControlledPasswordInput.js';
12
- import '../TextInput/PasswordInput.js';
13
+ import PasswordInput from '../TextInput/PasswordInput.js';
14
+ import { usePrefix } from '../../internal/usePrefix.js';
15
+ import { FormContext } from '../FluidForm/FormContext.js';
13
16
 
14
- ({
17
+ const FluidPasswordInput = ({
18
+ className,
19
+ ...other
20
+ }) => {
21
+ const prefix = usePrefix();
22
+ const classNames = cx(className, `${prefix}--text-input--fluid`);
23
+ return /*#__PURE__*/React.createElement(FormContext.Provider, {
24
+ value: {
25
+ isFluid: true
26
+ }
27
+ }, /*#__PURE__*/React.createElement(PasswordInput, _extends({
28
+ className: classNames
29
+ }, other)));
30
+ };
31
+ FluidPasswordInput.propTypes = {
15
32
  /**
16
33
  * Specify an optional className to be applied to the outer FluidForm wrapper
17
34
  */
@@ -88,4 +105,6 @@ import '../TextInput/PasswordInput.js';
88
105
  * Whether or not the component is readonly
89
106
  */
90
107
  readOnly: PropTypes.bool
91
- });
108
+ };
109
+
110
+ export { FluidPasswordInput as default };
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import FluidTextInput from './FluidTextInput.js';
9
- import './FluidPasswordInput.js';
9
+ export { default as FluidPasswordInput } from './FluidPasswordInput.js';
10
10
  export { default as FluidTextInputSkeleton } from './FluidTextInput.Skeleton.js';
11
11
 
12
12
 
@@ -10,8 +10,8 @@ import PropTypes from 'prop-types';
10
10
  import React from 'react';
11
11
  import cx from 'classnames';
12
12
  import { usePrefix } from '../../internal/usePrefix.js';
13
- import '../Text/index.js';
14
13
  import { Text } from '../Text/Text.js';
14
+ import '../Text/TextDirection.js';
15
15
 
16
16
  function FormLabel({
17
17
  className: customClassName,
@@ -5,7 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import React, { type HTMLAttributes } from 'react';
8
- import { type ListBoxSize, type ListBoxType } from '.';
8
+ import { type ListBoxSize, type ListBoxType } from './ListBoxPropTypes';
9
9
  type ExcludedAttributes = 'onKeyDown' | 'onKeyPress' | 'ref';
10
10
  export interface ListBoxProps extends Omit<HTMLAttributes<HTMLDivElement>, ExcludedAttributes> {
11
11
  /**
@@ -10,11 +10,10 @@ import cx from 'classnames';
10
10
  import React, { forwardRef, useContext } from 'react';
11
11
  import PropTypes from 'prop-types';
12
12
  import { deprecate } from '../../prop-types/deprecate.js';
13
- import './index.js';
13
+ import { ListBoxTypePropType, ListBoxSizePropType } from './ListBoxPropTypes.js';
14
14
  import { usePrefix } from '../../internal/usePrefix.js';
15
15
  import '../FluidForm/FluidForm.js';
16
16
  import { FormContext } from '../FluidForm/FormContext.js';
17
- import { ListBoxTypePropType, ListBoxSizePropType } from './ListBoxPropTypes.js';
18
17
 
19
18
  const handleOnKeyDown = event => {
20
19
  if (event.keyCode === 27) {
@@ -10,8 +10,8 @@ import PropTypes from 'prop-types';
10
10
  import React from 'react';
11
11
  import cx from 'classnames';
12
12
  import { usePrefix } from '../../internal/usePrefix.js';
13
- import '../Text/index.js';
14
13
  import { Text } from '../Text/Text.js';
14
+ import '../Text/TextDirection.js';
15
15
 
16
16
  function ListItem({
17
17
  className,
@@ -20,9 +20,9 @@ import { Menu } from './Menu.js';
20
20
  import { MenuContext } from './MenuContext.js';
21
21
  import '../LayoutDirection/LayoutDirection.js';
22
22
  import { useLayoutDirection } from '../LayoutDirection/useLayoutDirection.js';
23
- import '../Text/index.js';
24
- import { defaultItemToString } from '../../internal/defaultItemToString.js';
25
23
  import { Text } from '../Text/Text.js';
24
+ import '../Text/TextDirection.js';
25
+ import { defaultItemToString } from '../../internal/defaultItemToString.js';
26
26
 
27
27
  var _Checkmark, _CaretLeft, _CaretRight;
28
28
  const MenuItem = /*#__PURE__*/forwardRef(function MenuItem({
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright IBM Corp. 2023
2
+ * Copyright IBM Corp. 2023, 2025
3
3
  *
4
4
  * This source code is licensed under the Apache-2.0 license found in the
5
5
  * LICENSE file in the root directory of this source tree.
@@ -34,7 +34,7 @@ export interface MenuButtonProps extends ComponentProps<'div'> {
34
34
  /**
35
35
  * Specify the size of the button and menu.
36
36
  */
37
- size?: 'sm' | 'md' | 'lg';
37
+ size?: 'xs' | 'sm' | 'md' | 'lg';
38
38
  /**
39
39
  * Specify the tabIndex of the button.
40
40
  */
@@ -19,7 +19,7 @@ import { useId } from '../../internal/useId.js';
19
19
  import { usePrefix } from '../../internal/usePrefix.js';
20
20
  import { flip, size, useFloating, autoUpdate } from '@floating-ui/react';
21
21
  import { useFeatureFlag } from '../FeatureFlags/index.js';
22
- import mergeRefs from '../../tools/mergeRefs.js';
22
+ import { mergeRefs } from '../../tools/mergeRefs.js';
23
23
 
24
24
  const validButtonKinds = ['primary', 'tertiary', 'ghost'];
25
25
  const defaultButtonKind = 'primary';
@@ -177,7 +177,7 @@ MenuButton.propTypes = {
177
177
  */
178
178
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- https://github.com/carbon-design-system/carbon/issues/20071
179
179
  // @ts-ignore-next-line -- avoid spurious (?) TS2322 error
180
- size: PropTypes.oneOf(['sm', 'md', 'lg']),
180
+ size: PropTypes.oneOf(['xs', 'sm', 'md', 'lg']),
181
181
  /**
182
182
  * Specify the tabIndex of the button.
183
183
  */
@@ -7,7 +7,7 @@
7
7
 
8
8
  import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
9
9
  import PropTypes from 'prop-types';
10
- import React, { useRef, useState, useEffect, cloneElement } from 'react';
10
+ import React, { useContext, useRef, useState, useEffect, cloneElement } from 'react';
11
11
  import cx from 'classnames';
12
12
  import { Close } from '@carbon/icons-react';
13
13
  import { toggleClass } from '../../tools/toggleClass.js';
@@ -20,13 +20,15 @@ import { requiredIfGivenPropIsTruthy } from '../../prop-types/requiredIfGivenPro
20
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
+ import { useMergedRefs } from '../../internal/useMergedRefs.js';
23
24
  import { usePrefix } from '../../internal/usePrefix.js';
24
25
  import { usePreviousValue } from '../../internal/usePreviousValue.js';
25
26
  import { Escape, Enter, Tab } from '../../internal/keyboard/keys.js';
26
27
  import { match } from '../../internal/keyboard/match.js';
27
28
  import { IconButton } from '../IconButton/index.js';
28
29
  import { noopFn } from '../../internal/noopFn.js';
29
- import '../Text/index.js';
30
+ import { Text } from '../Text/Text.js';
31
+ import '../Text/TextDirection.js';
30
32
  import { useFeatureFlag } from '../FeatureFlags/index.js';
31
33
  import { composeEventHandlers } from '../../tools/events.js';
32
34
  import { deprecate } from '../../prop-types/deprecate.js';
@@ -34,12 +36,40 @@ import { Dialog } from '../Dialog/Dialog.js';
34
36
  import { AILabel } from '../AILabel/index.js';
35
37
  import { isComponentElement } from '../../internal/utils.js';
36
38
  import { warning } from '../../internal/warning.js';
39
+ import { ModalPresenceContext, useExclusiveModalPresenceContext, ModalPresence } from './ModalPresence.js';
37
40
  import { debounce } from '../../node_modules/es-toolkit/dist/compat/function/debounce.js';
38
- import { Text } from '../Text/Text.js';
39
41
 
40
42
  const ModalSizes = ['xs', 'sm', 'md', 'lg'];
41
43
  const invalidOutsideClickMessage = '`<Modal>` prop `preventCloseOnClickOutside` should not be `false` when ' + '`passiveModal` is `false`. Transactional, non-passive Modals should ' + 'not be dissmissable by clicking outside. ' + 'See: https://carbondesignsystem.com/components/modal/usage/#transactional-modal';
42
44
  const Modal = /*#__PURE__*/React.forwardRef(function Modal({
45
+ open,
46
+ ...props
47
+ }, ref) {
48
+ const id = useId();
49
+ const enablePresence = useFeatureFlag('enable-presence');
50
+ const hasPresenceContext = Boolean(useContext(ModalPresenceContext));
51
+ const hasPresenceOptIn = enablePresence || hasPresenceContext;
52
+ const exclusivePresenceContext = useExclusiveModalPresenceContext(id);
53
+
54
+ // if opt in and not exclusive to a presence context, wrap with presence
55
+ if (hasPresenceOptIn && !exclusivePresenceContext) {
56
+ return /*#__PURE__*/React.createElement(ModalPresence, {
57
+ open: open ?? false,
58
+ _presenceId: id
59
+ // do not auto enable styles for opt-in by feature flag
60
+ ,
61
+ _autoEnablePresence: hasPresenceContext
62
+ }, /*#__PURE__*/React.createElement(ModalDialog, _extends({
63
+ open: true,
64
+ ref: ref
65
+ }, props)));
66
+ }
67
+ return /*#__PURE__*/React.createElement(ModalDialog, _extends({
68
+ ref: ref,
69
+ open: open
70
+ }, props));
71
+ });
72
+ const ModalDialog = /*#__PURE__*/React.forwardRef(function ModalDialog({
43
73
  'aria-label': ariaLabelProp,
44
74
  children,
45
75
  className,
@@ -50,7 +80,7 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
50
80
  passiveModal = false,
51
81
  secondaryButtonText,
52
82
  primaryButtonText,
53
- open,
83
+ open: externalOpen,
54
84
  onRequestClose = noopFn,
55
85
  onRequestSubmit = noopFn,
56
86
  onSecondarySubmit,
@@ -83,7 +113,6 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
83
113
  const endTrap = useRef(null);
84
114
  const wrapFocusTimeout = useRef(null);
85
115
  const [isScrollable, setIsScrollable] = useState(false);
86
- const prevOpen = usePreviousValue(open);
87
116
  const modalInstanceId = `modal-${useId()}`;
88
117
  const modalLabelId = `${prefix}--modal-header__label--${modalInstanceId}`;
89
118
  const modalHeadingId = `${prefix}--modal-header__heading--${modalInstanceId}`;
@@ -93,6 +122,13 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
93
122
  [`${prefix}--btn--loading`]: loadingStatus !== 'inactive'
94
123
  });
95
124
  const loadingActive = loadingStatus !== 'inactive';
125
+ const presenceContext = useContext(ModalPresenceContext);
126
+ const mergedRefs = useMergedRefs([ref, presenceContext?.presenceRef]);
127
+ const enablePresence = useFeatureFlag('enable-presence') || presenceContext?.autoEnablePresence;
128
+
129
+ // always mark as open when mounted with presence
130
+ const open = externalOpen || enablePresence;
131
+ const prevOpen = usePreviousValue(open);
96
132
  const focusTrapWithoutSentinels = useFeatureFlag('enable-experimental-focus-wrap-without-sentinels');
97
133
  const enableDialogElement = useFeatureFlag('enable-dialog-element');
98
134
  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;
@@ -188,7 +224,8 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
188
224
  const onSecondaryButtonClick = onSecondarySubmit ? onSecondarySubmit : onRequestClose;
189
225
  const modalClasses = cx(`${prefix}--modal`, {
190
226
  [`${prefix}--modal-tall`]: !passiveModal,
191
- 'is-visible': open,
227
+ 'is-visible': enablePresence || open,
228
+ [`${prefix}--modal--enable-presence`]: presenceContext?.autoEnablePresence,
192
229
  [`${prefix}--modal--danger`]: danger,
193
230
  [`${prefix}--modal--slug`]: slug,
194
231
  [`${prefix}--modal--decorator`]: decorator
@@ -252,14 +289,25 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
252
289
  }
253
290
  }, [open, prefix, enableDialogElement]);
254
291
  useEffect(() => {
255
- if (!enableDialogElement && prevOpen && !open && launcherButtonRef) {
292
+ if (!enableDialogElement && !enablePresence && prevOpen && !open && launcherButtonRef) {
256
293
  setTimeout(() => {
257
294
  if ('current' in launcherButtonRef) {
258
295
  launcherButtonRef.current?.focus();
259
296
  }
260
297
  });
261
298
  }
262
- }, [open, prevOpen, launcherButtonRef, enableDialogElement]);
299
+ }, [open, prevOpen, launcherButtonRef, enableDialogElement, enablePresence]);
300
+ // Focus launcherButtonRef on unmount
301
+ useEffect(() => {
302
+ const launcherButton = launcherButtonRef?.current;
303
+ return () => {
304
+ if (enablePresence && launcherButton) {
305
+ setTimeout(() => {
306
+ launcherButton.focus();
307
+ });
308
+ }
309
+ };
310
+ }, [enablePresence, launcherButtonRef]);
263
311
  useEffect(() => {
264
312
  if (!enableDialogElement) {
265
313
  const initialFocus = focusContainerElement => {
@@ -331,7 +379,8 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
331
379
  role: isAlertDialog ? 'alertdialog' : '',
332
380
  "aria-describedby": isAlertDialog ? modalBodyId : '',
333
381
  className: containerClasses,
334
- "aria-label": ariaLabel
382
+ "aria-label": ariaLabel,
383
+ "data-exiting": presenceContext?.isExiting || undefined
335
384
  }, /*#__PURE__*/React.createElement("div", {
336
385
  className: `${prefix}--modal-header`
337
386
  }, modalLabel && /*#__PURE__*/React.createElement(Text, {
@@ -458,7 +507,8 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
458
507
  onBlur: handleBlur,
459
508
  className: modalClasses,
460
509
  role: "presentation",
461
- ref: ref
510
+ ref: mergedRefs,
511
+ "data-exiting": presenceContext?.isExiting || undefined
462
512
  }), modalBody);
463
513
  });
464
514
  Modal.propTypes = {
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Copyright IBM Corp. 2016, 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, { type PropsWithChildren } from 'react';
8
+ import { type PresenceContext } from '../../internal/usePresenceContext';
9
+ export interface ModalPresenceProps {
10
+ /**
11
+ * Specify whether the Modal is currently open
12
+ */
13
+ open: boolean;
14
+ /**
15
+ * Internal property for backwards compatibility. Specify whether the Modal should opt in to presence mode.
16
+ */
17
+ _autoEnablePresence?: boolean;
18
+ /**
19
+ * Internal property to predefine the presence context's id for exclusivity.
20
+ */
21
+ _presenceId?: string;
22
+ }
23
+ export declare const ModalPresence: ({ open, _presenceId: presenceId, _autoEnablePresence: autoEnablePresence, children, }: PropsWithChildren<ModalPresenceProps>) => import("react/jsx-runtime").JSX.Element | null;
24
+ interface ModalPresenceContextProps extends PresenceContext {
25
+ autoEnablePresence: boolean;
26
+ }
27
+ export declare const ModalPresenceContext: React.Context<ModalPresenceContextProps | undefined>;
28
+ /**
29
+ * Handles occurrences where only a single modal must consume a context.
30
+ */
31
+ export declare const useExclusiveModalPresenceContext: (id: string) => ModalPresenceContextProps | undefined;
32
+ export {};
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Copyright IBM Corp. 2016, 2023
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import React, { createContext, useContext, useMemo } from 'react';
9
+ import { usePresenceContext } from '../../internal/usePresenceContext.js';
10
+
11
+ const ModalPresence = ({
12
+ open,
13
+ _presenceId: presenceId,
14
+ _autoEnablePresence: autoEnablePresence = true,
15
+ children
16
+ }) => {
17
+ const [isPresent, context] = usePresenceContext(open, presenceId);
18
+ const contextValue = useMemo(() => ({
19
+ autoEnablePresence,
20
+ ...context
21
+ }), [autoEnablePresence, context]);
22
+ if (!isPresent) return null;
23
+ return /*#__PURE__*/React.createElement(ModalPresenceContext.Provider, {
24
+ value: contextValue
25
+ }, children);
26
+ };
27
+ const ModalPresenceContext = /*#__PURE__*/createContext(undefined);
28
+
29
+ /**
30
+ * Handles occurrences where only a single modal must consume a context.
31
+ */
32
+ const useExclusiveModalPresenceContext = id => {
33
+ const ctx = useContext(ModalPresenceContext);
34
+ return ctx?.isPresenceExclusive(id) ? ctx : undefined;
35
+ };
36
+
37
+ export { ModalPresence, ModalPresenceContext, useExclusiveModalPresenceContext };
@@ -5,5 +5,6 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import Modal, { type ModalProps } from './Modal';
8
+ import { ModalPresence, type ModalPresenceProps } from './ModalPresence';
8
9
  export default Modal;
9
- export { Modal, type ModalProps };
10
+ export { Modal, ModalPresence, type ModalProps, type ModalPresenceProps };
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  import Modal from './Modal.js';
9
+ import 'react';
9
10
 
10
11
 
11
12
 
@@ -21,7 +21,7 @@ import ListBoxSelection from '../ListBox/next/ListBoxSelection.js';
21
21
  import ListBoxTrigger from '../ListBox/next/ListBoxTrigger.js';
22
22
  import { Space, Enter, Delete, Escape, Tab, Home, End } from '../../internal/keyboard/keys.js';
23
23
  import { match } from '../../internal/keyboard/match.js';
24
- import mergeRefs from '../../tools/mergeRefs.js';
24
+ import { mergeRefs } from '../../tools/mergeRefs.js';
25
25
  import { deprecate } from '../../prop-types/deprecate.js';
26
26
  import { useId } from '../../internal/useId.js';
27
27
  import { defaultSortItems, defaultCompareItems } from './tools/sorting.js';
@@ -629,8 +629,8 @@ const FilterableMultiSelect = /*#__PURE__*/forwardRef(function FilterableMultiSe
629
629
  // NOTE: does not prevent click
630
630
  evt.preventDefault();
631
631
  // focus on the element as per readonly input behavior
632
- if (mergedRef.current !== undefined) {
633
- mergedRef.current.focus();
632
+ if (textInput.current) {
633
+ textInput.current.focus();
634
634
  }
635
635
  },
636
636
  onKeyDown: evt => {
@@ -11,13 +11,13 @@ import cx from 'classnames';
11
11
  import { useSelect } from 'downshift';
12
12
  import isEqual from 'react-fast-compare';
13
13
  import PropTypes from 'prop-types';
14
- import React, { useMemo, useContext, useState, useLayoutEffect, isValidElement, useCallback, cloneElement } from 'react';
14
+ import React, { useMemo, useContext, useState, useLayoutEffect, useRef, isValidElement, useCallback, cloneElement } from 'react';
15
15
  import ListBox from '../ListBox/index.js';
16
16
  import { sortingPropTypes } from './MultiSelectPropTypes.js';
17
17
  import { defaultSortItems, defaultCompareItems } from './tools/sorting.js';
18
18
  import { useSelection } from '../../internal/Selection.js';
19
19
  import { useId } from '../../internal/useId.js';
20
- import mergeRefs from '../../tools/mergeRefs.js';
20
+ import { mergeRefs } from '../../tools/mergeRefs.js';
21
21
  import { deprecate } from '../../prop-types/deprecate.js';
22
22
  import { Delete, Escape, Space, ArrowDown, Enter } from '../../internal/keyboard/keys.js';
23
23
  import { match } from '../../internal/keyboard/match.js';
@@ -233,7 +233,8 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
233
233
  }
234
234
  }
235
235
  });
236
- const mergedRef = mergeRefs(toggleButtonProps.ref, ref);
236
+ const toggleButtonRef = useRef(null);
237
+ const mergedRef = mergeRefs(toggleButtonProps.ref, ref, toggleButtonRef);
237
238
  const selectedItems = selectedItem;
238
239
 
239
240
  /**
@@ -388,8 +389,8 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
388
389
  // NOTE: does not prevent click
389
390
  evt.preventDefault();
390
391
  // focus on the element as per readonly input behavior
391
- if (mergedRef.current !== undefined) {
392
- mergedRef.current.focus();
392
+ if (toggleButtonRef.current) {
393
+ toggleButtonRef.current.focus();
393
394
  }
394
395
  },
395
396
  onKeyDown: evt => {
@@ -11,7 +11,8 @@ import React, { useState, useRef, useEffect } from 'react';
11
11
  import { deprecate } from '../../prop-types/deprecate.js';
12
12
  import cx from 'classnames';
13
13
  import { Close, InformationSquareFilled, InformationFilled, WarningAltFilled, WarningFilled, CheckmarkFilled, ErrorFilled } from '@carbon/icons-react';
14
- import '../Text/index.js';
14
+ import { Text } from '../Text/Text.js';
15
+ import '../Text/TextDirection.js';
15
16
  import Button from '../Button/Button.js';
16
17
  import '../Button/Button.Skeleton.js';
17
18
  import useIsomorphicEffect from '../../internal/useIsomorphicEffect.js';
@@ -25,7 +26,6 @@ import { wrapFocusWithoutSentinels, wrapFocus } from '../../internal/wrapFocus.j
25
26
  import { useFeatureFlag } from '../FeatureFlags/index.js';
26
27
  import { warning } from '../../internal/warning.js';
27
28
  import { deprecateValuesWithin } from '../../prop-types/deprecateValuesWithin.js';
28
- import { Text } from '../Text/Text.js';
29
29
 
30
30
  /**
31
31
  * Conditionally call a callback when the escape key is pressed
@@ -17,6 +17,26 @@ export declare const translationIds: {
17
17
  type TranslationKey = keyof typeof translationIds;
18
18
  type ExcludedAttributes = 'defaultValue' | 'id' | 'min' | 'max' | 'onChange' | 'onClick' | 'size' | 'step' | 'value';
19
19
  export interface NumberInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, ExcludedAttributes>, TranslateWithId<TranslationKey> {
20
+ /**
21
+ * Optional validation function that is called with the input value and locale.
22
+ * This is called before other validations, giving consumers the ability
23
+ * to short-circuit or extend validation without replacing built-in rules
24
+ * @example
25
+ * // Using the built-in separator validation
26
+ * <NumberInput validate={validateNumberSeparators} />
27
+ *
28
+ * // Combining with custom validation
29
+ * <NumberInput
30
+ * validate={(value, locale) => {
31
+ * return validateNumberSeparators(value, locale) && customValidation(value)
32
+ * }}
33
+ * />
34
+ * - Return `false` to immediately fail validation.
35
+ * - Return `true` to pass this validation, but still run other checks (min, max, required, etc.).
36
+ * - Return `undefined` to defer entirely to built-in validation logic.
37
+ *
38
+ */
39
+ validate?: (value: string, locale: string) => boolean | undefined;
20
40
  /**
21
41
  * `true` to allow empty string.
22
42
  */
@@ -186,16 +206,6 @@ export interface NumberInputProps extends Omit<React.InputHTMLAttributes<HTMLInp
186
206
  */
187
207
  warnText?: ReactNode;
188
208
  }
209
+ export declare const validateNumberSeparators: (input: string, locale: string) => boolean;
189
210
  declare const NumberInput: React.ForwardRefExoticComponent<NumberInputProps & React.RefAttributes<HTMLInputElement>>;
190
- export interface Label {
191
- disabled?: boolean;
192
- hideLabel?: boolean;
193
- id?: string;
194
- label?: ReactNode;
195
- }
196
- export interface HelperTextProps {
197
- id?: string;
198
- description?: ReactNode;
199
- disabled?: boolean;
200
- }
201
211
  export { NumberInput };