@carbon/react 1.60.2 → 1.61.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 (34) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +972 -1013
  2. package/es/components/ComboBox/ComboBox.js +8 -8
  3. package/es/components/ComposedModal/ComposedModal.js +4 -2
  4. package/es/components/DatePicker/DatePicker.js +6 -1
  5. package/es/components/Dropdown/Dropdown.d.ts +4 -0
  6. package/es/components/Dropdown/Dropdown.js +53 -8
  7. package/es/components/Modal/Modal.js +4 -2
  8. package/es/components/MultiSelect/FilterableMultiSelect.d.ts +20 -14
  9. package/es/components/MultiSelect/FilterableMultiSelect.js +59 -8
  10. package/es/components/MultiSelect/MultiSelect.d.ts +7 -38
  11. package/es/components/MultiSelect/MultiSelect.js +52 -5
  12. package/es/components/MultiSelect/MultiSelectPropTypes.d.ts +19 -16
  13. package/es/components/OverflowMenu/OverflowMenu.js +0 -1
  14. package/es/components/OverflowMenu/next/index.d.ts +4 -0
  15. package/es/components/OverflowMenu/next/index.js +41 -2
  16. package/es/components/UIShell/HeaderContainer.d.ts +11 -9
  17. package/es/components/UIShell/HeaderContainer.js +9 -7
  18. package/lib/components/ComboBox/ComboBox.js +7 -7
  19. package/lib/components/ComposedModal/ComposedModal.js +6 -4
  20. package/lib/components/DatePicker/DatePicker.js +6 -1
  21. package/lib/components/Dropdown/Dropdown.d.ts +4 -0
  22. package/lib/components/Dropdown/Dropdown.js +49 -4
  23. package/lib/components/Modal/Modal.js +6 -4
  24. package/lib/components/MultiSelect/FilterableMultiSelect.d.ts +20 -14
  25. package/lib/components/MultiSelect/FilterableMultiSelect.js +56 -5
  26. package/lib/components/MultiSelect/MultiSelect.d.ts +7 -38
  27. package/lib/components/MultiSelect/MultiSelect.js +49 -2
  28. package/lib/components/MultiSelect/MultiSelectPropTypes.d.ts +19 -16
  29. package/lib/components/OverflowMenu/OverflowMenu.js +0 -1
  30. package/lib/components/OverflowMenu/next/index.d.ts +4 -0
  31. package/lib/components/OverflowMenu/next/index.js +40 -1
  32. package/lib/components/UIShell/HeaderContainer.d.ts +11 -9
  33. package/lib/components/UIShell/HeaderContainer.js +9 -7
  34. package/package.json +7 -7
@@ -6,8 +6,8 @@
6
6
  */
7
7
  import { type UseComboboxProps, type UseMultipleSelectionProps } from 'downshift';
8
8
  import { ReactNode, FunctionComponent, ReactElement } from 'react';
