@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
@@ -11,7 +11,7 @@ import cx from 'classnames';
11
11
  import { useSelect } from 'downshift';
12
12
  import isEqual from 'lodash.isequal';
13
13
  import PropTypes from 'prop-types';
14
- import React__default, { useContext, useRef, useState, useMemo } from 'react';
14
+ import React__default, { useContext, useRef, useState, useLayoutEffect, useMemo } 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';
@@ -23,6 +23,7 @@ import { usePrefix } from '../../internal/usePrefix.js';
23
23
  import '../FluidForm/FluidForm.js';
24
24
  import { FormContext } from '../FluidForm/FormContext.js';
25
25
  import { noopFn } from '../../internal/noopFn.js';
26
+ import { useFloating, flip, size, autoUpdate } from '@floating-ui/react';
26
27
  import { match } from '../../internal/keyboard/match.js';
27
28
  import { ListBoxSize } from '../ListBox/ListBoxPropTypes.js';
28
29
  import { Delete, Escape, Space, ArrowDown, Enter } from '../../internal/keyboard/keys.js';
@@ -57,6 +58,7 @@ const defaultItemToString = item => {
57
58
  };
58
59
  const MultiSelect = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
59
60
  let {
61
+ autoAlign = false,
60
62
  className: containerClassName,
61
63
  id,
62
64
  items,
@@ -67,7 +69,7 @@ const MultiSelect = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
67
69
  helperText,
68
70
  label,
69
71
  type = 'default',
70
- size,
72
+ size: size$1,
71
73
  disabled = false,
72
74
  initialSelectedItems = [],
73
75
  sortItems = defaultSortItems,
@@ -116,6 +118,42 @@ const MultiSelect = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
116
118
  onChange,
117
119
  selectedItems: selected
118
120
  });
121
+ const {
122
+ refs,
123
+ floatingStyles,
124
+ middlewareData
125
+ } = useFloating(autoAlign ? {
126
+ placement: direction,
127
+ // The floating element is positioned relative to its nearest
128
+ // containing block (usually the viewport). It will in many cases also
129
+ // “break” the floating element out of a clipping ancestor.
130
+ // https://floating-ui.com/docs/misc#clipping
131
+ strategy: 'fixed',
132
+ // Middleware order matters, arrow should be last
133
+ middleware: [flip({
134
+ crossAxis: false
135
+ }), size({
136
+ apply(_ref2) {
137
+ let {
138
+ rects,
139
+ elements
140
+ } = _ref2;
141
+ Object.assign(elements.floating.style, {
142
+ width: `${rects.reference.width}px`
143
+ });
144
+ }
145
+ })],
146
+ whileElementsMounted: autoUpdate
147
+ } : {});
148
+ useLayoutEffect(() => {
149
+ if (autoAlign) {
150
+ Object.keys(floatingStyles).forEach(style => {
151
+ if (refs.floating.current) {
152
+ refs.floating.current.style[style] = floatingStyles[style];
153
+ }
154
+ });
155
+ }
156
+ }, [autoAlign, floatingStyles, refs.floating, middlewareData, open]);
119
157
 
120
158
  // Filter out items with an object having undefined values
