@carbon/react 1.84.0-rc.0 → 1.85.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.
Files changed (177) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +943 -943
  2. package/es/components/AILabel/index.js +6 -1
  3. package/es/components/Checkbox/Checkbox.d.ts +2 -2
  4. package/es/components/Checkbox/Checkbox.js +8 -8
  5. package/es/components/CheckboxGroup/CheckboxGroup.d.ts +2 -2
  6. package/es/components/CheckboxGroup/CheckboxGroup.js +9 -8
  7. package/es/components/CodeSnippet/CodeSnippet.js +2 -4
  8. package/es/components/ComboBox/ComboBox.d.ts +1 -1
  9. package/es/components/ComboBox/ComboBox.js +8 -7
  10. package/es/components/ComposedModal/ComposedModal.d.ts +1 -1
  11. package/es/components/ComposedModal/ComposedModal.js +34 -12
  12. package/es/components/ContainedList/ContainedList.d.ts +1 -1
  13. package/es/components/ContainedList/ContainedList.js +4 -2
  14. package/es/components/ContentSwitcher/ContentSwitcher.js +6 -5
  15. package/es/components/DataTable/DataTable.js +3 -0
  16. package/es/components/DataTable/TableDecoratorRow.d.ts +2 -2
  17. package/es/components/DataTable/TableDecoratorRow.js +8 -8
  18. package/es/components/DataTable/TableExpandRow.d.ts +1 -1
  19. package/es/components/DataTable/TableExpandRow.js +15 -6
  20. package/es/components/DataTable/TableHeader.js +10 -10
  21. package/es/components/DataTable/TableRow.js +12 -4
  22. package/es/components/DataTable/tools/normalize.js +2 -1
  23. package/es/components/DatePickerInput/DatePickerInput.js +8 -7
  24. package/es/components/Dialog/index.d.ts +5 -1
  25. package/es/components/Dialog/index.js +20 -0
  26. package/es/components/Dropdown/Dropdown.d.ts +1 -1
  27. package/es/components/Dropdown/Dropdown.js +8 -10
  28. package/es/components/FileUploader/FileUploaderButton.js +2 -2
  29. package/es/components/FileUploader/FileUploaderDropContainer.js +2 -2
  30. package/es/components/FileUploader/FileUploaderItem.js +2 -2
  31. package/es/components/Layer/index.d.ts +1 -3
  32. package/es/components/Layer/index.js +9 -8
  33. package/es/components/Menu/Menu.js +0 -6
  34. package/es/components/Modal/Modal.d.ts +2 -2
  35. package/es/components/Modal/Modal.js +39 -11
  36. package/es/components/MultiSelect/FilterableMultiSelect.d.ts +1 -1
  37. package/es/components/MultiSelect/FilterableMultiSelect.js +29 -7
  38. package/es/components/MultiSelect/MultiSelect.d.ts +1 -1
  39. package/es/components/MultiSelect/MultiSelect.js +8 -7
  40. package/es/components/NumberInput/NumberInput.d.ts +1 -1
  41. package/es/components/NumberInput/NumberInput.js +9 -8
  42. package/es/components/OverflowMenu/OverflowMenu.js +4 -5
  43. package/es/components/PageHeader/PageHeader.d.ts +10 -9
  44. package/es/components/PageHeader/PageHeader.js +94 -34
  45. package/es/components/PageHeader/index.d.ts +2 -2
  46. package/es/components/PageHeader/index.js +1 -1
  47. package/es/components/Popover/index.js +2 -1
  48. package/es/components/RadioButton/RadioButton.d.ts +2 -2
  49. package/es/components/RadioButton/RadioButton.js +8 -8
  50. package/es/components/RadioButtonGroup/RadioButtonGroup.d.ts +2 -2
  51. package/es/components/RadioButtonGroup/RadioButtonGroup.js +9 -8
  52. package/es/components/RadioTile/RadioTile.d.ts +1 -1
  53. package/es/components/RadioTile/RadioTile.js +8 -7
  54. package/es/components/Search/Search.js +0 -1
  55. package/es/components/Select/Select.d.ts +2 -2
  56. package/es/components/Select/Select.js +8 -7
  57. package/es/components/Slider/Slider.js +6 -0
  58. package/es/components/Tag/DismissibleTag.d.ts +1 -1
  59. package/es/components/Tag/DismissibleTag.js +9 -8
  60. package/es/components/Tag/Tag.d.ts +1 -1
  61. package/es/components/Tag/Tag.js +9 -8
  62. package/es/components/TextArea/TextArea.js +12 -11
  63. package/es/components/TextInput/TextInput.d.ts +1 -1
  64. package/es/components/TextInput/TextInput.js +20 -9
  65. package/es/components/Tile/Tile.d.ts +2 -2
  66. package/es/components/Tile/Tile.js +30 -36
  67. package/es/components/TileGroup/TileGroup.d.ts +4 -4
  68. package/es/components/TileGroup/TileGroup.js +45 -53
  69. package/es/components/TileGroup/index.d.ts +3 -3
  70. package/es/components/Toggletip/index.js +2 -2
  71. package/es/components/Tooltip/DefinitionTooltip.js +1 -0
  72. package/es/components/TreeView/TreeNode.js +3 -3
  73. package/es/components/TreeView/TreeView.js +3 -3
  74. package/es/components/UIShell/Content.d.ts +5 -3
  75. package/es/components/UIShell/HeaderMenuItem.js +2 -1
  76. package/es/components/UIShell/HeaderPanel.d.ts +2 -2
  77. package/es/components/UIShell/HeaderPanel.js +9 -5
  78. package/es/index.js +1 -1
  79. package/es/internal/Selection.js +8 -3
  80. package/es/internal/environment.js +1 -12
  81. package/es/internal/{__mocks__/mockHTMLElement.d.ts → index.d.ts} +2 -4
  82. package/es/internal/useOverflowItems.d.ts +29 -0
  83. package/es/internal/useOverflowItems.js +122 -0
  84. package/es/internal/useResizeObserver.d.ts +1 -1
  85. package/es/internal/utils.d.ts +14 -0
  86. package/es/internal/utils.js +18 -0
  87. package/es/tools/uniqueId.d.ts +1 -6
  88. package/lib/components/AILabel/index.js +6 -1
  89. package/lib/components/Checkbox/Checkbox.d.ts +2 -2
  90. package/lib/components/Checkbox/Checkbox.js +7 -7
  91. package/lib/components/CheckboxGroup/CheckboxGroup.d.ts +2 -2
  92. package/lib/components/CheckboxGroup/CheckboxGroup.js +8 -7
  93. package/lib/components/CodeSnippet/CodeSnippet.js +2 -4
  94. package/lib/components/ComboBox/ComboBox.d.ts +1 -1
  95. package/lib/components/ComboBox/ComboBox.js +11 -10
  96. package/lib/components/ComposedModal/ComposedModal.d.ts +1 -1
  97. package/lib/components/ComposedModal/ComposedModal.js +35 -13
  98. package/lib/components/ContainedList/ContainedList.d.ts +1 -1
  99. package/lib/components/ContainedList/ContainedList.js +4 -2
  100. package/lib/components/ContentSwitcher/ContentSwitcher.js +5 -4
  101. package/lib/components/DataTable/DataTable.js +3 -0
  102. package/lib/components/DataTable/TableDecoratorRow.d.ts +2 -2
  103. package/lib/components/DataTable/TableDecoratorRow.js +8 -8
  104. package/lib/components/DataTable/TableExpandRow.d.ts +1 -1
  105. package/lib/components/DataTable/TableExpandRow.js +14 -5
  106. package/lib/components/DataTable/TableHeader.js +9 -9
  107. package/lib/components/DataTable/TableRow.js +11 -3
  108. package/lib/components/DataTable/tools/normalize.js +2 -1
  109. package/lib/components/DatePickerInput/DatePickerInput.js +7 -6
  110. package/lib/components/Dialog/index.d.ts +5 -1
  111. package/lib/components/Dialog/index.js +20 -0
  112. package/lib/components/Dropdown/Dropdown.d.ts +1 -1
  113. package/lib/components/Dropdown/Dropdown.js +12 -14
  114. package/lib/components/FileUploader/FileUploaderButton.js +2 -2
  115. package/lib/components/FileUploader/FileUploaderDropContainer.js +2 -2
  116. package/lib/components/FileUploader/FileUploaderItem.js +2 -2
  117. package/lib/components/Layer/index.d.ts +1 -3
  118. package/lib/components/Layer/index.js +9 -8
  119. package/lib/components/Menu/Menu.js +0 -6
  120. package/lib/components/Modal/Modal.d.ts +2 -2
  121. package/lib/components/Modal/Modal.js +47 -19
  122. package/lib/components/MultiSelect/FilterableMultiSelect.d.ts +1 -1
  123. package/lib/components/MultiSelect/FilterableMultiSelect.js +33 -11
  124. package/lib/components/MultiSelect/MultiSelect.d.ts +1 -1
  125. package/lib/components/MultiSelect/MultiSelect.js +13 -12
  126. package/lib/components/NumberInput/NumberInput.d.ts +1 -1
  127. package/lib/components/NumberInput/NumberInput.js +8 -7
  128. package/lib/components/OverflowMenu/OverflowMenu.js +4 -5
  129. package/lib/components/PageHeader/PageHeader.d.ts +10 -9
  130. package/lib/components/PageHeader/PageHeader.js +92 -34
  131. package/lib/components/PageHeader/index.d.ts +2 -2
  132. package/lib/components/PageHeader/index.js +0 -2
  133. package/lib/components/Popover/index.js +2 -1
  134. package/lib/components/RadioButton/RadioButton.d.ts +2 -2
  135. package/lib/components/RadioButton/RadioButton.js +7 -7
  136. package/lib/components/RadioButtonGroup/RadioButtonGroup.d.ts +2 -2
  137. package/lib/components/RadioButtonGroup/RadioButtonGroup.js +10 -9
  138. package/lib/components/RadioTile/RadioTile.d.ts +1 -1
  139. package/lib/components/RadioTile/RadioTile.js +7 -6
  140. package/lib/components/Search/Search.js +0 -1
  141. package/lib/components/Select/Select.d.ts +2 -2
  142. package/lib/components/Select/Select.js +7 -6
  143. package/lib/components/Slider/Slider.js +6 -0
  144. package/lib/components/Tag/DismissibleTag.d.ts +1 -1
  145. package/lib/components/Tag/DismissibleTag.js +8 -7
  146. package/lib/components/Tag/Tag.d.ts +1 -1
  147. package/lib/components/Tag/Tag.js +8 -7
  148. package/lib/components/TextArea/TextArea.js +11 -10
  149. package/lib/components/TextInput/TextInput.d.ts +1 -1
  150. package/lib/components/TextInput/TextInput.js +19 -8
  151. package/lib/components/Tile/Tile.d.ts +2 -2
  152. package/lib/components/Tile/Tile.js +29 -35
  153. package/lib/components/TileGroup/TileGroup.d.ts +4 -4
  154. package/lib/components/TileGroup/TileGroup.js +44 -52
  155. package/lib/components/TileGroup/index.d.ts +3 -3
  156. package/lib/components/Toggletip/index.js +2 -2
  157. package/lib/components/Tooltip/DefinitionTooltip.js +1 -0
  158. package/lib/components/TreeView/TreeNode.js +3 -3
  159. package/lib/components/TreeView/TreeView.js +3 -3
  160. package/lib/components/UIShell/Content.d.ts +5 -3
  161. package/lib/components/UIShell/HeaderMenuItem.js +2 -1
  162. package/lib/components/UIShell/HeaderPanel.d.ts +2 -2
  163. package/lib/components/UIShell/HeaderPanel.js +8 -4
  164. package/lib/index.js +1 -1
  165. package/lib/internal/Selection.js +8 -3
  166. package/lib/internal/environment.js +1 -12
  167. package/lib/internal/{__mocks__/mockHTMLElement.d.ts → index.d.ts} +2 -4
  168. package/lib/internal/useOverflowItems.d.ts +29 -0
  169. package/lib/internal/useOverflowItems.js +126 -0
  170. package/lib/internal/useResizeObserver.d.ts +1 -1
  171. package/lib/internal/utils.d.ts +14 -0
  172. package/lib/internal/utils.js +22 -0
  173. package/lib/tools/uniqueId.d.ts +1 -6
  174. package/package.json +14 -23
  175. package/telemetry.yml +3 -0
  176. package/es/tools/uniqueId.js +0 -14
  177. package/lib/tools/uniqueId.js +0 -18