9
- import { type ItemBase, type SortingPropTypes } from './MultiSelectPropTypes';
10
- export interface FilterableMultiSelectProps<Item extends ItemBase> extends SortingPropTypes<Item> {
9
+ import { type MultiSelectSortingProps } from './MultiSelectPropTypes';
10
+ export interface FilterableMultiSelectProps<ItemType> extends MultiSelectSortingProps<ItemType> {
11
11
  /**
12
12
  * Specify a label to be read by screen readers on the container node
13
13
  * @deprecated
@@ -15,6 +15,12 @@ export interface FilterableMultiSelectProps<Item extends ItemBase> extends Sorti
15
15
  'aria-label'?: string;
16
16
  /** @deprecated */
17
17
  ariaLabel?: string;
18
+ /**
19
+ * **Experimental**: Will attempt to automatically align the floating
20
+ * element to avoid collisions with the viewport and being clipped by
21
+ * ancestor elements.
22
+ */
23
+ autoAlign?: boolean;
18
24
  className?: string;
19
25
  /**
20
26
  * Specify the text that should be read for screen readers that describes total items selected
@@ -35,14 +41,14 @@ export interface FilterableMultiSelectProps<Item extends ItemBase> extends Sorti
35
41
  /**
36
42
  * Additional props passed to Downshift
37
43
  */
38
- downshiftProps?: UseMultipleSelectionProps<Item>;
44
+ downshiftProps?: UseMultipleSelectionProps<ItemType>;
39
45
  /**
40
46
  * Default sorter is assigned if not provided.
41
47
  */
42
- filterItems(items: readonly Item[], extra: {
48
+ filterItems(items: readonly ItemType[], extra: {
43
49
  inputValue: string | null;
44
- itemToString: NonNullable<UseMultipleSelectionProps<Item>['itemToString']>;
45
- }): Item[];
50
+ itemToString: NonNullable<UseMultipleSelectionProps<ItemType>['itemToString']>;
51
+ }): ItemType[];
46
52
  /**
47
53
  * Specify whether the title text should be hidden or not
48
54
  */
@@ -60,7 +66,7 @@ export interface FilterableMultiSelectProps<Item extends ItemBase> extends Sorti
60
66
  * Allow users to pass in arbitrary items from their collection that are
61
67
  * pre-selected
62
68
  */
63
- initialSelectedItems?: Item[];
69
+ initialSelectedItems?: ItemType[];
64
70
  /**
65
71
  * Is the current selection invalid?
66
72
  */
@@ -73,7 +79,7 @@ export interface FilterableMultiSelectProps<Item extends ItemBase> extends Sorti
73
79
  * Function to render items as custom components instead of strings.
74
80
  * Defaults to null and is overridden by a getter
75
81
  */
76
- itemToElement?: FunctionComponent<Item>;
82
+ itemToElement?: FunctionComponent<ItemType>;
77
83
  /**
78
84
  * Helper function passed to downshift that allows the library to render
79
85
  * a given item to a string label.
@@ -81,12 +87,12 @@ export interface FilterableMultiSelectProps<Item extends ItemBase> extends Sorti
81
87
  * By default, it extracts the `label` field from a given item
82
88
  * to serve as the item label in the list.
83
89
  */
84
- itemToString?(item: Item | null): string;
90
+ itemToString?(item: ItemType | null): string;
85
91
  /**
86
92
  * We try to stay as generic as possible here to allow individuals to pass
87
93
  * in a collection of whatever kind of data structure they prefer
88
94
  */
89
- items: Item[];
95
+ items: ItemType[];
90
96
  /**
91
97
  * @deprecated `true` to use the light version.
92
98
  */
@@ -102,13 +108,13 @@ export interface FilterableMultiSelectProps<Item extends ItemBase> extends Sorti
102
108
  * consuming component what kind of internal state changes are occurring.
103
109
  */
104
110
  onChange?(changes: {
105
- selectedItems: Item[];
111
+ selectedItems: ItemType[];
106
112
  }): void;
107
113
  /**
108
114
  * A utility for this controlled component
109
115
  * to communicate to the currently typed input.
110
116
  */
111
- onInputValueChange?: UseComboboxProps<Item>['onInputValueChange'];
117
+ onInputValueChange?: UseComboboxProps<ItemType>['onInputValueChange'];
112
118
  /**
113
119
  * `onMenuChange` is a utility for this controlled component to communicate to a
114
120
  * consuming component that the menu was opened(`true`)/closed(`false`).
@@ -133,7 +139,7 @@ export interface FilterableMultiSelectProps<Item extends ItemBase> extends Sorti
133
139
  /**
134
140
  * For full control of the selected items
135
141
  */
136
- selectedItems?: Item[];
142
+ selectedItems?: ItemType[];
137
143
  /**
138
144
  * Specify the size of the ListBox.
139
145
  * Currently, supports either `sm`, `md` or `lg` as an option.
@@ -167,7 +173,7 @@ export interface FilterableMultiSelectProps<Item extends ItemBase> extends Sorti
167
173
  warnText?: ReactNode;
168
174
  }
169
175
  declare const FilterableMultiSelect: {
170
- <Item extends ItemBase>(props: FilterableMultiSelectProps<Item>): ReactElement;
176
+ <ItemType>(props: FilterableMultiSelectProps<ItemType>): ReactElement;
171
177
  propTypes?: any;
172
178
  contextTypes?: any;
173
179
  defaultProps?: any;
@@ -28,6 +28,7 @@ var usePrefix = require('../../internal/usePrefix.js');
28
28
  require('../FluidForm/FluidForm.js');
29
29
  var FormContext = require('../FluidForm/FormContext.js');
30
30
  var Selection = require('../../internal/Selection.js');
31
+ var react = require('@floating-ui/react');
31
32
  var match = require('../../internal/keyboard/match.js');
32
33
  var ListBoxSelection = require('../ListBox/next/ListBoxSelection.js');
33
34
  var ListBoxTrigger = require('../ListBox/next/ListBoxTrigger.js');
@@ -65,6 +66,7 @@ const {
65
66
  } = Downshift.useMultipleSelection.stateChangeTypes;
66
67
  const FilterableMultiSelect = /*#__PURE__*/React__default["default"].forwardRef(function FilterableMultiSelect(_ref, ref) {
67
68
  let {
69
+ autoAlign = false,
68
70
  className: containerClassName,
69
71
  clearSelectionDescription = 'Total items selected: ',
70
72
  clearSelectionText = 'To clear selection, press Delete or Backspace',
@@ -121,6 +123,42 @@ const FilterableMultiSelect = /*#__PURE__*/React__default["default"].forwardRef(
121
123
  onChange,
122
124
  selectedItems: selected
123
125
  });
126
+ const {
127
+ refs,
128
+ floatingStyles,
129
+ middlewareData
130
+ } = react.useFloating(autoAlign ? {
131
+ placement: direction,
132
+ // The floating element is positioned relative to its nearest
133
+ // containing block (usually the viewport). It will in many cases also
134
+ // “break” the floating element out of a clipping ancestor.
135
+ // https://floating-ui.com/docs/misc#clipping
136
+ strategy: 'fixed',
137
+ // Middleware order matters, arrow should be last
138
+ middleware: [react.flip({
139
+ crossAxis: false
140
+ }), react.size({
141
+ apply(_ref2) {
142
+ let {
143
+ rects,
144
+ elements
145
+ } = _ref2;
146
+ Object.assign(elements.floating.style, {
147
+ width: `${rects.reference.width}px`
148
+ });
149
+ }
150
+ })],
151
+ whileElementsMounted: react.autoUpdate
152
+ } : {});
153
+ React.useLayoutEffect(() => {
154
+ if (autoAlign) {
155
+ Object.keys(floatingStyles).forEach(style => {
156
+ if (refs.floating.current) {
157
+ refs.floating.current.style[style] = floatingStyles[style];
158
+ }
159
+ });
160
+ }
161
+ }, [autoAlign, floatingStyles, refs.floating, middlewareData, open]);
124
162
  const textInput = React.useRef(null);
125
163
  const filterableMultiSelectInstanceId = useId.useId();
126
164
  const prefix = usePrefix.usePrefix();
@@ -128,6 +166,8 @@ const FilterableMultiSelect = /*#__PURE__*/React__default["default"].forwardRef(
128
166
  setIsOpen(open);
129
167
  setPrevOpen(open);
130
168
  }
169
+
170
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
131
171
  const sortedItems = sortItems(filterItems(items, {
132
172
  itemToString: itemToString$1,
133
173
  inputValue
@@ -243,8 +283,6 @@ const FilterableMultiSelect = /*#__PURE__*/React__default["default"].forwardRef(
243
283
  return changes;
244
284
  case InputBlur:
245
285
  case InputKeyDownEscape:
246
- setInputFocused(false);
247
- setInputValue('');
248
286
  setIsOpen(false);
249
287
  return changes;
250
288
  case FunctionToggleMenu:
@@ -428,7 +466,11 @@ const FilterableMultiSelect = /*#__PURE__*/React__default["default"].forwardRef(
428
466
  $input.setSelectionRange($value.length, $value.length);
429
467
  }
430
468
  },
431
- onFocus: () => setInputFocused(true)
469
+ onFocus: () => setInputFocused(true),
470
+ onBlur: () => {
471
+ !isOpen && setInputFocused(false);
472
+ setInputValue('');
473
+ }
432
474
  }));
433
475
  const menuProps = getMenuProps({}, {
434
476
  suppressRefError: true
@@ -465,7 +507,8 @@ const FilterableMultiSelect = /*#__PURE__*/React__default["default"].forwardRef(
465
507
  isOpen: isOpen,
466
508
  size: size
467
509
  }, /*#__PURE__*/React__default["default"].createElement("div", {
468
- className: `${prefix}--list-box__field`
510
+ className: `${prefix}--list-box__field`,
511
+ ref: refs.setReference
469
512
  }, controlledSelectedItems.length > 0 &&
470
513
  /*#__PURE__*/
471
514
  // @ts-expect-error: It is expecting a non-required prop called: "onClearSelection"
@@ -506,7 +549,9 @@ const FilterableMultiSelect = /*#__PURE__*/React__default["default"].forwardRef(
506
549
  // @ts-expect-error
507
550
  isOpen: isOpen,
508
551
  translateWithId: translateWithId
509
- }))), normalizedSlug, /*#__PURE__*/React__default["default"].createElement(index["default"].Menu, menuProps, isOpen ? sortedItems.map((item, index$1) => {
552
+ }))), normalizedSlug, /*#__PURE__*/React__default["default"].createElement(index["default"].Menu, _rollupPluginBabelHelpers["extends"]({}, menuProps, {
553
+ ref: refs.setFloating
554
+ }), isOpen ? sortedItems.map((item, index$1) => {
510
555
  const isChecked = controlledSelectedItems.filter(selected => isEqual__default["default"](selected, item)).length > 0;
511
556
  const itemProps = getItemProps({
512
557
  item,
@@ -554,6 +599,12 @@ FilterableMultiSelect.propTypes = {
554
599
  * Specify a label to be read by screen readers on the container note.
555
600
  */
556
601
  ariaLabel: deprecate["default"](PropTypes__default["default"].string, 'ariaLabel / aria-label props are no longer required for FilterableMultiSelect'),
602
+ /**
603
+ * **Experimental**: Will attempt to automatically align the floating
604
+ * element to avoid collisions with the viewport and being clipped by
605
+ * ancestor elements.
606
+ */
607
+ autoAlign: PropTypes__default["default"].bool,
557
608
  /**
558
609
  * Specify the text that should be read for screen readers that describes total items selected
559
610
  */
@@ -7,50 +7,19 @@
7
7
  import { UseSelectProps } from 'downshift';
8
8
  import React, { ReactNode } from 'react';
9
9
  import { ListBoxSize, ListBoxType } from '../ListBox';
10
+ import { MultiSelectSortingProps } from './MultiSelectPropTypes';
10
11
  import { ListBoxProps } from '../ListBox/ListBox';
11
12
  import type { InternationalProps } from '../../types/common';
12
- interface SharedOptions {
13
- locale: string;
14
- }
15
- interface DownshiftTypedProps<ItemType> {
16
- itemToString?(item: ItemType): string;
17
- }
18
- interface SortItemsOptions<ItemType> extends SharedOptions, DownshiftTypedProps<ItemType> {
19
- compareItems(item1: ItemType, item2: ItemType, options: SharedOptions): number;
20
- selectedItems: ItemType[];
21
- }
22
- interface MultiSelectSortingProps<ItemType> {
23
- /**
24
- * Provide a compare function that is used to determine the ordering of
25
- * options. See 'sortItems' for more control.
26
- */
27
- compareItems?(item1: ItemType, item2: ItemType, options: SharedOptions): number;
28
- /**
29
- * Provide a method that sorts all options in the control. Overriding this
30
- * prop means that you also have to handle the sort logic for selected versus
31
- * un-selected items. If you just want to control ordering, consider the
32
- * `compareItems` prop instead.
33
- *
34
- * The return value should be a number whose sign indicates the relative order
35
- * of the two elements: negative if a is less than b, positive if a is greater
36
- * than b, and zero if they are equal.
37
- *
38
- * sortItems :
39
- * (items: Array<Item>, {
40
- * selectedItems: Array<Item>,
41
- * itemToString: Item => string,
42
- * compareItems: (itemA: string, itemB: string, {
43
- * locale: string
44
- * }) => number,
45
- * locale: string,
46
- * }) => Array<Item>
47
- */
48
- sortItems?(items: ReadonlyArray<ItemType>, options: SortItemsOptions<ItemType>): ItemType[];
49
- }
50
13
  interface OnChangeData<ItemType> {
51
14
  selectedItems: ItemType[] | null;
52
15
  }
53
16
  export interface MultiSelectProps<ItemType> extends MultiSelectSortingProps<ItemType>, InternationalProps<'close.menu' | 'open.menu' | 'clear.all' | 'clear.selection'> {
17
+ /**
18
+ * **Experimental**: Will attempt to automatically align the floating
19
+ * element to avoid collisions with the viewport and being clipped by
20
+ * ancestor elements.
21
+ */
22
+ autoAlign?: boolean;
54
23
  className?: string;
55
24
  /**
56
25
  * Specify the text that should be read for screen readers that describes that all items are deleted
@@ -27,6 +27,7 @@ var usePrefix = require('../../internal/usePrefix.js');
27
27
  require('../FluidForm/FluidForm.js');
28
28
  var FormContext = require('../FluidForm/FormContext.js');
29
29
  var noopFn = require('../../internal/noopFn.js');
30
+ var react = require('@floating-ui/react');
30
31
  var match = require('../../internal/keyboard/match.js');
31
32
  var ListBoxPropTypes = require('../ListBox/ListBoxPropTypes.js');
32
33
  var keys = require('../../internal/keyboard/keys.js');
@@ -68,6 +69,7 @@ const defaultItemToString = item => {
68
69
  };
69
70
  const MultiSelect = /*#__PURE__*/React__default["default"].forwardRef((_ref, ref) => {
70
71
  let {
72
+ autoAlign = false,
71
73
  className: containerClassName,
72
74
  id,
73
75
  items,
@@ -127,6 +129,42 @@ const MultiSelect = /*#__PURE__*/React__default["default"].forwardRef((_ref, ref
127
129
  onChange,
128
130
  selectedItems: selected
129
131
  });
132
+ const {
133
+ refs,
134
+ floatingStyles,
135
+ middlewareData
136
+ } = react.useFloating(autoAlign ? {
137
+ placement: direction,
138
+ // The floating element is positioned relative to its nearest
139
+ // containing block (usually the viewport). It will in many cases also
140
+ // “break” the floating element out of a clipping ancestor.
141
+ // https://floating-ui.com/docs/misc#clipping
142
+ strategy: 'fixed',
143
+ // Middleware order matters, arrow should be last
144
+ middleware: [react.flip({
145
+ crossAxis: false
146
+ }), react.size({
147
+ apply(_ref2) {
148
+ let {
149
+ rects,
150
+ elements
151
+ } = _ref2;
152
+ Object.assign(elements.floating.style, {
153
+ width: `${rects.reference.width}px`
154
+ });
155
+ }
156
+ })],
157
+ whileElementsMounted: react.autoUpdate
158
+ } : {});
159
+ React.useLayoutEffect(() => {
160
+ if (autoAlign) {
161
+ Object.keys(floatingStyles).forEach(style => {
162
+ if (refs.floating.current) {
163
+ refs.floating.current.style[style] = floatingStyles[style];
164
+ }
165
+ });
166
+ }
167
+ }, [autoAlign, floatingStyles, refs.floating, middlewareData, open]);
130
168
 
131
169
  // Filter out items with an object having undefined values
132
170
  const filteredItems = React.useMemo(() => {
@@ -393,7 +431,8 @@ const MultiSelect = /*#__PURE__*/React__default["default"].forwardRef((_ref, ref
393
431
  }), showWarning && /*#__PURE__*/React__default["default"].createElement(iconsReact.WarningAltFilled, {
394
432
  className: `${prefix}--list-box__invalid-icon ${prefix}--list-box__invalid-icon--warning`
395
433
  }), /*#__PURE__*/React__default["default"].createElement("div", {
396
- className: multiSelectFieldWrapperClasses
434
+ className: multiSelectFieldWrapperClasses,
435
+ ref: refs.setReference
397
436
  }, selectedItems.length > 0 && /*#__PURE__*/React__default["default"].createElement(index["default"].Selection, {
398
437
  readOnly: readOnly,
399
438
  clearSelection: !disabled && !readOnly ? clearSelection : noopFn.noopFn,
@@ -416,7 +455,9 @@ const MultiSelect = /*#__PURE__*/React__default["default"].forwardRef((_ref, ref
416
455
  }, label), /*#__PURE__*/React__default["default"].createElement(index["default"].MenuIcon, {
417
456
  isOpen: isOpen,
418
457
  translateWithId: translateWithId
419
- })), normalizedSlug), /*#__PURE__*/React__default["default"].createElement(index["default"].Menu, getMenuProps(), isOpen &&
458
+ })), normalizedSlug), /*#__PURE__*/React__default["default"].createElement(index["default"].Menu, getMenuProps({
459
+ ref: refs.setFloating
460
+ }), isOpen &&
420
461
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
421
462
  sortItems(filteredItems, sortOptions).map((item, index$1) => {
422
463
  const isChecked = selectedItems.filter(selected => isEqual__default["default"](selected, item)).length > 0;
@@ -455,6 +496,12 @@ const MultiSelect = /*#__PURE__*/React__default["default"].forwardRef((_ref, ref
455
496
  MultiSelect.displayName = 'MultiSelect';
456
497
  MultiSelect.propTypes = {
457
498
  ...MultiSelectPropTypes.sortingPropTypes,
499
+ /**
500
+ * **Experimental**: Will attempt to automatically align the floating
501
+ * element to avoid collisions with the viewport and being clipped by
502
+ * ancestor elements.
503
+ */
504
+ autoAlign: PropTypes__default["default"].bool,
458
505
  /**
459
506
  * Provide a custom class name to be added to the outermost node in the
460
507
  * component
@@ -34,29 +34,32 @@ export declare const sortingPropTypes: {
34
34
  */
35
35
  sortItems: PropTypes.Requireable<(...args: any[]) => any>;
36
36
  };
37
- export interface ItemBase {
38
- disabled?: boolean;
37
+ interface DownshiftTypedProps<ItemType> {
38
+ itemToString?(item: ItemType): string;
39
39
  }
40
- export interface SortingPropTypes<Item extends ItemBase> {
40
+ interface SharedOptions {
41
+ locale: string;
42
+ }
43
+ export interface SortItemsOptions<ItemType> extends SharedOptions, DownshiftTypedProps<ItemType> {
44
+ compareItems(item1: ItemType, item2: ItemType, options: SharedOptions): number;
45
+ selectedItems: ItemType[];
46
+ }
47
+ export interface MultiSelectSortingProps<ItemType> {
41
48
  /**
42
- * Provide a compare function that is used
43
- * to determine the ordering of options.
49
+ * Provide a compare function that is used to determine the ordering of
50
+ * options. See 'sortItems' for more control.
44
51
  */
45
- compareItems(itemA: string, itemB: string, ctx: {
46
- locale: string;
47
- }): number;
52
+ compareItems?(item1: ItemType, item2: ItemType, options: SharedOptions): number;
48
53
  /**
49
54
  * Provide a method that sorts all options in the control. Overriding this
50
55
  * prop means that you also have to handle the sort logic for selected versus
51
56
  * un-selected items. If you just want to control ordering, consider the
52
57
  * `compareItems` prop instead.
58
+ *
59
+ * The return value should be a number whose sign indicates the relative order
60
+ * of the two elements: negative if a is less than b, positive if a is greater
61
+ * than b, and zero if they are equal.
53
62
  */
54
- sortItems(items: Item[], state: {
55
- selectedItems: Item[];
56
- itemToString(item: Item): string;
57
- compareItems(itemA: string, itemB: string, ctx: {
58
- locale: string;
59
- }): number;
60
- locale: string;
61
- }): Item[];
63
+ sortItems?(items: ReadonlyArray<ItemType>, options: SortItemsOptions<ItemType>): ItemType[];
62
64
  }
65
+ export {};
@@ -138,7 +138,6 @@ class OverflowMenu extends React__default["default"].Component {
138
138
  this.setState({
139
139
  click: true
140
140
  });
141
- evt.stopPropagation();
142
141
  if (!this._menuBody || !this._menuBody.contains(evt.target)) {
143
142
  this.setState({
144
143
  open: !this.state.open
@@ -6,6 +6,10 @@
6
6
  */
7
7
  import React, { type ComponentType, type FunctionComponent } from 'react';
8
8
  interface OverflowMenuProps {
9
+ /**
10
+ * **Experimental**: Will attempt to automatically align the floating element to avoid collisions with the viewport and being clipped by ancestor elements.
11
+ */
12
+ autoAlign?: boolean;
9
13
  /**
10
14
  * A collection of MenuItems to be rendered within this OverflowMenu.
11
15
  */
@@ -14,9 +14,11 @@ var React = require('react');
14
14
  var PropTypes = require('prop-types');
15
15
  var cx = require('classnames');
16
16
  var iconsReact = require('@carbon/icons-react');
17
+ var react = require('@floating-ui/react');
17
18
  var index = require('../../IconButton/index.js');
18
19
  var Menu = require('../../Menu/Menu.js');
19
20
  require('../../Menu/MenuItem.js');
21
+ var mergeRefs = require('../../../tools/mergeRefs.js');
20
22
  var useId = require('../../../internal/useId.js');
21
23
  var usePrefix = require('../../../internal/usePrefix.js');
22
24
  var useAttachedMenu = require('../../../internal/useAttachedMenu.js');
@@ -30,6 +32,7 @@ var cx__default = /*#__PURE__*/_interopDefaultLegacy(cx);
30
32
  const defaultSize = 'md';
31
33
  const OverflowMenu = /*#__PURE__*/React__default["default"].forwardRef(function OverflowMenu(_ref, forwardRef) {
32
34
  let {
35
+ autoAlign = false,
33
36
  children,
34
37
  className,
35
38
  label = 'Options',
@@ -39,6 +42,26 @@ const OverflowMenu = /*#__PURE__*/React__default["default"].forwardRef(function
39
42
  tooltipAlignment,
40
43
  ...rest
41
44
  } = _ref;
45
+ const {
46
+ refs,
47
+ floatingStyles,
48
+ placement,
49
+ middlewareData
50
+ } = react.useFloating(autoAlign ? {
51
+ placement: menuAlignment,
52
+ // The floating element is positioned relative to its nearest
53
+ // containing block (usually the viewport). It will in many cases also
54
+ // “break” the floating element out of a clipping ancestor.
55
+ // https://floating-ui.com/docs/misc#clipping
56
+ strategy: 'fixed',
57
+ // Middleware order matters, arrow should be last
58
+ middleware: [react.flip({
59
+ fallbackAxisSideDirection: 'start',
60
+ fallbackPlacements: ['top-start', 'top-end', 'bottom-start', 'bottom-end']
61
+ })],
62
+ whileElementsMounted: react.autoUpdate
63
+ } : {} // When autoAlign is turned off, floating-ui will not be used
64
+ );
42
65
  const id = useId.useId('overflowmenu');
43
66
  const prefix = usePrefix.usePrefix();
44
67
  const triggerRef = React.useRef(null);
@@ -50,6 +73,15 @@ const OverflowMenu = /*#__PURE__*/React__default["default"].forwardRef(function
50
73
  handleMousedown,
51
74
  handleClose
52
75
  } = useAttachedMenu.useAttachedMenu(triggerRef);
76
+ React.useEffect(() => {
77
+ if (autoAlign) {
78
+ Object.keys(floatingStyles).forEach(style => {
79
+ if (refs.floating.current) {
80
+ refs.floating.current.style[style] = floatingStyles[style];
81
+ }
82
+ });
83
+ }
84
+ }, [floatingStyles, autoAlign, refs.floating, open, placement, middlewareData]);
53
85
  function handleTriggerClick() {
54
86
  if (triggerRef.current) {
55
87
  hookOnClick();
@@ -60,6 +92,7 @@ const OverflowMenu = /*#__PURE__*/React__default["default"].forwardRef(function
60
92
  const triggerClasses = cx__default["default"](`${prefix}--overflow-menu`, {
61
93
  [`${prefix}--overflow-menu--open`]: open
62
94
  }, size !== defaultSize && `${prefix}--overflow-menu--${size}`);
95
+ const floatingRef = mergeRefs["default"](triggerRef, refs.setReference);
63
96
  return /*#__PURE__*/React__default["default"].createElement("div", _rollupPluginBabelHelpers["extends"]({}, rest, {
64
97
  className: containerClasses,
65
98
  "aria-owns": open ? id : undefined,
@@ -71,17 +104,19 @@ const OverflowMenu = /*#__PURE__*/React__default["default"].forwardRef(function
71
104
  className: triggerClasses,
72
105
  onClick: handleTriggerClick,
73
106
  onMouseDown: handleMousedown,
74
- ref: triggerRef,
107
+ ref: floatingRef,
75
108
  label: label,
76
109
  align: tooltipAlignment
77
110
  }, /*#__PURE__*/React__default["default"].createElement(IconElement, {
78
111
  className: `${prefix}--overflow-menu__icon`
79
112
  })), /*#__PURE__*/React__default["default"].createElement(Menu.Menu, {
80
113
  containerRef: triggerRef,
114
+ ref: refs.setFloating,
81
115
  menuAlignment: menuAlignment,
82
116
  className: menuClasses,
83
117
  id: id,
84
118
  size: size,
119
+ legacyAutoalign: !autoAlign,
85
120
  open: open,
86
121
  onClose: handleClose,
87
122
  x: x,
@@ -90,6 +125,10 @@ const OverflowMenu = /*#__PURE__*/React__default["default"].forwardRef(function
90
125
  }, children));
91
126
  });
92
127
  OverflowMenu.propTypes = {
128
+ /**
129
+ * **Experimental**: Will attempt to automatically align the floating element to avoid collisions with the viewport and being clipped by ancestor elements.
130
+ */
131
+ autoAlign: PropTypes__default["default"].bool,
93
132
  /**
94
133
  * A collection of MenuItems to be rendered within this OverflowMenu.
95
134
  */
@@ -6,15 +6,17 @@
6
6
  */
7
7
  import PropTypes from 'prop-types';
8
8
  import React from 'react';
9
- interface HeaderContainerRenderProps {
9
+ export interface HeaderContainerRenderProps {
10
10
  isSideNavExpanded: boolean;
11
11
  onClickSideNavExpand: () => void;
12
12
  }
13
- export interface HeaderContainerProps {
13
+ export type HeaderContainerProps<P extends HeaderContainerRenderProps> = {
14
14
  isSideNavExpanded?: boolean;
15
- render: React.ComponentType<HeaderContainerRenderProps>;
16
- }
17
- declare function HeaderContainer({ render: Children, isSideNavExpanded, }: HeaderContainerProps): import("react/jsx-runtime").JSX.Element;
15
+ render: React.ComponentType<P>;
16
+ } & {
17
+ [K in keyof Omit<P, keyof HeaderContainerRenderProps>]: P[K];
18
+ };
19
+ declare function HeaderContainer<P extends HeaderContainerRenderProps>({ render: Children, isSideNavExpanded, ...rest }: HeaderContainerProps<P>): import("react/jsx-runtime").JSX.Element;
18
20
  declare namespace HeaderContainer {
19
21
  var propTypes: {
20
22
  /**
@@ -22,10 +24,10 @@ declare namespace HeaderContainer {
22
24
  */
23
25
  isSideNavExpanded: PropTypes.Requireable<boolean>;
24
26
  /**
25
- * A function or component that is passed an object parameter with two
26
- * properties: `isSideNavExpanded` and `onClickSideNavExpand`. The function or
27
- * component can then use those properties to within the components it
28
- * returns, such as with the HeaderMenuButton and SideNav components.
27
+ * A function or a component that is invoked with `isSideNavExpanded` and `onClickSideNavExpand`.
28
+ * The function or component can then use those properties to within the components it
29
+ * returns, such as with the HeaderMenuButton and SideNav components. Additional props will also be passed
30
+ * into this component for convenience.
29
31
  */
30
32
  render: PropTypes.Validator<NonNullable<PropTypes.ReactComponentLike>>;
31
33
  };
@@ -9,6 +9,7 @@
9
9
 
10
10
  Object.defineProperty(exports, '__esModule', { value: true });
11
11
 
12
+ var _rollupPluginBabelHelpers = require('../../_virtual/_rollupPluginBabelHelpers.js');
12
13
  var PropTypes = require('prop-types');
13
14
  var React = require('react');
14
15
  var useEvent = require('../../internal/useEvent.js');
@@ -23,7 +24,8 @@ var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
23
24
  function HeaderContainer(_ref) {
24
25
  let {
25
26
  render: Children,
26
- isSideNavExpanded = false
27
+ isSideNavExpanded = false,
28
+ ...rest
27
29
  } = _ref;
28
30
  //state for expandable sidenav
29
31
  const [isSideNavExpandedState, setIsSideNavExpandedState] = React.useState(isSideNavExpanded);
@@ -35,10 +37,10 @@ function HeaderContainer(_ref) {
35
37
  const handleHeaderMenuButtonClick = React.useCallback(() => {
36
38
  setIsSideNavExpandedState(prevIsSideNavExpanded => !prevIsSideNavExpanded);
37
39
  }, [setIsSideNavExpandedState]);
38
- return /*#__PURE__*/React__default["default"].createElement(Children, {
40
+ return /*#__PURE__*/React__default["default"].createElement(Children, _rollupPluginBabelHelpers["extends"]({}, rest, {
39
41
  isSideNavExpanded: isSideNavExpandedState,
40
42
  onClickSideNavExpand: handleHeaderMenuButtonClick
41
- });
43
+ }));
42
44
  }
43
45
  HeaderContainer.propTypes = {
44
46
  /**
@@ -46,10 +48,10 @@ HeaderContainer.propTypes = {
46
48
  */
47
49
  isSideNavExpanded: PropTypes__default["default"].bool,
48
50
  /**
49
- * A function or component that is passed an object parameter with two
50
- * properties: `isSideNavExpanded` and `onClickSideNavExpand`. The function or
51
- * component can then use those properties to within the components it
52
- * returns, such as with the HeaderMenuButton and SideNav components.
51
+ * A function or a component that is invoked with `isSideNavExpanded` and `onClickSideNavExpand`.
52
+ * The function or component can then use those properties to within the components it
53
+ * returns, such as with the HeaderMenuButton and SideNav components. Additional props will also be passed
54
+ * into this component for convenience.
53
55
  */
54
56
  render: PropTypes__default["default"].elementType.isRequired
55
57
  };