@carbon/react 1.111.0 → 1.112.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 (37) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +960 -1001
  2. package/es/components/ComboBox/ComboBox.js +7 -7
  3. package/es/components/Dropdown/Dropdown.js +1 -4
  4. package/es/components/FeatureFlags/index.js +32 -14
  5. package/es/components/IconIndicator/index.d.ts +33 -1
  6. package/es/components/IconIndicator/index.js +55 -26
  7. package/es/components/MultiSelect/FilterableMultiSelect.js +6 -7
  8. package/es/components/MultiSelect/MultiSelect.js +3 -4
  9. package/es/components/OverflowMenu/OverflowMenu.js +31 -6
  10. package/es/components/OverflowMenu/next/index.d.ts +1 -1
  11. package/es/components/OverflowMenu/next/index.js +2 -2
  12. package/es/components/ShapeIndicator/index.d.ts +18 -0
  13. package/es/components/ShapeIndicator/index.js +49 -7
  14. package/es/components/Tabs/Tabs.js +1 -1
  15. package/es/components/Tooltip/DefinitionTooltip.js +5 -2
  16. package/es/internal/index.d.ts +2 -1
  17. package/es/internal/isItemDisabled.d.ts +7 -0
  18. package/es/internal/isItemDisabled.js +17 -0
  19. package/lib/components/ComboBox/ComboBox.js +7 -7
  20. package/lib/components/Dropdown/Dropdown.js +2 -5
  21. package/lib/components/FeatureFlags/index.js +32 -14
  22. package/lib/components/IconIndicator/index.d.ts +33 -1
  23. package/lib/components/IconIndicator/index.js +54 -25
  24. package/lib/components/MultiSelect/FilterableMultiSelect.js +6 -7
  25. package/lib/components/MultiSelect/MultiSelect.js +3 -4
  26. package/lib/components/OverflowMenu/OverflowMenu.js +30 -5
  27. package/lib/components/OverflowMenu/next/index.d.ts +1 -1
  28. package/lib/components/OverflowMenu/next/index.js +2 -2
  29. package/lib/components/ShapeIndicator/index.d.ts +18 -0
  30. package/lib/components/ShapeIndicator/index.js +48 -6
  31. package/lib/components/Tabs/Tabs.js +1 -1
  32. package/lib/components/Tooltip/DefinitionTooltip.js +4 -1
  33. package/lib/internal/index.d.ts +2 -1
  34. package/lib/internal/isItemDisabled.d.ts +7 -0
  35. package/lib/internal/isItemDisabled.js +17 -0
  36. package/package.json +9 -8
  37. package/telemetry.yml +2 -0
@@ -12,6 +12,7 @@ import { match } from "../../internal/keyboard/match.js";
12
12
  import { useId } from "../../internal/useId.js";
13
13
  import { deprecate } from "../../prop-types/deprecate.js";
14
14
  import { defaultItemToString } from "../../internal/defaultItemToString.js";
15
+ import { isItemDisabled } from "../../internal/isItemDisabled.js";
15
16
  import { isComponentElement } from "../../internal/utils.js";
16
17
  import { useFeatureFlag } from "../FeatureFlags/index.js";
17
18
  import { useNormalizedInputProps } from "../../internal/useNormalizedInputProps.js";
@@ -39,7 +40,6 @@ import isEqual from "react-fast-compare";
39
40
  */
40
41
  const { InputBlur, InputKeyDownEnter, FunctionToggleMenu, ToggleButtonClick, ItemMouseMove, InputKeyDownArrowUp, InputKeyDownArrowDown, MenuMouseLeave, ItemClick, FunctionSelectItem } = useCombobox.stateChangeTypes;
41
42
  const defaultShouldFilterItem = () => true;