121
159
  const filteredItems = useMemo(() => {
@@ -367,7 +405,7 @@ const MultiSelect = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
367
405
  onFocus: isFluid ? handleFocus : undefined,
368
406
  onBlur: isFluid ? handleFocus : undefined,
369
407
  type: type,
370
- size: size,
408
+ size: size$1,
371
409
  className: className,
372
410
  disabled: disabled,
373
411
  light: light,
@@ -382,7 +420,8 @@ const MultiSelect = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
382
420
  }), showWarning && /*#__PURE__*/React__default.createElement(WarningAltFilled, {
383
421
  className: `${prefix}--list-box__invalid-icon ${prefix}--list-box__invalid-icon--warning`
384
422
  }), /*#__PURE__*/React__default.createElement("div", {
385
- className: multiSelectFieldWrapperClasses
423
+ className: multiSelectFieldWrapperClasses,
424
+ ref: refs.setReference
386
425
  }, selectedItems.length > 0 && /*#__PURE__*/React__default.createElement(ListBox.Selection, {
387
426
  readOnly: readOnly,
388
427
  clearSelection: !disabled && !readOnly ? clearSelection : noopFn,
@@ -405,7 +444,9 @@ const MultiSelect = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
405
444
  }, label), /*#__PURE__*/React__default.createElement(ListBox.MenuIcon, {
406
445
  isOpen: isOpen,
407
446
  translateWithId: translateWithId
408
- })), normalizedSlug), /*#__PURE__*/React__default.createElement(ListBox.Menu, getMenuProps(), isOpen &&
447
+ })), normalizedSlug), /*#__PURE__*/React__default.createElement(ListBox.Menu, getMenuProps({
448
+ ref: refs.setFloating
449
+ }), isOpen &&
409
450
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
410
451
  sortItems(filteredItems, sortOptions).map((item, index) => {
411
452
  const isChecked = selectedItems.filter(selected => isEqual(selected, item)).length > 0;
@@ -444,6 +485,12 @@ const MultiSelect = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
444
485
  MultiSelect.displayName = 'MultiSelect';
445
486
  MultiSelect.propTypes = {
446
487
  ...sortingPropTypes,
488
+ /**
489
+ * **Experimental**: Will attempt to automatically align the floating
490
+ * element to avoid collisions with the viewport and being clipped by
491
+ * ancestor elements.
492
+ */
493
+ autoAlign: PropTypes.bool,
447
494
  /**
448
495
  * Provide a custom class name to be added to the outermost node in the
449
496
  * 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 {};
@@ -127,7 +127,6 @@ class OverflowMenu extends React__default.Component {
127
127
  this.setState({
128
128
  click: true
129
129
  });
130
- evt.stopPropagation();
131
130
  if (!this._menuBody || !this._menuBody.contains(evt.target)) {
132
131
  this.setState({
133
132
  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
  */
@@ -6,13 +6,15 @@
6
6
  */
7
7
 
8
8
  import { extends as _extends } from '../../../_virtual/_rollupPluginBabelHelpers.js';
9
- import React__default, { useRef } from 'react';
9
+ import React__default, { useRef, useEffect } from 'react';
10
10
  import PropTypes from 'prop-types';
11
11
  import cx from 'classnames';
12
12
  import { OverflowMenuVertical } from '@carbon/icons-react';
13
+ import { useFloating, flip, autoUpdate } from '@floating-ui/react';
13
14
  import { IconButton } from '../../IconButton/index.js';
14
15
  import { Menu } from '../../Menu/Menu.js';
15
16
  import '../../Menu/MenuItem.js';
17
+ import mergeRefs from '../../../tools/mergeRefs.js';
16
18
  import { useId } from '../../../internal/useId.js';
17
19
  import { usePrefix } from '../../../internal/usePrefix.js';
18
20
  import { useAttachedMenu } from '../../../internal/useAttachedMenu.js';
@@ -20,6 +22,7 @@ import { useAttachedMenu } from '../../../internal/useAttachedMenu.js';
20
22
  const defaultSize = 'md';
21
23
  const OverflowMenu = /*#__PURE__*/React__default.forwardRef(function OverflowMenu(_ref, forwardRef) {
22
24
  let {
25
+ autoAlign = false,
23
26
  children,
24
27
  className,
25
28
  label = 'Options',
@@ -29,6 +32,26 @@ const OverflowMenu = /*#__PURE__*/React__default.forwardRef(function OverflowMen
29
32
  tooltipAlignment,
30
33
  ...rest
31
34
  } = _ref;
35
+ const {
36
+ refs,
37
+ floatingStyles,
38
+ placement,
39
+ middlewareData
40
+ } = useFloating(autoAlign ? {
41
+ placement: menuAlignment,
42
+ // The floating element is positioned relative to its nearest
43
+ // containing block (usually the viewport). It will in many cases also
44
+ // “break” the floating element out of a clipping ancestor.
45
+ // https://floating-ui.com/docs/misc#clipping
46
+ strategy: 'fixed',
47
+ // Middleware order matters, arrow should be last
48
+ middleware: [flip({
49
+ fallbackAxisSideDirection: 'start',
50
+ fallbackPlacements: ['top-start', 'top-end', 'bottom-start', 'bottom-end']
51
+ })],
52
+ whileElementsMounted: autoUpdate
53
+ } : {} // When autoAlign is turned off, floating-ui will not be used
54
+ );
32
55
  const id = useId('overflowmenu');
33
56
  const prefix = usePrefix();
34
57
  const triggerRef = useRef(null);
@@ -40,6 +63,15 @@ const OverflowMenu = /*#__PURE__*/React__default.forwardRef(function OverflowMen
40
63
  handleMousedown,
41
64
  handleClose
42
65
  } = useAttachedMenu(triggerRef);
66
+ useEffect(() => {
67
+ if (autoAlign) {
68
+ Object.keys(floatingStyles).forEach(style => {
69
+ if (refs.floating.current) {
70
+ refs.floating.current.style[style] = floatingStyles[style];
71
+ }
72
+ });
73
+ }
74
+ }, [floatingStyles, autoAlign, refs.floating, open, placement, middlewareData]);
43
75
  function handleTriggerClick() {
44
76
  if (triggerRef.current) {
45
77
  hookOnClick();
@@ -50,6 +82,7 @@ const OverflowMenu = /*#__PURE__*/React__default.forwardRef(function OverflowMen
50
82
  const triggerClasses = cx(`${prefix}--overflow-menu`, {
51
83
  [`${prefix}--overflow-menu--open`]: open
52
84
  }, size !== defaultSize && `${prefix}--overflow-menu--${size}`);
85
+ const floatingRef = mergeRefs(triggerRef, refs.setReference);
53
86
  return /*#__PURE__*/React__default.createElement("div", _extends({}, rest, {
54
87
  className: containerClasses,
55
88
  "aria-owns": open ? id : undefined,
@@ -61,17 +94,19 @@ const OverflowMenu = /*#__PURE__*/React__default.forwardRef(function OverflowMen
61
94
  className: triggerClasses,
62
95
  onClick: handleTriggerClick,
63
96
  onMouseDown: handleMousedown,
64
- ref: triggerRef,
97
+ ref: floatingRef,
65
98
  label: label,
66
99
  align: tooltipAlignment
67
100
  }, /*#__PURE__*/React__default.createElement(IconElement, {
68
101
  className: `${prefix}--overflow-menu__icon`
69
102
  })), /*#__PURE__*/React__default.createElement(Menu, {
70
103
  containerRef: triggerRef,
104
+ ref: refs.setFloating,
71
105
  menuAlignment: menuAlignment,
72
106
  className: menuClasses,
73
107
  id: id,
74
108
  size: size,
109
+ legacyAutoalign: !autoAlign,
75
110
  open: open,
76
111
  onClose: handleClose,
77
112
  x: x,
@@ -80,6 +115,10 @@ const OverflowMenu = /*#__PURE__*/React__default.forwardRef(function OverflowMen
80
115
  }, children));
81
116
  });
82
117
  OverflowMenu.propTypes = {
118
+ /**
119
+ * **Experimental**: Will attempt to automatically align the floating element to avoid collisions with the viewport and being clipped by ancestor elements.
120
+ */
121
+ autoAlign: PropTypes.bool,
83
122
  /**
84
123
  * A collection of MenuItems to be rendered within this OverflowMenu.
85
124
  */
@@ -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
  };
@@ -5,6 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
+ import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
8
9
  import PropTypes from 'prop-types';
9
10
  import React__default, { useState, useCallback } from 'react';
10
11
  import { useWindowEvent } from '../../internal/useEvent.js';
@@ -14,7 +15,8 @@ import { Escape } from '../../internal/keyboard/keys.js';
14
15
  function HeaderContainer(_ref) {
15
16
  let {
16
17
  render: Children,
17
- isSideNavExpanded = false
18
+ isSideNavExpanded = false,
19
+ ...rest
18
20
  } = _ref;
19
21
  //state for expandable sidenav
20
22
  const [isSideNavExpandedState, setIsSideNavExpandedState] = useState(isSideNavExpanded);
@@ -26,10 +28,10 @@ function HeaderContainer(_ref) {
26
28
  const handleHeaderMenuButtonClick = useCallback(() => {
27
29
  setIsSideNavExpandedState(prevIsSideNavExpanded => !prevIsSideNavExpanded);
28
30
  }, [setIsSideNavExpandedState]);
29
- return /*#__PURE__*/React__default.createElement(Children, {
31
+ return /*#__PURE__*/React__default.createElement(Children, _extends({}, rest, {
30
32
  isSideNavExpanded: isSideNavExpandedState,
31
33
  onClickSideNavExpand: handleHeaderMenuButtonClick
32
- });
34
+ }));
33
35
  }
34
36
  HeaderContainer.propTypes = {
35
37
  /**
@@ -37,10 +39,10 @@ HeaderContainer.propTypes = {
37
39
  */
38
40
  isSideNavExpanded: PropTypes.bool,
39
41
  /**
40
- * A function or component that is passed an object parameter with two
41
- * properties: `isSideNavExpanded` and `onClickSideNavExpand`. The function or
42
- * component can then use those properties to within the components it
43
- * returns, such as with the HeaderMenuButton and SideNav components.
42
+ * A function or a component that is invoked with `isSideNavExpanded` and `onClickSideNavExpand`.
43
+ * The function or component can then use those properties to within the components it
44
+ * returns, such as with the HeaderMenuButton and SideNav components. Additional props will also be passed
45
+ * into this component for convenience.
44
46
  */
45
47
  render: PropTypes.elementType.isRequired
46
48
  };
@@ -392,6 +392,10 @@ const ComboBox = /*#__PURE__*/React.forwardRef((props, ref) => {
392
392
  // when both the message is supplied *and* when the component is in
393
393
  // the matching state (invalid, warn, etc).
394
394
  const ariaDescribedBy = invalid && invalidText && invalidTextId || warn && warnText && warnTextId || helperText && !isFluid && helperTextId || undefined;
395
+ const menuProps = React.useMemo(() => getMenuProps({
396
+ 'aria-label': deprecatedAriaLabel || ariaLabel,
397
+ ref: autoAlign ? refs.setFloating : null
398
+ }), [autoAlign, deprecatedAriaLabel, ariaLabel]);
395
399
  return /*#__PURE__*/React__default["default"].createElement("div", {
396
400
  className: wrapperClasses
397
401
  }, titleText && /*#__PURE__*/React__default["default"].createElement(Text.Text, _rollupPluginBabelHelpers["extends"]({
@@ -409,7 +413,7 @@ const ComboBox = /*#__PURE__*/React.forwardRef((props, ref) => {
409
413
  light: light,
410
414
  size: size,
411
415
  warn: warn,
412
- ref: refs.setReference,
416
+ ref: autoAlign ? refs.setReference : null,
413
417
  warnText: warnText,
414
418
  warnTextId: warnTextId
415
419
  }, /*#__PURE__*/React__default["default"].createElement("div", {
@@ -422,7 +426,7 @@ const ComboBox = /*#__PURE__*/React.forwardRef((props, ref) => {
422
426
  "aria-haspopup": "listbox",
423
427
  title: textInput?.current?.value
424
428
  }, getInputProps({
425
- 'aria-controls': isOpen ? undefined : getMenuProps().id,
429
+ 'aria-controls': isOpen ? undefined : menuProps.id,
426
430
  placeholder,
427
431
  ref: {
428
432
  ...mergeRefs["default"](textInput, ref)
@@ -484,11 +488,7 @@ const ComboBox = /*#__PURE__*/React.forwardRef((props, ref) => {
484
488
  // @ts-expect-error
485
489
  isOpen: isOpen,
486
490
  translateWithId: translateWithId
487
- }))), normalizedSlug, /*#__PURE__*/React__default["default"].createElement(index["default"].Menu, _rollupPluginBabelHelpers["extends"]({}, getMenuProps({
488
- 'aria-label': deprecatedAriaLabel || ariaLabel
489
- }), {
490
- ref: mergeRefs["default"](getMenuProps().ref, refs.setFloating)
491
- }), isOpen ? filterItems(items, itemToString, inputValue).map((item, index$1) => {
491
+ }))), normalizedSlug, /*#__PURE__*/React__default["default"].createElement(index["default"].Menu, menuProps, isOpen ? filterItems(items, itemToString, inputValue).map((item, index$1) => {
492
492
  const isObject = item !== null && typeof item === 'object';
493
493
  const title = isObject && 'text' in item && itemToElement ? item.text?.toString() : itemToString(item);
494
494
  const itemProps = getItemProps({
@@ -13,6 +13,7 @@ var _rollupPluginBabelHelpers = require('../../_virtual/_rollupPluginBabelHelper
13
13
  var React = require('react');
14
14
  var reactIs = require('react-is');
15
15
  var PropTypes = require('prop-types');
16
+ var index = require('../Layer/index.js');
16
17
  var ModalHeader = require('./ModalHeader.js');
17
18
  var ModalFooter = require('./ModalFooter.js');
18
19
  var debounce = require('lodash.debounce');
@@ -23,7 +24,7 @@ var toggleClass = require('../../tools/toggleClass.js');
23
24
  var requiredIfGivenPropIsTruthy = require('../../prop-types/requiredIfGivenPropIsTruthy.js');
24
25
  var wrapFocus = require('../../internal/wrapFocus.js');
25
26
  var usePrefix = require('../../internal/usePrefix.js');
26
- var index = require('../FeatureFlags/index.js');
27
+ var index$1 = require('../FeatureFlags/index.js');
27
28
  var match = require('../../internal/keyboard/match.js');
28
29
  var keys = require('../../internal/keyboard/keys.js');
29
30
 
@@ -70,7 +71,7 @@ const ModalBody = /*#__PURE__*/React__default["default"].forwardRef(function Mod
70
71
  tabIndex: 0,
71
72
  role: 'region'
72
73
  } : {};
73
- return /*#__PURE__*/React__default["default"].createElement("div", _rollupPluginBabelHelpers["extends"]({
74
+ return /*#__PURE__*/React__default["default"].createElement(index.Layer, _rollupPluginBabelHelpers["extends"]({
74
75
  className: contentClass
75
76
  }, hasScrollingContentProps, rest, {
76
77
  ref: mergeRefs["default"](contentRef, ref)
@@ -126,7 +127,7 @@ const ComposedModal = /*#__PURE__*/React__default["default"].forwardRef(function
126
127
  const button = React.useRef(null);
127
128
  const startSentinel = React.useRef(null);
128
129
  const endSentinel = React.useRef(null);
129
- const focusTrapWithoutSentinels = index.useFeatureFlag('enable-experimental-focus-wrap-without-sentinels');
130
+ const focusTrapWithoutSentinels = index$1.useFeatureFlag('enable-experimental-focus-wrap-without-sentinels');
130
131
 
131
132
  // Keep track of modal open/close state
132
133
  // and propagate it to the document.body
@@ -260,7 +261,8 @@ const ComposedModal = /*#__PURE__*/React__default["default"].forwardRef(function
260
261
  size: 'sm'
261
262
  });
262
263
  }
263
- return /*#__PURE__*/React__default["default"].createElement("div", _rollupPluginBabelHelpers["extends"]({}, rest, {
264
+ return /*#__PURE__*/React__default["default"].createElement(index.Layer, _rollupPluginBabelHelpers["extends"]({}, rest, {
265
+ level: 0,
264
266
  role: "presentation",
265
267
  ref: ref,
266
268
  "aria-hidden": !open,
@@ -188,6 +188,8 @@ const DatePicker = /*#__PURE__*/React__default["default"].forwardRef(function Da
188
188
 
189
189
  // fix datepicker deleting the selectedDate when the calendar closes
190
190
  const onCalendarClose = (selectedDates, dateStr) => {
191
+ endInputField?.current?.focus();
192
+ calendarRef?.current?.calendarContainer?.classList.remove('open');
191
193
  setTimeout(() => {
192
194
  if (lastStartValue.current && selectedDates[0] && !startInputField.current.value) {
193
195
  startInputField.current.value = lastStartValue.current;
@@ -367,9 +369,12 @@ const DatePicker = /*#__PURE__*/React__default["default"].forwardRef(function Da
367
369
  calendarRef.current = calendar;
368
370
  function handleArrowDown(event) {
369
371
  if (match.match(event, keys.Escape)) {
370
- calendar.calendarContainer.classList.remove('open');
372
+ calendar?.calendarContainer?.classList.remove('open');
371
373
  }
372
374
  if (match.match(event, keys.ArrowDown)) {
375
+ if (event.target == endInputField.current) {
376
+ calendar?.calendarContainer?.classList.add('open');
377
+ }
373
378
  const {
374
379
  calendarContainer,
375
380
  selectedDateElem: fpSelectedDateElem,
@@ -23,6 +23,10 @@ export interface DropdownProps<ItemType> extends Omit<ReactAttr<HTMLDivElement>,
23
23
  * Specify a label to be read by screen readers on the container note.
24
24
  */
25
25
  ariaLabel?: string;
26
+ /**
27
+ * **Experimental**: Will attempt to automatically align the floating element to avoid collisions with the viewport and being clipped by ancestor elements.
28
+ */
29
+ autoAlign?: boolean;
26
30
  /**
27
31
  * Specify the direction of the dropdown. Can be either top or bottom.
28
32
  */
@@ -22,6 +22,7 @@ var usePrefix = require('../../internal/usePrefix.js');
22
22
  require('../FluidForm/FluidForm.js');
23
23
  var FormContext = require('../FluidForm/FormContext.js');
24
24
  var setupGetInstanceId = require('../../tools/setupGetInstanceId.js');
25
+ var react = require('@floating-ui/react');
25
26
  var ListBoxPropTypes = require('../ListBox/ListBoxPropTypes.js');
26
27
 
27
28
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
@@ -53,6 +54,7 @@ const defaultItemToString = item => {
53
54
  };
54
55
  const Dropdown = /*#__PURE__*/React__default["default"].forwardRef((_ref, ref) => {
55
56
  let {
57
+ autoAlign = false,
56
58
  className: containerClassName,
57
59
  disabled = false,
58
60
  direction = 'bottom',
@@ -83,6 +85,40 @@ const Dropdown = /*#__PURE__*/React__default["default"].forwardRef((_ref, ref) =
83
85
  slug,
84
86
  ...other
85
87
  } = _ref;
88
+ const {
89
+ refs,
90
+ floatingStyles
91
+ } = react.useFloating(autoAlign ? {
92
+ placement: direction,
93
+ // The floating element is positioned relative to its nearest
94
+ // containing block (usually the viewport). It will in many cases also
95
+ // “break” the floating element out of a clipping ancestor.
96
+ // https://floating-ui.com/docs/misc#clipping
97
+ strategy: 'fixed',
98
+ // Middleware order matters, arrow should be last
99
+ middleware: [react.size({
100
+ apply(_ref2) {
101
+ let {
102
+ rects,
103
+ elements
104
+ } = _ref2;
105
+ Object.assign(elements.floating.style, {
106
+ width: `${rects.reference.width}px`
107
+ });
108
+ }
109
+ }), react.flip()],
110
+ whileElementsMounted: react.autoUpdate
111
+ } : {} // When autoAlign is turned off, floating-ui will not be used
112
+ );
113
+ React.useEffect(() => {
114
+ if (autoAlign) {
115
+ Object.keys(floatingStyles).forEach(style => {
116
+ if (refs.floating.current) {
117
+ refs.floating.current.style[style] = floatingStyles[style];
118
+ }
119
+ });
120
+ }
121
+ }, [floatingStyles, autoAlign, refs.floating]);
86
122
  const prefix = usePrefix.usePrefix();
87
123
  const {
88
124
  isFluid
@@ -157,7 +193,8 @@ const Dropdown = /*#__PURE__*/React__default["default"].forwardRef((_ref, ref) =
157
193
  [`${prefix}--dropdown--light`]: light,
158
194
  [`${prefix}--dropdown--readonly`]: readOnly,
159
195
  [`${prefix}--dropdown--${size}`]: size,
160
- [`${prefix}--list-box--up`]: direction === 'top'
196
+ [`${prefix}--list-box--up`]: direction === 'top',
197
+ [`${prefix}--dropdown--autoalign`]: autoAlign
161
198
  });
162
199
  const titleClasses = cx__default["default"](`${prefix}--label`, {
163
200
  [`${prefix}--label--disabled`]: disabled,
@@ -184,10 +221,10 @@ const Dropdown = /*#__PURE__*/React__default["default"].forwardRef((_ref, ref) =
184
221
  id: helperId,
185
222
  className: helperClasses
186
223
  }, helperText) : null;
187
- function onSelectedItemChange(_ref2) {
224
+ function onSelectedItemChange(_ref3) {
188
225
  let {
189
226
  selectedItem
190
- } = _ref2;
227
+ } = _ref3;
191
228
  if (onChange) {
192
229
  onChange({
193
230
  selectedItem: selectedItem ?? null
@@ -237,6 +274,7 @@ const Dropdown = /*#__PURE__*/React__default["default"].forwardRef((_ref, ref) =
237
274
  }
238
275
  };
239
276
  const menuProps = getMenuProps();
277
+ const menuRef = mergeRefs["default"](menuProps.ref, refs.setFloating);
240
278
 
241
279
  // Slug is always size `mini`
242
280
  let normalizedSlug;
@@ -261,6 +299,7 @@ const Dropdown = /*#__PURE__*/React__default["default"].forwardRef((_ref, ref) =
261
299
  warnText: warnText,
262
300
  light: light,
263
301
  isOpen: isOpen,
302
+ ref: refs.setReference,
264
303
  id: id
265
304
  }, invalid && /*#__PURE__*/React__default["default"].createElement(iconsReact.WarningFilled, {
266
305
  className: `${prefix}--list-box__invalid-icon`
@@ -283,7 +322,9 @@ const Dropdown = /*#__PURE__*/React__default["default"].forwardRef((_ref, ref) =
283
322
  }, selectedItem ? renderSelectedItem ? renderSelectedItem(selectedItem) : itemToString(selectedItem) : label), /*#__PURE__*/React__default["default"].createElement(index["default"].MenuIcon, {
284
323
  isOpen: isOpen,
285
324
  translateWithId: translateWithId
286
- })), normalizedSlug, /*#__PURE__*/React__default["default"].createElement(index["default"].Menu, menuProps, isOpen && items.map((item, index$1) => {
325
+ })), normalizedSlug, /*#__PURE__*/React__default["default"].createElement(index["default"].Menu, _rollupPluginBabelHelpers["extends"]({}, menuProps, {
326
+ ref: menuRef
327
+ }), isOpen && items.map((item, index$1) => {
287
328
  const isObject = item !== null && typeof item === 'object';
288
329
  const itemProps = getItemProps({
289
330
  item,
@@ -318,6 +359,10 @@ Dropdown.propTypes = {
318
359
  * Specify a label to be read by screen readers on the container note.
319
360
  */
320
361
  ariaLabel: deprecate["default"](PropTypes__default["default"].string, 'This prop syntax has been deprecated. Please use the new `aria-label`.'),
362
+ /**
363
+ * **Experimental**: Will attempt to automatically align the floating element to avoid collisions with the viewport and being clipped by ancestor elements.
364
+ */
365
+ autoAlign: PropTypes__default["default"].bool,
321
366
  /**
322
367
  * Provide a custom className to be applied on the cds--dropdown node
323
368
  */
@@ -19,13 +19,14 @@ var Button = require('../Button/Button.js');
19
19
  require('../Button/Button.Skeleton.js');
20
20
  var ButtonSet = require('../ButtonSet/ButtonSet.js');
21
21
  var InlineLoading = require('../InlineLoading/InlineLoading.js');
22
+ var index$1 = require('../Layer/index.js');
22
23
  var requiredIfGivenPropIsTruthy = require('../../prop-types/requiredIfGivenPropIsTruthy.js');
23
24
  var wrapFocus = require('../../internal/wrapFocus.js');
24
25
  var debounce = require('lodash.debounce');
25
26
  var useIsomorphicEffect = require('../../internal/useIsomorphicEffect.js');
26
27
  var setupGetInstanceId = require('../../tools/setupGetInstanceId.js');
27
28
  var usePrefix = require('../../internal/usePrefix.js');
28
- var index$1 = require('../IconButton/index.js');
29
+ var index$2 = require('../IconButton/index.js');
29
30
  var noopFn = require('../../internal/noopFn.js');
30
31
  require('../Text/index.js');
31
32
  var index = require('../FeatureFlags/index.js');
@@ -246,7 +247,7 @@ const Modal = /*#__PURE__*/React__default["default"].forwardRef(function Modal(_
246
247
  }
247
248
  const modalButton = /*#__PURE__*/React__default["default"].createElement("div", {
248
249
  className: `${prefix}--modal-close-button`
249
- }, /*#__PURE__*/React__default["default"].createElement(index$1.IconButton, {
250
+ }, /*#__PURE__*/React__default["default"].createElement(index$2.IconButton, {
250
251
  className: modalCloseButtonClass,
251
252
  label: closeButtonLabel,
252
253
  onClick: onRequestClose,
@@ -277,7 +278,7 @@ const Modal = /*#__PURE__*/React__default["default"].forwardRef(function Modal(_
277
278
  as: "h3",
278
279
  id: modalHeadingId,
279
280
  className: `${prefix}--modal-header__heading`
280
- }, modalHeading), normalizedSlug, !passiveModal && modalButton), /*#__PURE__*/React__default["default"].createElement("div", _rollupPluginBabelHelpers["extends"]({
281
+ }, modalHeading), normalizedSlug, !passiveModal && modalButton), /*#__PURE__*/React__default["default"].createElement(index$1.Layer, _rollupPluginBabelHelpers["extends"]({
281
282
  ref: contentRef,
282
283
  id: modalBodyId,
283
284
  className: contentClasses
@@ -312,7 +313,8 @@ const Modal = /*#__PURE__*/React__default["default"].forwardRef(function Modal(_
312
313
  className: `${prefix}--inline-loading--btn`,
313
314
  onSuccess: onLoadingSuccess
314
315
  }))));
315
- return /*#__PURE__*/React__default["default"].createElement("div", _rollupPluginBabelHelpers["extends"]({}, rest, {
316
+ return /*#__PURE__*/React__default["default"].createElement(index$1.Layer, _rollupPluginBabelHelpers["extends"]({}, rest, {
317
+ level: 0,
316
318
  onKeyDown: handleKeyDown,
317
319
  onMouseDown: handleMousedown,
318
320
  onBlur: !focusTrapWithoutSentinels ? handleBlur : () => {},