@@ -35,6 +35,7 @@ const DialogContext = /*#__PURE__*/createContext({});
35
35
  const unstable__Dialog = /*#__PURE__*/React.forwardRef(({
36
36
  children,
37
37
  className,
38
+ focusAfterCloseRef,
38
39
  modal,
39
40
  onCancel = noopFn,
40
41
  onClick = noopFn,
@@ -93,6 +94,19 @@ const unstable__Dialog = /*#__PURE__*/React.forwardRef(({
93
94
  }
94
95
  }
95
96
  }, [modal, open]);
97
+ useEffect(() => {
98
+ if (!open && focusAfterCloseRef) {
99
+ // use setTimeout to ensure focus is set after all other default focus behavior
100
+ const moveFocus = setTimeout(() => {
101
+ focusAfterCloseRef.current?.focus();
102
+ });
103
+
104
+ //component did unmount equivalent
105
+ return () => {
106
+ clearTimeout(moveFocus);
107
+ };
108
+ }
109
+ }, [open, focusAfterCloseRef]);
96
110
  const containerClasses = cx(`${prefix}--dialog-container`);
97
111
  const contextValue = {
98
112
  dialogId,
@@ -138,6 +152,12 @@ unstable__Dialog.propTypes = {
138
152
  * Specify an optional className to be applied to the modal root node
139
153
  */
140
154
  className: PropTypes.string,
155
+ /**
156
+ * Provide a ref to return focus to once the dialog is closed.
157
+ */
158
+ focusAfterCloseRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({
159
+ current: PropTypes.any
160
+ })]),
141
161
  /**
142
162
  * Modal specifies whether the Dialog is modal or non-modal. This cannot be
143
163
  * changed while open=true
@@ -4,7 +4,7 @@
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.
6
6
  */
7
- import React, { Ref, type HTMLAttributes, type ReactNode } from 'react';
7
+ import React, { type HTMLAttributes, type ReactNode, type Ref } from 'react';
8
8
  import { UseSelectProps } from 'downshift';
9
9
  import { type ListBoxMenuIconTranslationKey, type ListBoxSize, type ListBoxType } from '../ListBox';
10
10
  import { TranslateWithId } from '../../types/common';
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
9
- import React, { useEffect, useContext, useCallback, useMemo, useState, isValidElement } from 'react';
9
+ import React, { useEffect, useContext, useCallback, useMemo, useState, isValidElement, cloneElement } from 'react';
10
10
  import { useSelect } from 'downshift';
11
11
  import cx from 'classnames';
12
12
  import PropTypes from 'prop-types';
@@ -20,6 +20,8 @@ import { FormContext } from '../FluidForm/FormContext.js';
20
20
  import { useId } from '../../internal/useId.js';
21
21
  import { useFloating, size, flip, hide, autoUpdate } from '@floating-ui/react';
22
22
  import { useFeatureFlag } from '../FeatureFlags/index.js';
23
+ import { AILabel } from '../AILabel/index.js';
24
+ import { isComponentElement } from '../../internal/utils.js';
23
25
  import { ListBoxSizePropType, ListBoxTypePropType } from '../ListBox/ListBoxPropTypes.js';
24
26
 
25
27
  const {
@@ -308,15 +310,11 @@ const Dropdown = /*#__PURE__*/React.forwardRef(({
308
310
  }), [autoAlign, getMenuProps, refs.setFloating, enableFloatingStyles]);
309
311
 
310
312
  // AILabel is always size `mini`
311
- const normalizedDecorator = useMemo(() => {
312
- let element = slug ?? decorator;
313
- if (element && element['type']?.displayName === 'AILabel') {
314
- return /*#__PURE__*/React.cloneElement(element, {
315
- size: 'mini'
316
- });
317
- }
318
- return /*#__PURE__*/React.isValidElement(element) ? element : null;
319
- }, [slug, decorator]);
313
+ const candidate = slug ?? decorator;
314
+ const candidateIsAILabel = isComponentElement(candidate, AILabel);
315
+ const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/cloneElement(candidate, {
316
+ size: 'mini'
317
+ }) : null;
320
318
  const allLabelProps = getLabelProps();
321
319
  const labelProps = /*#__PURE__*/isValidElement(titleText) ? {
322
320
  id: allLabelProps.id
@@ -11,7 +11,7 @@ import PropTypes from 'prop-types';
11
11
  import React, { useState, useRef } from 'react';
12
12
  import { Enter, Space } from '../../internal/keyboard/keys.js';
13
13
  import { matches } from '../../internal/keyboard/match.js';
14
- import { uniqueId } from '../../tools/uniqueId.js';
14
+ import { useId } from '../../internal/useId.js';
15
15
  import { usePrefix } from '../../internal/usePrefix.js';
16
16
  import deprecate from '../../prop-types/deprecate.js';
17
17
  import { noopFn } from '../../internal/noopFn.js';
@@ -39,7 +39,7 @@ function FileUploaderButton({
39
39
  const [prevOwnerLabelText, setPrevOwnerLabelText] = useState(ownerLabelText);
40
40
  const {
41
41
  current: inputId
42
- } = useRef(id || uniqueId());
42
+ } = useRef(id || useId());
43
43
  const inputNode = useRef(null);
44
44
  const classes = cx(`${prefix}--btn`, className, {
45
45
  [`${prefix}--btn--${buttonKind}`]: buttonKind,
@@ -11,7 +11,7 @@ import PropTypes from 'prop-types';
11
11
  import cx from 'classnames';
12
12
  import { Enter, Space } from '../../internal/keyboard/keys.js';
13
13
  import { matches } from '../../internal/keyboard/match.js';
14
- import { uniqueId } from '../../tools/uniqueId.js';
14
+ import { useId } from '../../internal/useId.js';
15
15
  import { usePrefix } from '../../internal/usePrefix.js';
16
16
  import { composeEventHandlers } from '../../tools/events.js';
17
17
  import deprecate from '../../prop-types/deprecate.js';
@@ -36,7 +36,7 @@ function FileUploaderDropContainer({
36
36
  const inputRef = useRef(null);
37
37
  const {
38
38
  current: uid
39
- } = useRef(id || uniqueId());
39
+ } = useRef(id || useId());
40
40
  const [isActive, setActive] = useState(false);
41
41
  const dropareaClasses = cx(`${prefix}--file__drop-container`, `${prefix}--file-browse-btn`, {
42
42
  [`${prefix}--file__drop-container--drag-over`]: isActive,
@@ -12,7 +12,7 @@ import React, { useRef, useState, useLayoutEffect } from 'react';
12
12
  import Filename from './Filename.js';
13
13
  import { Enter, Space } from '../../internal/keyboard/keys.js';
14
14
  import { matches } from '../../internal/keyboard/match.js';
15
- import { uniqueId } from '../../tools/uniqueId.js';
15
+ import { useId } from '../../internal/useId.js';
16
16
  import { usePrefix } from '../../internal/usePrefix.js';
17
17
  import { noopFn } from '../../internal/noopFn.js';
18
18
  import '../Text/index.js';
@@ -38,7 +38,7 @@ function FileUploaderItem({
38
38
  const prefix = usePrefix();
39
39
  const {
40
40
  current: id
41
- } = useRef(uuid || uniqueId());
41
+ } = useRef(uuid || useId());
42
42
  const classes = cx(`${prefix}--file__selected-file`, className, {
43
43
  [`${prefix}--file__selected-file--invalid`]: invalid,
44
44
  [`${prefix}--file__selected-file--md`]: size === 'md',
@@ -35,7 +35,5 @@ export interface LayerBaseProps {
35
35
  withBackground?: boolean;
36
36
  }
37
37
  export type LayerProps<T extends React.ElementType> = PolymorphicComponentPropWithRef<T, LayerBaseProps>;
38
- declare const Layer: React.ForwardRefExoticComponent<LayerBaseProps & {
39
- as?: React.ElementType;
40
- } & React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<any>>;
38
+ declare const Layer: React.ForwardRefExoticComponent<Omit<LayerProps<React.ElementType<any, keyof React.JSX.IntrinsicElements>>, "ref"> & React.RefAttributes<unknown>>;
41
39
  export { Layer };
@@ -25,14 +25,15 @@ function useLayer() {
25
25
  level
26
26
  };
27
27
  }
28
- const Layer = /*#__PURE__*/React.forwardRef(({
29
- as,
30
- className: customClassName,
31
- children,
32
- level: overrideLevel,
33
- withBackground = false,
34
- ...rest
35
- }, ref) => {
28
+ const Layer = /*#__PURE__*/React.forwardRef((props, ref) => {
29
+ const {
30
+ as,
31
+ className: customClassName,
32
+ children,
33
+ level: overrideLevel,
34
+ withBackground = false,
35
+ ...rest
36
+ } = props;
36
37
  const contextLevel = React.useContext(LayerContext);
37
38
  const level = overrideLevel ?? contextLevel;
38
39
  const prefix = usePrefix();
@@ -34,12 +34,6 @@ const Menu = /*#__PURE__*/forwardRef(function Menu({
34
34
  open,
35
35
  size = 'sm',
36
36
  legacyAutoalign = 'true',
37
- // TODO: `ssr-friendly` doesn't support ESLint v9.
38
- // https://github.com/kopiro/eslint-plugin-ssr-friendly/issues/30
39
- // https://github.com/carbon-design-system/carbon/issues/18991
40
- /*
41
- // eslint-disable-next-line ssr-friendly/no-dom-globals-in-react-fc
42
- */
43
37
  target = canUseDOM && document.body,
44
38
  x = 0,
45
39
  y = 0,
@@ -4,7 +4,7 @@
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.
6
6
  */
7
- import React, { type HTMLAttributes, type ReactNode, type Ref } from 'react';
7
+ import React, { type HTMLAttributes, type ReactNode, type RefObject } from 'react';
8
8
  import { InlineLoadingStatus } from '../InlineLoading/InlineLoading';
9
9
  export declare const ModalSizes: readonly ["xs", "sm", "md", "lg"];
10
10
  export type ModalSize = (typeof ModalSizes)[number];
@@ -57,7 +57,7 @@ export interface ModalProps extends HTMLAttributes<HTMLDivElement> {
57
57
  /**
58
58
  * Provide a ref to return focus to once the modal is closed.
59
59
  */
60
- launcherButtonRef?: Ref<HTMLButtonElement>;
60
+ launcherButtonRef?: RefObject<HTMLButtonElement | null>;
61
61
  /**
62
62
  * Specify the description for the loading text
63
63
  */
@@ -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 } from 'react';
10
+ import React, { 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';
@@ -31,11 +31,14 @@ import { useFeatureFlag } from '../FeatureFlags/index.js';
31
31
  import { composeEventHandlers } from '../../tools/events.js';
32
32
  import deprecate from '../../prop-types/deprecate.js';
33
33
  import { unstable__Dialog } from '../Dialog/index.js';
34
+ import { AILabel } from '../AILabel/index.js';
35
+ import { isComponentElement } from '../../internal/utils.js';
34
36
  import { warning } from '../../internal/warning.js';
35
37
  import { debounce } from '../../node_modules/es-toolkit/dist/compat/function/debounce.mjs.js';
36
38
  import { Text } from '../Text/Text.js';
37
39
 
38
40
  const ModalSizes = ['xs', 'sm', 'md', 'lg'];
41
+ const invalidOutsideClickMessage = '`Modal`: `preventCloseOnClickOutside` should not be `false` when `passiveModal` is `false`. Non-passive `Modal`s should not be dismissible by clicking outside.';
39
42
  const Modal = /*#__PURE__*/React.forwardRef(function Modal({
40
43
  'aria-label': ariaLabelProp,
41
44
  children,
@@ -61,7 +64,7 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
61
64
  size,
62
65
  hasScrollingContent = false,
63
66
  closeButtonLabel = 'Close',
64
- preventCloseOnClickOutside = false,
67
+ preventCloseOnClickOutside = !passiveModal,
65
68
  isFullWidth,
66
69
  launcherButtonRef,
67
70
  loadingStatus = 'inactive',
@@ -92,6 +95,9 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
92
95
  const focusTrapWithoutSentinels = useFeatureFlag('enable-experimental-focus-wrap-without-sentinels');
93
96
  const enableDialogElement = useFeatureFlag('enable-dialog-element');
94
97
  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;
98
+ if (!passiveModal && preventCloseOnClickOutside === false) {
99
+ console.error(invalidOutsideClickMessage);
100
+ }
95
101
  function isCloseButton(element) {
96
102
  return !onSecondarySubmit && element === secondaryButton.current || element.classList.contains(modalCloseButtonClass);
97
103
  }
@@ -129,7 +135,7 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
129
135
  target: oldActiveNode,
130
136
  relatedTarget: currentActiveNode
131
137
  }) {
132
- if (open && oldActiveNode instanceof HTMLElement && currentActiveNode instanceof HTMLElement) {
138
+ if (!enableDialogElement && open && oldActiveNode instanceof HTMLElement && currentActiveNode instanceof HTMLElement) {
133
139
  const {
134
140
  current: bodyNode
135
141
  } = innerModal;
@@ -148,6 +154,23 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
148
154
  selectorsFloatingMenus
149
155
  });
150
156
  }
157
+
158
+ // Adjust scroll if needed so that element with focus is not obscured by gradient
159
+ const modalContent = document.querySelector(`.${prefix}--modal-content`);
160
+ if (!modalContent || !modalContent.classList.contains(`${prefix}--modal-scroll-content`) || !currentActiveNode || !modalContent.contains(currentActiveNode)) {
161
+ return;
162
+ }
163
+ const lastContent = modalContent.children[modalContent.children.length - 1];
164
+ const gradientSpacing = modalContent.scrollHeight - lastContent.offsetTop - lastContent.clientHeight;
165
+ for (let elem of modalContent.children) {
166
+ if (elem.contains(currentActiveNode)) {
167
+ const spaceBelow = modalContent.clientHeight - elem.offsetTop + modalContent.scrollTop - elem.clientHeight;
168
+ if (spaceBelow < gradientSpacing) {
169
+ modalContent.scrollTop = modalContent.scrollTop + (gradientSpacing - spaceBelow);
170
+ }
171
+ break;
172
+ }
173
+ }
151
174
  }
152
175
  const onSecondaryButtonClick = onSecondarySubmit ? onSecondarySubmit : onRequestClose;
153
176
  const modalClasses = cx(`${prefix}--modal`, {
@@ -248,12 +271,11 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
248
271
  }, []);
249
272
 
250
273
  // AILabel always size `sm`
251
- let normalizedDecorator = /*#__PURE__*/React.isValidElement(slug ?? decorator) ? slug ?? decorator : null;
252
- if (normalizedDecorator && normalizedDecorator['type']?.displayName === 'AILabel') {
253
- normalizedDecorator = /*#__PURE__*/React.cloneElement(normalizedDecorator, {
254
- size: 'sm'
255
- });
256
- }
274
+ const candidate = slug ?? decorator;
275
+ const candidateIsAILabel = isComponentElement(candidate, AILabel);
276
+ const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/cloneElement(candidate, {
277
+ size: 'sm'
278
+ }) : null;
257
279
  const modalButton = /*#__PURE__*/React.createElement("div", {
258
280
  className: `${prefix}--modal-close-button`
259
281
  }, /*#__PURE__*/React.createElement(IconButton, {
@@ -275,6 +297,7 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
275
297
  const isAlertDialog = alert && !passiveModal;
276
298
  const modalBody = enableDialogElement ? /*#__PURE__*/React.createElement(unstable__Dialog, {
277
299
  open: open,
300
+ focusAfterCloseRef: launcherButtonRef,
278
301
  modal: true,
279
302
  ref: innerModal,
280
303
  role: isAlertDialog ? 'alertdialog' : '',
@@ -404,7 +427,7 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
404
427
  level: 0,
405
428
  onKeyDown: handleKeyDown,
406
429
  onClick: composeEventHandlers([rest?.onClick, handleOnClick]),
407
- onBlur: !enableDialogElement ? handleBlur : () => {},
430
+ onBlur: handleBlur,
408
431
  className: modalClasses,
409
432
  role: "presentation",
410
433
  ref: ref
@@ -521,7 +544,12 @@ Modal.propTypes = {
521
544
  /**
522
545
  * Prevent closing on click outside of modal
523
546
  */
524
- preventCloseOnClickOutside: PropTypes.bool,
547
+ preventCloseOnClickOutside: (props, propName) => {
548
+ if (!props.passiveModal && props[propName] === false) {
549
+ return new Error(invalidOutsideClickMessage);
550
+ }
551
+ return null;
552
+ },
525
553
  /**
526
554
  * Specify whether the Button should be disabled, or not
527
555
  */
@@ -5,7 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import { type UseComboboxProps, type UseMultipleSelectionProps } from 'downshift';
8
- import React, { ReactNode, FunctionComponent, ReactElement } from 'react';
8
+ import React, { type FunctionComponent, type ReactElement, type ReactNode } from 'react';
9
9
  import { type MultiSelectSortingProps } from './MultiSelectPropTypes';
10
10
  import { type ListBoxSize, type ListBoxType } from '../ListBox';
11
11
  import { TranslateWithId } from '../../types/common';
@@ -11,7 +11,7 @@ import cx from 'classnames';
11
11
  import Downshift, { useCombobox, useMultipleSelection } from 'downshift';
12
12
  import isEqual from 'react-fast-compare';
13
13
  import PropTypes from 'prop-types';
14
- import React, { forwardRef, useContext, useRef, useState, useLayoutEffect, useMemo, useEffect } from 'react';
14
+ import React, { forwardRef, useContext, useRef, useState, useLayoutEffect, useMemo, useEffect, cloneElement } from 'react';
15
15
  import { defaultFilterItems } from '../ComboBox/tools/filter.js';
16
16
  import { sortingPropTypes } from './MultiSelectPropTypes.js';
17
17
  import ListBox from '../ListBox/index.js';
@@ -29,6 +29,8 @@ import '../FluidForm/FluidForm.js';
29
29
  import { FormContext } from '../FluidForm/FormContext.js';
30
30
  import { useSelection } from '../../internal/Selection.js';
31
31
  import { useFloating, flip, size, hide, autoUpdate } from '@floating-ui/react';
32
+ import { AILabel } from '../AILabel/index.js';
33
+ import { isComponentElement } from '../../internal/utils.js';
32
34
  import { ListBoxSizePropType, ListBoxTypePropType } from '../ListBox/ListBoxPropTypes.js';
33
35
 
34
36
  const {
@@ -248,6 +250,27 @@ const FilterableMultiSelect = /*#__PURE__*/forwardRef(function FilterableMultiSe
248
250
  onMenuChange?.(isOpen);
249
251
  }
250
252
  }, [isOpen, onMenuChange, open]);
253
+ useEffect(() => {
254
+ const handleClickOutside = event => {
255
+ const target = event.target;
256
+ const wrapper = document.getElementById(id)?.closest(`.${prefix}--multi-select__wrapper`);
257
+
258
+ // If click is outside our component and menu is open or input is focused
259
+ if (wrapper && !wrapper.contains(target)) {
260
+ if (isOpen || inputFocused) {
261
+ setIsOpen(false);
262
+ setInputFocused(false);
263
+ setInputValue('');
264
+ }
265
+ }
266
+ };
267
+ if (inputFocused || isOpen) {
268
+ document.addEventListener('mousedown', handleClickOutside);
269
+ }
270
+ return () => {
271
+ document.removeEventListener('mousedown', handleClickOutside);
272
+ };
273
+ }, [isOpen, inputFocused]);
251
274
  const {
252
275
  getToggleButtonProps,
253
276
  getLabelProps,
@@ -423,12 +446,11 @@ const FilterableMultiSelect = /*#__PURE__*/forwardRef(function FilterableMultiSe
423
446
  }
424
447
 
425
448
  // AILabel always size `mini`
426
- let normalizedDecorator = /*#__PURE__*/React.isValidElement(slug ?? decorator) ? slug ?? decorator : null;
427
- if (normalizedDecorator && normalizedDecorator['type']?.displayName === 'AILabel') {
428
- normalizedDecorator = /*#__PURE__*/React.cloneElement(normalizedDecorator, {
429
- size: 'mini'
430
- });
431
- }
449
+ const candidate = slug ?? decorator;
450
+ const candidateIsAILabel = isComponentElement(candidate, AILabel);
451
+ const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/cloneElement(candidate, {
452
+ size: 'mini'
453
+ }) : null;
432
454
  const className = cx(`${prefix}--multi-select`, `${prefix}--combo-box`, `${prefix}--multi-select--filterable`, {
433
455
  [`${prefix}--multi-select--invalid`]: invalid,
434
456
  [`${prefix}--multi-select--invalid--focused`]: invalid && inputFocused,
@@ -5,7 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import { UseSelectProps } from 'downshift';
8
- import React, { ReactNode } from 'react';
8
+ import React, { type ReactNode } from 'react';
9
9
  import { type ListBoxSize, type ListBoxType } from '../ListBox';
10
10
  import { MultiSelectSortingProps } from './MultiSelectPropTypes';
11
11
  import { ListBoxProps } from '../ListBox/ListBox';
@@ -11,7 +11,7 @@ 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 } from 'react';
14
+ import React, { useMemo, useContext, useState, useLayoutEffect, 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';
@@ -29,6 +29,8 @@ import '../Checkbox/Checkbox.Skeleton.js';
29
29
  import { noopFn } from '../../internal/noopFn.js';
30
30
  import { useFloating, flip, size, hide, autoUpdate } from '@floating-ui/react';
31
31
  import { useFeatureFlag } from '../FeatureFlags/index.js';
32
+ import { AILabel } from '../AILabel/index.js';
33
+ import { isComponentElement } from '../../internal/utils.js';
32
34
  import { ListBoxSizePropType, ListBoxTypePropType } from '../ListBox/ListBoxPropTypes.js';
33
35
 
34
36
  const {
@@ -409,12 +411,11 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
409
411
  } : {};
410
412
 
411
413
  // AILabel always size `mini`
412
- let normalizedDecorator = /*#__PURE__*/React.isValidElement(slug ?? decorator) ? slug ?? decorator : null;
413
- if (normalizedDecorator && normalizedDecorator['type']?.displayName === 'AILabel') {
414
- normalizedDecorator = /*#__PURE__*/React.cloneElement(normalizedDecorator, {
415
- size: 'mini'
416
- });
417
- }
414
+ const candidate = slug ?? decorator;
415
+ const candidateIsAILabel = isComponentElement(candidate, AILabel);
416
+ const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/cloneElement(candidate, {
417
+ size: 'mini'
418
+ }) : null;
418
419
  const itemsSelectedText = selectedItems.length > 0 && selectedItems.map(item => item?.text);
419
420
  const selectedItemsLength = selectAll ? selectedItems.filter(item => !item.isSelectAll).length : selectedItems.length;
420
421
 
@@ -4,7 +4,7 @@
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.
6
6
  */
7
- import React, { ReactNode } from 'react';
7
+ import React, { type ReactNode } from 'react';
8
8
  import { TranslateWithId } from '../../types/common';
9
9
  import { type NumberFormatOptions } from '@carbon/utilities';
10
10
  export declare const translationIds: {
@@ -9,7 +9,7 @@ import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js
9
9
  import { Subtract, Add } from '@carbon/icons-react';
10
10
  import cx from 'classnames';
11
11
  import PropTypes from 'prop-types';
12
- import React, { useContext, useState, useMemo, useCallback, useRef, useEffect } from 'react';
12
+ import React, { useContext, useState, useMemo, useCallback, useRef, useEffect, cloneElement } from 'react';
13
13
  import { useMergedRefs } from '../../internal/useMergedRefs.js';
14
14
  import { useNormalizedInputProps } from '../../internal/useNormalizedInputProps.js';
15
15
  import { usePrefix } from '../../internal/usePrefix.js';
@@ -23,6 +23,8 @@ import { NumberParser, NumberFormatter } from '@carbon/utilities';
23
23
  import { ArrowUp, ArrowDown } from '../../internal/keyboard/keys.js';
24
24
  import { match } from '../../internal/keyboard/match.js';
25
25
  import { NumberFormatOptionsPropType } from './NumberFormatPropTypes.js';
26
+ import { AILabel } from '../AILabel/index.js';
27
+ import { isComponentElement } from '../../internal/utils.js';
26
28
  import { Text } from '../Text/Text.js';
27
29
 
28
30
  var _Subtract, _Add;
@@ -262,16 +264,15 @@ const NumberInput = /*#__PURE__*/React.forwardRef(function NumberInput(props, fo
262
264
  };
263
265
 
264
266
  // AILabel always size `mini`
265
- let normalizedDecorator = /*#__PURE__*/React.isValidElement(slug ?? decorator) ? slug ?? decorator : null;
266
- if (normalizedDecorator && normalizedDecorator['type']?.displayName === 'AILabel') {
267
- normalizedDecorator = /*#__PURE__*/React.cloneElement(normalizedDecorator, {
268
- size: 'mini'
269
- });
270
- }
267
+ const candidate = slug ?? decorator;
268
+ const candidateIsAILabel = isComponentElement(candidate, AILabel);
269
+ const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/cloneElement(candidate, {
270
+ size: 'mini'
271
+ }) : null;
271
272
 
272
273
  // Need to update the internal value when the revert button is clicked
273
274
  let isRevertActive;
274
- if (normalizedDecorator && normalizedDecorator['type']?.displayName === 'AILabel') {
275
+ if (normalizedDecorator?.type === AILabel) {
275
276
  isRevertActive = normalizedDecorator.props.revertActive;
276
277
  }
277
278
  useEffect(() => {
@@ -143,14 +143,14 @@ const OverflowMenu = /*#__PURE__*/forwardRef(({
143
143
  setHasMountedTrigger(true);
144
144
  }
145
145
  }, []);
146
-
147
- // Call `onClose` when menu closes.
148
146
  useEffect(() => {
149
- if (!open && prevOpenState.current) {
147
+ if (open && !prevOpenState.current) {
148
+ onOpen();
149
+ } else if (!open && prevOpenState.current) {
150
150
  onClose();
151
151
  }
152
152
  prevOpenState.current = open;
153
- }, [open, onClose]);
153
+ }, [open, onClose, onOpen]);
154
154
  useOutsideClick(wrapperRef, ({
155
155
  target
156
156
  }) => {
@@ -259,7 +259,6 @@ const OverflowMenu = /*#__PURE__*/forwardRef(({
259
259
  }
260
260
  }
261
261
  }, !hasFocusin);
262
- onOpen();
263
262
  };
264
263
  const getTarget = () => {
265
264
  const triggerEl = triggerRef.current;
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import React, { type ComponentType, type FunctionComponent } from 'react';
8
8
  import PropTypes from 'prop-types';
9
- import { Tabs as BaseTabs } from '../Tabs/Tabs';
9
+ import { TYPES } from '../Tag/Tag';
10
10
  /**
11
11
  * ----------
12
12
  * PageHeader
@@ -199,16 +199,18 @@ declare const PageHeaderHeroImage: {
199
199
  * PageHeaderTabBar
200
200
  * ----------------
201
201
  */
202
+ interface TagItem {
203
+ type: keyof typeof TYPES;
204
+ text: string;
205
+ size?: 'sm' | 'md' | 'lg';
206
+ id: string;
207
+ }
202
208
  interface PageHeaderTabBarProps {
203
209
  children?: React.ReactNode;
204
210
  className?: string;
211
+ tags?: TagItem[];
205
212
  }
206
213
  declare const PageHeaderTabBar: React.ForwardRefExoticComponent<PageHeaderTabBarProps & React.RefAttributes<HTMLDivElement>>;
207
- interface PageHeaderTabsProps extends React.ComponentProps<typeof BaseTabs> {
208
- children?: React.ReactNode;
209
- className?: string;
210
- }
211
- declare const PageHeaderTabs: React.ForwardRefExoticComponent<PageHeaderTabsProps & React.RefAttributes<HTMLDivElement>>;
212
214
  /**
213
215
  * -------
214
216
  * Exports
@@ -272,6 +274,5 @@ declare const HeroImage: {
272
274
  };
273
275
  };
274
276
  declare const TabBar: React.ForwardRefExoticComponent<PageHeaderTabBarProps & React.RefAttributes<HTMLDivElement>>;
275
- declare const Tabs: React.ForwardRefExoticComponent<PageHeaderTabsProps & React.RefAttributes<HTMLDivElement>>;
276
- export { PageHeader, PageHeaderBreadcrumbBar, PageHeaderContent, PageHeaderContentPageActions, PageHeaderContentText, PageHeaderHeroImage, PageHeaderTabBar, PageHeaderTabs, Root, BreadcrumbBar, Content, ContentPageActions, ContentText, HeroImage, TabBar, Tabs, };
277
- export type { PageHeaderProps, PageHeaderBreadcrumbBarProps, PageHeaderContentProps, PageHeaderContentPageActionsProps, PageHeaderContentTextProps, PageHeaderHeroImageProps, PageHeaderTabBarProps, PageHeaderTabsProps, };
277
+ export { PageHeader, PageHeaderBreadcrumbBar, PageHeaderContent, PageHeaderContentPageActions, PageHeaderContentText, PageHeaderHeroImage, PageHeaderTabBar, Root, BreadcrumbBar, Content, ContentPageActions, ContentText, HeroImage, TabBar, };
278
+ export type { PageHeaderProps, PageHeaderBreadcrumbBarProps, PageHeaderContentProps, PageHeaderContentPageActionsProps, PageHeaderContentTextProps, PageHeaderHeroImageProps, PageHeaderTabBarProps, };