42
- const isDisabledItem = (item) => item !== null && typeof item === "object" && "disabled" in item && Boolean(item.disabled);
43
43
  const autocompleteCustomFilter = ({ item, inputValue }) => {
44
44
  if (inputValue === null || inputValue === "") return true;
45
45
  const lowercaseItem = item.toLowerCase();
@@ -56,7 +56,7 @@ const findHighlightedIndex = ({ items, itemToString = defaultItemToString }, inp
56
56
  const searchValue = inputValue.toLowerCase();
57
57
  for (let i = 0; i < items.length; i++) {
58
58
  const item = itemToString(items[i]).toLowerCase();
59
- if (!isDisabledItem(items[i]) && item.indexOf(searchValue) !== -1) return i;
59
+ if (!isItemDisabled(items[i]) && item.indexOf(searchValue) !== -1) return i;
60
60
  }
61
61
  return -1;
62
62
  };
@@ -99,7 +99,7 @@ const ComboBox = forwardRef((props, ref) => {
99
99
  useEffect(() => {
100
100
  if (typeahead) {
101
101
  if (inputValue.length >= prevInputLengthRef.current) if (inputValue) {
102
- const filteredItems = items.filter((item) => !isDisabledItem(item) && autocompleteCustomFilter({
102
+ const filteredItems = items.filter((item) => !isItemDisabled(item) && autocompleteCustomFilter({
103
103
  item: itemToString(item),
104
104
  inputValue
105
105
  }));
@@ -221,7 +221,7 @@ const ComboBox = forwardRef((props, ref) => {
221
221
  case InputKeyDownEnter:
222
222
  if (!allowCustomValue) if (state.highlightedIndex !== -1) {
223
223
  const highlightedItem = filterItems(items, itemToString, inputValue)[state.highlightedIndex];
224
- if (highlightedItem && !isDisabledItem(highlightedItem)) return {
224
+ if (highlightedItem && !isItemDisabled(highlightedItem)) return {
225
225
  ...changes,
226
226
  selectedItem: highlightedItem,
227
227
  inputValue: itemToString(highlightedItem)
@@ -230,7 +230,7 @@ const ComboBox = forwardRef((props, ref) => {
230
230
  const autoIndex = indexToHighlight(inputValue);
231
231
  if (autoIndex !== -1) {
232
232
  const matchingItem = items[autoIndex];
233
- if (matchingItem && !isDisabledItem(matchingItem)) return {
233
+ if (matchingItem && !isItemDisabled(matchingItem)) return {
234
234
  ...changes,
235
235
  selectedItem: matchingItem,
236
236
  inputValue: itemToString(matchingItem)
@@ -352,7 +352,7 @@ const ComboBox = forwardRef((props, ref) => {
352
352
  initialSelectedItem,
353
353
  inputId: id,
354
354
  stateReducer,
355
- isItemDisabled: isDisabledItem,
355
+ isItemDisabled,
356
356
  ...downshiftProps,
357
357
  onStateChange: ({ type, selectedItem: newSelectedItem }) => {
358
358
  if (isManualClearingRef.current || isSyncingControlledSelectionRef.current) {
@@ -539,7 +539,7 @@ const ComboBox = forwardRef((props, ref) => {
539
539
  }
540
540
  if (typeahead && event.key === "Tab") {
541
541
  if (!isOpen) return;
542
- const matchingItem = items.find((item) => !isDisabledItem(item) && itemToString(item).toLowerCase().startsWith(inputValue.toLowerCase()));
542
+ const matchingItem = items.find((item) => !isItemDisabled(item) && itemToString(item).toLowerCase().startsWith(inputValue.toLowerCase()));
543
543
  if (matchingItem) {
544
544
  downshiftSetInputValue(itemToString(matchingItem));
545
545
  selectItem(matchingItem);
@@ -8,6 +8,7 @@
8
8
  import { usePrefix } from "../../internal/usePrefix.js";
9
9
  import { deprecate } from "../../prop-types/deprecate.js";
10
10
  import { defaultItemToString } from "../../internal/defaultItemToString.js";
11
+ import { isItemDisabled } from "../../internal/isItemDisabled.js";
11
12
  import { isComponentElement } from "../../internal/utils.js";
12
13
  import { useFeatureFlag } from "../FeatureFlags/index.js";
13
14
  import { useNormalizedInputProps } from "../../internal/useNormalizedInputProps.js";
@@ -99,9 +100,6 @@ const Dropdown = React.forwardRef(({ autoAlign = false, className: containerClas
99
100
  const onSelectedItemChange = useCallback(({ selectedItem }) => {
100
101
  if (onChange) onChange({ selectedItem: selectedItem ?? null });
101
102
  }, [onChange]);
102
- const isItemDisabled = useCallback((item) => {
103
- return item !== null && typeof item === "object" && "disabled" in item && item.disabled === true;
104
- }, []);
105
103
  const onHighlightedIndexChange = useCallback((changes) => {
106
104
  const { highlightedIndex } = changes;
107
105
  if (highlightedIndex !== void 0 && highlightedIndex > -1) {
@@ -128,7 +126,6 @@ const Dropdown = React.forwardRef(({ autoAlign = false, className: containerClas
128
126
  initialSelectedItem,
129
127
  onSelectedItemChange,
130
128
  stateReducer,
131
- isItemDisabled,
132
129
  onHighlightedIndexChange,
133
130
  downshiftProps
134
131
  ]);
@@ -22,27 +22,45 @@ import { jsx } from "react/jsx-runtime";
22
22
  * or disable feature flags in a given React tree
23
23
  */
24
24
  const FeatureFlagContext = createContext(FeatureFlags);
25
+ const PROP_TO_FLAG = {
26
+ enableV12TileDefaultIcons: "enable-v12-tile-default-icons",
27
+ enableV12TileRadioIcons: "enable-v12-tile-radio-icons",
28
+ enableV12Overflowmenu: "enable-v12-overflowmenu",
29
+ enableTreeviewControllable: "enable-treeview-controllable",
30
+ enableExperimentalFocusWrapWithoutSentinels: "enable-experimental-focus-wrap-without-sentinels",
31
+ enableFocusWrapWithoutSentinels: "enable-focus-wrap-without-sentinels",
32
+ enableDialogElement: "enable-dialog-element",
33
+ enableV12DynamicFloatingStyles: "enable-v12-dynamic-floating-styles",
34
+ enableEnhancedFileUploader: "enable-enhanced-file-uploader",
35
+ enablePresence: "enable-presence"
36
+ };
25
37
  /**
26
38
  * Supports an object of feature flag values with the `flags` prop, merging them
27
39
  * along with the current `FeatureFlagContext` to provide consumers to check if
28
40
  * a feature flag is enabled or disabled in a given React tree
29
41
  */
30
- const FeatureFlags$1 = ({ children, flags = {}, enableV12TileDefaultIcons = false, enableV12TileRadioIcons = false, enableV12Overflowmenu = false, enableTreeviewControllable = false, enableExperimentalFocusWrapWithoutSentinels = false, enableFocusWrapWithoutSentinels = false, enableDialogElement = false, enableV12DynamicFloatingStyles = false, enableEnhancedFileUploader = false, enablePresence = false }) => {
42
+ const FeatureFlags$1 = ({ children, flags, enableV12TileDefaultIcons, enableV12TileRadioIcons, enableV12Overflowmenu, enableTreeviewControllable, enableExperimentalFocusWrapWithoutSentinels, enableFocusWrapWithoutSentinels, enableDialogElement, enableV12DynamicFloatingStyles, enableEnhancedFileUploader, enablePresence }) => {
31
43
  const parentScope = useContext(FeatureFlagContext);
32
44
  const scope = useMemo(() => {
33
- const scope = createScope({
34
- "enable-v12-tile-default-icons": enableV12TileDefaultIcons,
35
- "enable-v12-tile-radio-icons": enableV12TileRadioIcons,
36
- "enable-v12-overflowmenu": enableV12Overflowmenu,
37
- "enable-treeview-controllable": enableTreeviewControllable,
38
- "enable-experimental-focus-wrap-without-sentinels": enableExperimentalFocusWrapWithoutSentinels,
39
- "enable-focus-wrap-without-sentinels": enableFocusWrapWithoutSentinels,
40
- "enable-dialog-element": enableDialogElement,
41
- "enable-v12-dynamic-floating-styles": enableV12DynamicFloatingStyles,
42
- "enable-enhanced-file-uploader": enableEnhancedFileUploader,
43
- "enable-presence": enablePresence,
44
- ...flags
45
- });
45
+ const flagProps = {
46
+ enableV12TileDefaultIcons,
47
+ enableV12TileRadioIcons,
48
+ enableV12Overflowmenu,
49
+ enableTreeviewControllable,
50
+ enableExperimentalFocusWrapWithoutSentinels,
51
+ enableFocusWrapWithoutSentinels,
52
+ enableDialogElement,
53
+ enableV12DynamicFloatingStyles,
54
+ enableEnhancedFileUploader,
55
+ enablePresence
56
+ };
57
+ const explicitFlags = {};
58
+ for (const [prop, flagKey] of Object.entries(PROP_TO_FLAG)) {
59
+ const value = flagProps[prop];
60
+ if (value !== void 0) explicitFlags[flagKey] = value;
61
+ }
62
+ if (flags) Object.assign(explicitFlags, flags);
63
+ const scope = createScope(explicitFlags);
46
64
  scope.mergeWithScope(parentScope);
47
65
  return scope;
48
66
  }, [
@@ -5,13 +5,45 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import React from 'react';
8
- export declare const IconIndicatorKinds: string[];
8
+ import { PopoverAlignment } from '../Popover';
9
+ declare const iconTypes: {
10
+ readonly failed: import("@carbon/icons-react").CarbonIconType;
11
+ readonly 'caution-major': import("@carbon/icons-react").CarbonIconType;
12
+ readonly 'caution-minor': import("@carbon/icons-react").CarbonIconType;
13
+ readonly undefined: import("@carbon/icons-react").CarbonIconType;
14
+ readonly succeeded: import("@carbon/icons-react").CarbonIconType;
15
+ readonly normal: import("@carbon/icons-react").CarbonIconType;
16
+ readonly 'in-progress': import("@carbon/icons-react").CarbonIconType;
17
+ readonly incomplete: import("@carbon/icons-react").CarbonIconType;
18
+ readonly 'not-started': import("@carbon/icons-react").CarbonIconType;
19
+ readonly pending: import("@carbon/icons-react").CarbonIconType;
20
+ readonly unknown: import("@carbon/icons-react").CarbonIconType;
21
+ readonly informative: import("@carbon/icons-react").CarbonIconType;
22
+ };
23
+ export declare const IconIndicatorKinds: (keyof typeof iconTypes)[];
9
24
  export type IconIndicatorKind = (typeof IconIndicatorKinds)[number];
10
25
  export interface IconIndicatorProps {
26
+ /**
27
+ * Specify how the tooltip should align with the icon in compact mode
28
+ */
29
+ align?: PopoverAlignment;
30
+ /**
31
+ * Will auto-align the tooltip in compact mode.
32
+ */
33
+ autoAlign?: boolean;
11
34
  /**
12
35
  * Specify an optional className to add.
13
36
  */
14
37
  className?: string;
38
+ /**
39
+ * When true, displays only the icon with the label in a tooltip
40
+ */
41
+ compact?: boolean;
42
+ /**
43
+ * Description for the icon announced to screen readers in compact mode.
44
+ * Defaults to `label` when not provided.
45
+ */
46
+ iconDescription?: string;
15
47
  /**
16
48
  * Specify the kind of icon to be used
17
49
  */
@@ -6,10 +6,11 @@
6
6
  */
7
7
 
8
8
  import { usePrefix } from "../../internal/usePrefix.js";
9
+ import { DefinitionTooltip } from "../Tooltip/DefinitionTooltip.js";
9
10
  import classNames from "classnames";
10
11
  import React from "react";
11
12
  import PropTypes from "prop-types";
12
- import { jsx, jsxs } from "react/jsx-runtime";
13
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
13
14
  import { CheckmarkFilled, CheckmarkOutline, CircleDash, ErrorFilled, InProgress, Incomplete, PendingFilled, UndefinedFilled, UnknownFilled, WarningAltFilled, WarningAltInvertedFilled, WarningSquareFilled } from "@carbon/icons-react";
14
15
  //#region src/components/IconIndicator/index.tsx
15
16
  /**
@@ -18,54 +19,82 @@ import { CheckmarkFilled, CheckmarkOutline, CircleDash, ErrorFilled, InProgress,
18
19
  * This source code is licensed under the Apache-2.0 license found in the
19
20
  * LICENSE file in the root directory of this source tree.
20
21
  */
21
- const IconIndicatorKinds = [
22
- "failed",
23
- "caution-major",
24
- "caution-minor",
25
- "undefined",
26
- "succeeded",
27
- "normal",
28
- "in-progress",
29
- "incomplete",
30
- "not-started",
31
- "pending",
32
- "unknown",
33
- "informative"
34
- ];
35
22
  const iconTypes = {
36
23
  failed: ErrorFilled,
37
- ["caution-major"]: WarningAltInvertedFilled,
38
- ["caution-minor"]: WarningAltFilled,
24
+ "caution-major": WarningAltInvertedFilled,
25
+ "caution-minor": WarningAltFilled,
39
26
  undefined: UndefinedFilled,
40
27
  succeeded: CheckmarkFilled,
41
28
  normal: CheckmarkOutline,
42
- ["in-progress"]: InProgress,
29
+ "in-progress": InProgress,
43
30
  incomplete: Incomplete,
44
- ["not-started"]: CircleDash,
31
+ "not-started": CircleDash,
45
32
  pending: PendingFilled,
46
33
  unknown: UnknownFilled,
47
34
  informative: WarningSquareFilled
48
35
  };
49
- const IconIndicator = React.forwardRef(({ className: customClassName, kind, label, size = 16 }, ref) => {
36
+ const IconIndicatorKinds = Object.keys(iconTypes);
37
+ const IconIndicator = React.forwardRef(({ align = "right", autoAlign = false, className: customClassName, compact = false, iconDescription, kind, label, size = 16 }, ref) => {
50
38
  const prefix = usePrefix();
51
- const classNames$1 = classNames(`${prefix}--icon-indicator`, customClassName, { [`${prefix}--icon-indicator--20`]: size == 20 });
39
+ const classNames$1 = classNames(`${prefix}--icon-indicator`, customClassName, { [`${prefix}--icon-indicator--20`]: size === 20 });
52
40
  const IconForKind = iconTypes[kind];
53
41
  if (!IconForKind) return null;
54
- return /* @__PURE__ */ jsxs("div", {
42
+ const iconElement = /* @__PURE__ */ jsx(IconForKind, {
43
+ size,
44
+ className: `${prefix}--icon-indicator--${kind}`
45
+ });
46
+ return /* @__PURE__ */ jsx("div", {
55
47
  className: classNames$1,
56
48
  ref,
57
- children: [/* @__PURE__ */ jsx(IconForKind, {
58
- size,
59
- className: `${prefix}--icon-indicator--${kind}`
60
- }), label]
49
+ children: compact ? /* @__PURE__ */ jsxs(DefinitionTooltip, {
50
+ align,
51
+ autoAlign,
52
+ openOnHover: true,
53
+ definition: label,
54
+ triggerClassName: `${prefix}--icon-indicator__button`,
55
+ children: [iconElement, /* @__PURE__ */ jsx("span", {
56
+ className: `${prefix}--visually-hidden`,
57
+ children: iconDescription ?? label
58
+ })]
59
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [iconElement, label] })
61
60
  });
62
61
  });
63
62
  IconIndicator.propTypes = {
63
+ /**
64
+ * Specify how the tooltip should align with the icon in compact mode
65
+ */
66
+ align: PropTypes.oneOf([
67
+ "top",
68
+ "top-start",
69
+ "top-end",
70
+ "bottom",
71
+ "bottom-start",
72
+ "bottom-end",
73
+ "left",
74
+ "left-start",
75
+ "left-end",
76
+ "right",
77
+ "right-start",
78
+ "right-end"
79
+ ]),
80
+ /**
81
+ * Will auto-align the tooltip in compact mode
82
+ */
83
+ autoAlign: PropTypes.bool,
64
84
  /**
65
85
  * Specify an optional className to add.
66
86
  */
67
87
  className: PropTypes.string,
68
88
  /**
89
+ * When true, displays only the icon with the label in a tooltip
90
+ */
91
+ compact: PropTypes.bool,
92
+ /**
93
+ * Description for the icon announced to screen readers in compact mode.
94
+ * Defaults to `label` when not provided.
95
+ */
96
+ iconDescription: PropTypes.string,
97
+ /**
69
98
  * Specify the kind of the Icon Indicator
70
99
  */
71
100
  kind: PropTypes.oneOf(IconIndicatorKinds).isRequired,
@@ -12,6 +12,7 @@ import useIsomorphicEffect from "../../internal/useIsomorphicEffect.js";
12
12
  import { useId } from "../../internal/useId.js";
13
13
  import { deprecate } from "../../prop-types/deprecate.js";
14
14
  import { defaultItemToString } from "../../internal/defaultItemToString.js";
15
+ import { isItemDisabled } from "../../internal/isItemDisabled.js";
15
16
  import { isComponentElement } from "../../internal/utils.js";
16
17
  import { hasHelperText } from "../../internal/hasHelperText.js";
17
18
  import { useNormalizedInputProps } from "../../internal/useNormalizedInputProps.js";
@@ -72,7 +73,7 @@ const FilterableMultiSelect = forwardRef(function FilterableMultiSelect({ autoAl
72
73
  filteredItems
73
74
  });
74
75
  const selectAllStatus = useMemo(() => {
75
- const selectable = nonSelectAllItems.filter((item) => !item.disabled);
76
+ const selectable = nonSelectAllItems.filter((item) => !isItemDisabled(item));
76
77
  const nonSelectedCount = selectable.filter((item) => !controlledSelectedItems.some((sel) => isEqual(sel, item))).length;
77
78
  const totalCount = selectable.length;
78
79
  return {
@@ -81,7 +82,7 @@ const FilterableMultiSelect = forwardRef(function FilterableMultiSelect({ autoAl
81
82
  };
82
83
  }, [controlledSelectedItems, nonSelectAllItems]);
83
84
  const handleSelectAllClick = useCallback(() => {
84
- const selectable = nonSelectAllItems.filter((i) => !i.disabled);
85
+ const selectable = nonSelectAllItems.filter((item) => !isItemDisabled(item));
85
86
  const { checked, indeterminate } = selectAllStatus;
86
87
  if (checked || indeterminate) toggleAll(controlledSelectedItems.filter((sel) => !filteredItems.some((e) => isEqual(e, sel))));
87
88
  else {
@@ -131,7 +132,7 @@ const FilterableMultiSelect = forwardRef(function FilterableMultiSelect({ autoAl
131
132
  }, [open]);
132
133
  const sortedItems = useMemo(() => {
133
134
  const selectAllItem = items.find(isSelectAllItem);
134
- const selectableRealItems = nonSelectAllItems.filter((item) => !item.disabled);
135
+ const selectableRealItems = nonSelectAllItems.filter((item) => !isItemDisabled(item));
135
136
  const sortedReal = sortItems(nonSelectAllItems, {
136
137
  selectedItems: {
137
138
  top: controlledSelectedItems,
@@ -255,9 +256,7 @@ const FilterableMultiSelect = forwardRef(function FilterableMultiSelect({ autoAl
255
256
  inputId,
256
257
  inputValue,
257
258
  stateReducer,
258
- isItemDisabled(item) {
259
- return item?.disabled;
260
- }
259
+ isItemDisabled
261
260
  });
262
261
  function stateReducer(state, actionAndChanges) {
263
262
  const { type, props, changes } = actionAndChanges;
@@ -266,7 +265,7 @@ const FilterableMultiSelect = forwardRef(function FilterableMultiSelect({ autoAl
266
265
  switch (type) {
267
266
  case InputKeyDownEnter:
268
267
  if (sortedItems.length === 0) return changes;
269
- if (changes.selectedItem && changes.selectedItem.disabled !== true) if (isSelectAllItem(changes.selectedItem)) handleSelectAllClick();
268
+ if (changes.selectedItem && !isItemDisabled(changes.selectedItem)) if (isSelectAllItem(changes.selectedItem)) handleSelectAllClick();
270
269
  else onItemChange(changes.selectedItem);
271
270
  setHighlightedIndex(changes.selectedItem);
272
271
  return {
@@ -13,6 +13,7 @@ import { useId } from "../../internal/useId.js";
13
13
  import { noopFn } from "../../internal/noopFn.js";
14
14
  import { deprecate } from "../../prop-types/deprecate.js";
15
15
  import { defaultItemToString } from "../../internal/defaultItemToString.js";
16
+ import { isItemDisabled } from "../../internal/isItemDisabled.js";
16
17
  import { isComponentElement } from "../../internal/utils.js";
17
18
  import { useFeatureFlag } from "../FeatureFlags/index.js";
18
19
  import { useNormalizedInputProps } from "../../internal/useNormalizedInputProps.js";
@@ -114,9 +115,7 @@ const MultiSelect = React.forwardRef(({ autoAlign = false, className: containerC
114
115
  },
115
116
  selectedItem: controlledSelectedItems,
116
117
  items: filteredItems,
117
- isItemDisabled(item) {
118
- return item?.disabled;
119
- },
118
+ isItemDisabled,
120
119
  ...downshiftProps
121
120
  });
122
121
  const toggleButtonProps = getToggleButtonProps({
@@ -298,7 +297,7 @@ const MultiSelect = React.forwardRef(({ autoAlign = false, className: containerC
298
297
  return {
299
298
  hasIndividualSelections: selectedItems.some((selected) => !isSelectAllItem(selected)),
300
299
  nonSelectAllSelectedCount: selectedItems.filter((selected) => !isSelectAllItem(selected)).length,
301
- totalSelectableCount: filteredItems.filter((item) => !isSelectAllItem(item) && !item.disabled).length
300
+ totalSelectableCount: filteredItems.filter((item) => !isSelectAllItem(item) && !isItemDisabled(item)).length
302
301
  };
303
302
  }, [selectedItems, filteredItems]);
304
303
  return /* @__PURE__ */ jsxs("div", {
@@ -18,7 +18,7 @@ import { mergeRefs } from "../../tools/mergeRefs.js";
18
18
  import { DIRECTION_BOTTOM, FloatingMenu } from "../../internal/FloatingMenu.js";
19
19
  import { useOutsideClick } from "../../internal/useOutsideClick.js";
20
20
  import classNames from "classnames";
21
- import React, { Children, cloneElement, forwardRef, isValidElement, useCallback, useContext, useEffect, useRef, useState } from "react";
21
+ import React, { Children, cloneElement, forwardRef, isValidElement, useCallback, useContext, useEffect, useReducer, useRef, useState } from "react";
22
22
  import PropTypes from "prop-types";
23
23
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
24
24
  import { OverflowMenuVertical } from "@carbon/icons-react";
@@ -81,7 +81,7 @@ const getMenuOffset = (menuBody, direction, trigger, flip) => {
81
81
  };
82
82
  }
83
83
  };
84
- const OverflowMenu = forwardRef(({ align, ["aria-label"]: ariaLabel = null, ariaLabel: deprecatedAriaLabel, children, className, direction = DIRECTION_BOTTOM, flipped = false, focusTrap = false, iconClass, iconDescription = "Options", id, light, menuOffset = getMenuOffset, menuOffsetFlip = getMenuOffset, menuOptionsClass, onClick = noopFn, onClose = noopFn, onOpen = noopFn, open: openProp, renderIcon: IconElement = OverflowMenuVertical, selectorPrimaryFocus = "[data-floating-menu-primary-focus]", size = "md", innerRef, ...other }, ref) => {
84
+ const OverflowMenu = forwardRef(({ align, ["aria-label"]: ariaLabel = null, ariaLabel: deprecatedAriaLabel, children, className, direction = DIRECTION_BOTTOM, flipped = false, focusTrap = false, iconClass, iconDescription = "Options", id, light, menuOffset = getMenuOffset, menuOffsetFlip = getMenuOffset, menuOptionsClass, onClick = noopFn, onClose = noopFn, onOpen = noopFn, open: openProp, renderIcon: IconElement = OverflowMenuVertical, selectorPrimaryFocus = "[data-floating-menu-primary-focus]", size, innerRef, ...other }, ref) => {
85
85
  const prefix = useContext(PrefixContext);
86
86
  const [open, setOpen] = useState(openProp ?? false);
87
87
  const [click, setClick] = useState(false);
@@ -96,6 +96,8 @@ const OverflowMenu = forwardRef(({ align, ["aria-label"]: ariaLabel = null, aria
96
96
  /** The element ref of the tooltip's trigger button. */
97
97
  const triggerRef = useRef(null);
98
98
  const wrapperRef = useRef(null);
99
+ const [, forceUpdate] = useReducer((x) => x + 1, 0);
100
+ const resizeObserverRef = useRef(null);
99
101
  useEffect(() => {
100
102
  if (prevOpenProp.current !== openProp) {
101
103
  setOpen(!!openProp);
@@ -105,6 +107,26 @@ const OverflowMenu = forwardRef(({ align, ["aria-label"]: ariaLabel = null, aria
105
107
  useEffect(() => {
106
108
  if (triggerRef.current) setHasMountedTrigger(true);
107
109
  }, []);
110
+ /**
111
+ * When `size` is brought in from a contextual layout token, FloatingMenu can't detect size changes
112
+ * while the menu is open since there is no state/prop update. This ResizeObserver watches
113
+ * the trigger button when the menu is open and calls `forceUpdate()` on resize to force a re-render if its
114
+ * size changes while the menu is open
115
+ */
116
+ useEffect(() => {
117
+ resizeObserverRef.current = new ResizeObserver(() => {
118
+ forceUpdate();
119
+ });
120
+ return () => {
121
+ resizeObserverRef.current?.disconnect();
122
+ resizeObserverRef.current = null;
123
+ };
124
+ }, []);
125
+ useEffect(() => {
126
+ if (!triggerRef.current || !resizeObserverRef.current) return;
127
+ if (open) resizeObserverRef.current.observe(triggerRef.current);
128
+ else resizeObserverRef.current.disconnect();
129
+ }, [open]);
108
130
  useEffect(() => {
109
131
  if (open && !prevOpenState.current) onOpen();
110
132
  else if (!open && prevOpenState.current) onClose();
@@ -205,22 +227,25 @@ const OverflowMenu = forwardRef(({ align, ["aria-label"]: ariaLabel = null, aria
205
227
  };
206
228
  const getTarget = () => {
207
229
  const triggerEl = triggerRef.current;
208
- if (triggerEl instanceof Element) return triggerEl.closest("[data-floating-menu-container]") || document.body;
230
+ if (triggerEl instanceof Element) return triggerEl.closest("[data-floating-menu-container]") || triggerEl.closest(`.${prefix}--layout`) || document.body;
209
231
  return document.body;
210
232
  };
211
233
  const menuBodyId = `overflow-menu-${instanceId.current}__menu-body`;
212
234
  const overflowMenuClasses = classNames(className, `${prefix}--overflow-menu`, {
213
235
  [`${prefix}--overflow-menu--open`]: open,
214
236
  [`${prefix}--overflow-menu--light`]: light,
215
- [`${prefix}--overflow-menu--${size}`]: size
237
+ [`${prefix}--overflow-menu--${size}`]: size,
238
+ [`${prefix}--layout--size-${size}`]: size
216
239
  });
217
240
  const overflowMenuOptionsClasses = classNames(menuOptionsClass, `${prefix}--overflow-menu-options`, {
218
241
  [`${prefix}--overflow-menu--flip`]: flipped,
219
242
  [`${prefix}--overflow-menu-options--open`]: open,
220
243
  [`${prefix}--overflow-menu-options--light`]: light,
221
- [`${prefix}--overflow-menu-options--${size}`]: size
244
+ [`${prefix}--overflow-menu-options--${size}`]: size,
245
+ [`${prefix}--layout--size-${size}`]: size
222
246
  });
223
247
  const overflowMenuIconClasses = classNames(`${prefix}--overflow-menu__icon`, iconClass);
248
+ const overflowMenuWrapperClasses = classNames(`${prefix}--overflow-menu__wrapper`);
224
249
  const childrenWithProps = Children.toArray(children).map((child, index) => {
225
250
  if (isValidElement(child)) {
226
251
  const childElement = child;
@@ -257,7 +282,7 @@ const OverflowMenu = forwardRef(({ align, ["aria-label"]: ariaLabel = null, aria
257
282
  });
258
283
  const combinedRef = innerRef ? mergeRefs(triggerRef, innerRef, ref) : mergeRefs(triggerRef, ref);
259
284
  return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs("span", {
260
- className: `${prefix}--overflow-menu__wrapper`,
285
+ className: overflowMenuWrapperClasses,
261
286
  "aria-owns": open ? menuBodyId : void 0,
262
287
  ref: wrapperRef,
263
288
  children: [/* @__PURE__ */ jsx(IconButton, {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright IBM Corp. 2020, 2025
2
+ * Copyright IBM Corp. 2020, 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.
@@ -22,7 +22,7 @@ import { OverflowMenuVertical } from "@carbon/icons-react";
22
22
  import { autoUpdate, flip, useFloating } from "@floating-ui/react";
23
23
  //#region src/components/OverflowMenu/next/index.tsx
24
24
  /**
25
- * Copyright IBM Corp. 2020, 2025
25
+ * Copyright IBM Corp. 2020, 2026
26
26
  *
27
27
  * This source code is licensed under the Apache-2.0 license found in the
28
28
  * LICENSE file in the root directory of this source tree.
@@ -67,7 +67,7 @@ const OverflowMenu = React.forwardRef(({ autoAlign = false, children, className,
67
67
  }
68
68
  const containerClasses = classNames(className, `${prefix}--overflow-menu__container`, { [`${prefix}--autoalign`]: enableFloatingStyles });
69
69
  const menuClasses = classNames(`${prefix}--overflow-menu__${menuAlignment}`);
70
- const triggerClasses = classNames(`${prefix}--overflow-menu`, { [`${prefix}--overflow-menu--open`]: open }, size !== defaultSize && `${prefix}--overflow-menu--${size}`);
70
+ const triggerClasses = classNames(`${prefix}--overflow-menu`, { [`${prefix}--overflow-menu--open`]: open }, size !== defaultSize && `${prefix}--overflow-menu--${size}`, size !== defaultSize && `${prefix}--layout--size-${size}`);
71
71
  const floatingRef = mergeRefs(triggerRef, refs.setReference);
72
72
  return /* @__PURE__ */ jsxs("div", {
73
73
  ...rest,
@@ -5,13 +5,26 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import React from 'react';
8
+ import { PopoverAlignment } from '../Popover';
8
9
  export declare const ShapeIndicatorKinds: string[];
9
10
  export type ShapeIndicatorKind = (typeof ShapeIndicatorKinds)[number];
10
11
  export interface ShapeIndicatorProps {
12
+ /**
13
+ * Specify how the tooltip should align with the shape in compact mode
14
+ */
15
+ align?: PopoverAlignment;
16
+ /**
17
+ * Will auto-align the tooltip in compact mode.
18
+ */
19
+ autoAlign?: boolean;
11
20
  /**
12
21
  * Specify an optional className to add.
13
22
  */
14
23
  className?: string;
24
+ /**
25
+ * When true, displays only the shape with the label in a tooltip
26
+ */
27
+ compact?: boolean;
15
28
  /**
16
29
  * Specify the kind of shape to be used
17
30
  */
@@ -20,6 +33,11 @@ export interface ShapeIndicatorProps {
20
33
  * Label next to the shape
21
34
  */
22
35
  label: string;
36
+ /**
37
+ * Description for the shape announced to screen readers in compact mode.
38
+ * Defaults to `label` when not provided.
39
+ */
40
+ shapeDescription?: string;
23
41
  /**
24
42
  * Specify the text size of the Shape Indicator. Defaults to 12.
25
43
  */
@@ -6,10 +6,11 @@
6
6
  */
7
7
 
8
8
  import { usePrefix } from "../../internal/usePrefix.js";
9
+ import { DefinitionTooltip } from "../Tooltip/DefinitionTooltip.js";
9
10
  import classNames from "classnames";
10
11
  import React from "react";
11
12
  import PropTypes from "prop-types";
12
- import { jsx, jsxs } from "react/jsx-runtime";
13
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
13
14
  import { Caution, CircleFill, CircleStroke, Critical, CriticalSeverity, DiamondFill, LowSeverity } from "@carbon/icons-react";
14
15
  //#region src/components/ShapeIndicator/index.tsx
15
16
  /**
@@ -61,26 +62,62 @@ const shapeTypes = {
61
62
  incomplete: incompleteIcon,
62
63
  draft: CircleStroke
63
64
  };
64
- const ShapeIndicator = React.forwardRef(({ className: customClassName, kind, label, textSize = 12 }, ref) => {
65
+ const ShapeIndicator = React.forwardRef(({ align = "right", autoAlign = false, className: customClassName, compact = false, kind, label, shapeDescription, textSize = 12 }, ref) => {
65
66
  const prefix = usePrefix();
66
67
  const classNames$1 = classNames(`${prefix}--shape-indicator`, customClassName, { [`${prefix}--shape-indicator--14`]: textSize == 14 });
67
68
  const ShapeForKind = shapeTypes[kind];
68
69
  if (!ShapeForKind) return null;
69
- return /* @__PURE__ */ jsxs("div", {
70
+ const shapeElement = /* @__PURE__ */ jsx(ShapeForKind, {
71
+ size: 16,
72
+ className: `${prefix}--shape-indicator--${kind}`
73
+ });
74
+ return /* @__PURE__ */ jsx("div", {
70
75
  className: classNames$1,
71
76
  ref,
72
- children: [/* @__PURE__ */ jsx(ShapeForKind, {
73
- size: 16,
74
- className: `${prefix}--shape-indicator--${kind}`
75
- }), label]
77
+ children: compact ? /* @__PURE__ */ jsxs(DefinitionTooltip, {
78
+ align,
79
+ autoAlign,
80
+ openOnHover: true,
81
+ definition: label,
82
+ triggerClassName: `${prefix}--shape-indicator__button`,
83
+ children: [shapeElement, /* @__PURE__ */ jsx("span", {
84
+ className: `${prefix}--visually-hidden`,
85
+ children: shapeDescription ?? label
86
+ })]
87
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [shapeElement, label] })
76
88
  });
77
89
  });
78
90
  ShapeIndicator.propTypes = {
91
+ /**
92
+ * Specify how the tooltip should align with the shape in compact mode
93
+ */
94
+ align: PropTypes.oneOf([
95
+ "top",
96
+ "top-start",
97
+ "top-end",
98
+ "bottom",
99
+ "bottom-start",
100
+ "bottom-end",
101
+ "left",
102
+ "left-start",
103
+ "left-end",
104
+ "right",
105
+ "right-start",
106
+ "right-end"
107
+ ]),
108
+ /**
109
+ * Will auto-align the tooltip in compact mode
110
+ */
111
+ autoAlign: PropTypes.bool,
79
112
  /**
80
113
  * Specify an optional className to add.
81
114
  */
82
115
  className: PropTypes.string,
83
116
  /**
117
+ * When true, displays only the shape with the label in a tooltip
118
+ */
119
+ compact: PropTypes.bool,
120
+ /**
84
121
  * Specify the kind of the Shape Indicator
85
122
  */
86
123
  kind: PropTypes.oneOf(ShapeIndicatorKinds).isRequired,
@@ -89,6 +126,11 @@ ShapeIndicator.propTypes = {
89
126
  */
90
127
  label: PropTypes.string.isRequired,
91
128
  /**
129
+ * Description for the shape announced to screen readers in compact mode.
130
+ * Defaults to `label` when not provided.
131
+ */
132
+ shapeDescription: PropTypes.string,
133
+ /**
92
134
  * Specify the text size of the Shape Indicator. Defaults to 12.
93
135
  */
94
136
  textSize: PropTypes.oneOf([12, 14])