@itwin/itwinui-react 3.0.0-dev.8 → 3.0.0-dev.9

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 (61) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/cjs/core/Buttons/DropdownButton/DropdownButton.js +7 -19
  3. package/cjs/core/Buttons/SplitButton/SplitButton.d.ts +4 -4
  4. package/cjs/core/Buttons/SplitButton/SplitButton.js +53 -31
  5. package/cjs/core/ComboBox/ComboBox.d.ts +2 -2
  6. package/cjs/core/ComboBox/ComboBox.js +32 -24
  7. package/cjs/core/ComboBox/ComboBoxInput.js +29 -21
  8. package/cjs/core/ComboBox/ComboBoxMenu.js +73 -93
  9. package/cjs/core/ComboBox/helpers.d.ts +4 -1
  10. package/cjs/core/DropdownMenu/DropdownMenu.d.ts +6 -5
  11. package/cjs/core/DropdownMenu/DropdownMenu.js +59 -55
  12. package/cjs/core/Header/HeaderDropdownButton.js +1 -2
  13. package/cjs/core/Header/HeaderSplitButton.js +1 -2
  14. package/cjs/core/Menu/Menu.js +1 -1
  15. package/cjs/core/Menu/MenuItem.js +77 -55
  16. package/cjs/core/Select/Select.d.ts +5 -5
  17. package/cjs/core/Select/Select.js +74 -93
  18. package/cjs/core/Table/columns/actionColumn.js +3 -7
  19. package/cjs/core/Table/filters/DateRangeFilter/DatePickerInput.js +36 -41
  20. package/cjs/core/Table/filters/FilterToggle.js +3 -2
  21. package/cjs/core/Tile/Tile.js +21 -22
  22. package/cjs/core/index.d.ts +1 -1
  23. package/cjs/core/index.js +8 -1
  24. package/cjs/core/utils/components/InputContainer.d.ts +4 -4
  25. package/cjs/core/utils/components/InputContainer.js +7 -3
  26. package/cjs/core/utils/components/Popover.d.ts +113 -27
  27. package/cjs/core/utils/components/Popover.js +156 -118
  28. package/cjs/styles.js +2 -5
  29. package/esm/core/Buttons/DropdownButton/DropdownButton.js +8 -24
  30. package/esm/core/Buttons/SplitButton/SplitButton.d.ts +4 -4
  31. package/esm/core/Buttons/SplitButton/SplitButton.js +53 -28
  32. package/esm/core/ComboBox/ComboBox.d.ts +2 -2
  33. package/esm/core/ComboBox/ComboBox.js +33 -24
  34. package/esm/core/ComboBox/ComboBoxInput.js +22 -21
  35. package/esm/core/ComboBox/ComboBoxMenu.js +67 -87
  36. package/esm/core/ComboBox/helpers.d.ts +4 -1
  37. package/esm/core/DropdownMenu/DropdownMenu.d.ts +6 -5
  38. package/esm/core/DropdownMenu/DropdownMenu.js +64 -56
  39. package/esm/core/Header/HeaderDropdownButton.js +1 -2
  40. package/esm/core/Header/HeaderSplitButton.js +1 -2
  41. package/esm/core/Menu/Menu.js +7 -2
  42. package/esm/core/Menu/MenuItem.js +84 -52
  43. package/esm/core/Select/Select.d.ts +5 -5
  44. package/esm/core/Select/Select.js +74 -90
  45. package/esm/core/Table/columns/actionColumn.js +3 -7
  46. package/esm/core/Table/filters/DateRangeFilter/DatePickerInput.js +36 -41
  47. package/esm/core/Table/filters/FilterToggle.js +3 -2
  48. package/esm/core/Tile/Tile.js +21 -22
  49. package/esm/core/index.d.ts +1 -1
  50. package/esm/core/index.js +1 -0
  51. package/esm/core/utils/components/InputContainer.d.ts +4 -4
  52. package/esm/core/utils/components/InputContainer.js +7 -2
  53. package/esm/core/utils/components/Popover.d.ts +113 -27
  54. package/esm/core/utils/components/Popover.js +175 -118
  55. package/esm/styles.js +2 -5
  56. package/package.json +2 -4
  57. package/styles.css +3 -3
  58. package/cjs/core/ComboBox/ComboBoxDropdown.d.ts +0 -7
  59. package/cjs/core/ComboBox/ComboBoxDropdown.js +0 -43
  60. package/esm/core/ComboBox/ComboBoxDropdown.d.ts +0 -7
  61. package/esm/core/ComboBox/ComboBoxDropdown.js +0 -37
@@ -4,129 +4,167 @@
4
4
  * See LICENSE.md in the project root for license terms and full copyright notice.
5
5
  *--------------------------------------------------------------------------------------------*/
6
6
  Object.defineProperty(exports, '__esModule', { value: true });
7
- exports.hideOnEscOrTab = exports.Popover = void 0;
7
+ exports.Popover = exports.usePopover = void 0;
8
8
  const tslib_1 = require('tslib');
9
9
  const React = tslib_1.__importStar(require('react'));
10
- const classnames_1 = tslib_1.__importDefault(require('classnames'));
11
- const react_1 = tslib_1.__importDefault(require('@tippyjs/react'));
12
- const index_js_1 = require('../hooks/index.js');
13
- const ThemeContext_js_1 = require('../../ThemeProvider/ThemeContext.js');
14
- /**
15
- * Wrapper around [tippy.js](https://atomiks.github.io/tippyjs)
16
- * with pre-configured props and plugins (e.g. lazy mounting, focus, etc).
17
- * @private
18
- */
19
- exports.Popover = React.forwardRef((props, ref) => {
20
- const [mounted, setMounted] = React.useState(false);
21
- const themeInfo = React.useContext(ThemeContext_js_1.ThemeContext);
22
- const isDomAvailable = (0, index_js_1.useIsClient)();
23
- const tippyRef = React.useRef(null);
24
- const refs = (0, index_js_1.useMergedRefs)(tippyRef, ref);
25
- // Plugin to allow lazy mounting. See https://github.com/atomiks/tippyjs-react#lazy-mounting
26
- const lazyLoad = {
27
- fn: () => ({
28
- onShow: () => setMounted(true),
29
- onHidden: () => setMounted(false),
10
+ const react_1 = require('@floating-ui/react');
11
+ const index_js_1 = require('../index.js');
12
+ const Portal_js_1 = require('./Portal.js');
13
+ const index_js_2 = require('../../Surface/index.js');
14
+ const index_js_3 = require('../../ThemeProvider/index.js');
15
+ // ----------------------------------------------------------------------------
16
+ const usePopover = (options) => {
17
+ const {
18
+ placement = 'bottom-start',
19
+ visible,
20
+ onVisibleChange,
21
+ closeOnOutsideClick,
22
+ autoUpdateOptions,
23
+ middleware = { flip: true, shift: true },
24
+ matchWidth,
25
+ trigger = { click: true, hover: false, focus: false },
26
+ role,
27
+ } = options;
28
+ const [open, onOpenChange] = (0, index_js_1.useControlledState)(
29
+ false,
30
+ visible,
31
+ onVisibleChange,
32
+ );
33
+ const floating = (0, react_1.useFloating)({
34
+ placement,
35
+ open,
36
+ onOpenChange,
37
+ whileElementsMounted: (...args) =>
38
+ (0, react_1.autoUpdate)(...args, autoUpdateOptions),
39
+ middleware: [
40
+ middleware.offset !== undefined && (0, react_1.offset)(middleware.offset),
41
+ middleware.flip && (0, react_1.flip)(),
42
+ middleware.shift && (0, react_1.shift)(),
43
+ matchWidth &&
44
+ (0, react_1.size)({
45
+ apply: ({ rects }) => {
46
+ setReferenceWidth(rects.reference.width);
47
+ },
48
+ }),
49
+ middleware.autoPlacement && (0, react_1.autoPlacement)(),
50
+ middleware.inline && (0, react_1.inline)(),
51
+ middleware.hide && (0, react_1.hide)(),
52
+ ].filter(Boolean),
53
+ });
54
+ const interactions = (0, react_1.useInteractions)([
55
+ (0, react_1.useClick)(floating.context, { enabled: !!trigger.click }),
56
+ (0, react_1.useDismiss)(floating.context, {
57
+ outsidePress: closeOnOutsideClick,
30
58
  }),
31
- };
32
- // Plugin to remove tabindex from tippy, to prevent focus ring from unintentionally showing.
33
- const removeTabIndex = {
34
- fn: () => ({
35
- onCreate: (instance) => {
36
- instance.popper.firstElementChild?.removeAttribute('tabindex');
37
- },
59
+ (0, react_1.useHover)(floating.context, {
60
+ enabled: !!trigger.hover,
61
+ delay: 100,
62
+ handleClose: (0, react_1.safePolygon)({ buffer: 1 }),
38
63
  }),
39
- };
40
- const computedProps = {
41
- allowHTML: true,
42
- animation: false,
43
- appendTo: (el) => themeInfo?.portalContainer || el.ownerDocument.body,
44
- arrow: false,
45
- duration: 0,
46
- interactive: true,
47
- role: '',
48
- offset: [0, 0],
49
- maxWidth: '',
50
- zIndex: 99999,
51
- ...props,
52
- className: (0, classnames_1.default)('iui-popover', props.className),
53
- // add additional check for isDomAvailable when using in controlled mode,
54
- // because rootRef is not available in first render
55
- visible:
56
- props.visible !== undefined ? props.visible && isDomAvailable : undefined,
57
- plugins: [
58
- lazyLoad,
59
- removeTabIndex,
60
- exports.hideOnEscOrTab,
61
- ...(props.plugins || []),
62
- ],
63
- popperOptions: {
64
- strategy: 'fixed',
65
- ...props.popperOptions,
66
- modifiers: [
67
- { name: 'flip' },
68
- {
69
- name: 'preventOverflow',
70
- options: { padding: 0 },
64
+ (0, react_1.useFocus)(floating.context, { enabled: !!trigger.focus }),
65
+ (0, react_1.useRole)(floating.context, { role: 'dialog', enabled: !!role }),
66
+ ]);
67
+ const [referenceWidth, setReferenceWidth] = React.useState();
68
+ const getFloatingProps = React.useCallback(
69
+ (userProps) =>
70
+ interactions.getFloatingProps({
71
+ ...userProps,
72
+ style: {
73
+ ...floating.floatingStyles,
74
+ zIndex: 9999,
75
+ ...(matchWidth && referenceWidth
76
+ ? {
77
+ minInlineSize: `${referenceWidth}px`,
78
+ maxInlineSize: `min(${referenceWidth * 2}px, 90vw)`,
79
+ }
80
+ : {}),
81
+ ...userProps?.style,
71
82
  },
72
- ...(props.popperOptions?.modifiers || []),
73
- ],
74
- },
75
- };
76
- if (props.render) {
77
- const render = props.render;
78
- computedProps.render = (...args) => (mounted ? render(...args) : '');
79
- } else {
80
- // Fixing issue where elements below Popover gets click events.
81
- // Tippy uses react Portal, which propagates events by react tree, not dom tree.
82
- // Read more: https://reactjs.org/docs/portals.html#event-bubbling-through-portals
83
- const clonedContent = React.isValidElement(props.content)
84
- ? React.cloneElement(props.content, {
85
- onClick: (e) => {
86
- e.stopPropagation();
87
- props.content.props.onClick?.(e);
88
- },
89
- })
90
- : props.content;
91
- computedProps.content = mounted ? clonedContent : '';
92
- }
93
- return React.createElement(react_1.default, { ...computedProps, ref: refs });
94
- });
83
+ }),
84
+ [floating.floatingStyles, interactions, matchWidth, referenceWidth],
85
+ );
86
+ return React.useMemo(
87
+ () => ({
88
+ open,
89
+ onOpenChange,
90
+ ...interactions,
91
+ getFloatingProps,
92
+ ...floating,
93
+ }),
94
+ [open, onOpenChange, interactions, getFloatingProps, floating],
95
+ );
96
+ };
97
+ exports.usePopover = usePopover;
95
98
  /**
96
- * Plugin to hide Popover when either Esc key is pressed,
97
- * or when the content inside is not tabbable and Tab key is pressed.
99
+ * A utility component to help with positioning of floating content.
100
+ * Built on top of [`floating-ui`](https://floating-ui.com/)
98
101
  */
99
- exports.hideOnEscOrTab = {
100
- fn(instance) {
101
- /** @returns true if none of the children are tabbable */
102
- const shouldHideOnTab = () => {
103
- const descendents = Array.from(instance.popper.querySelectorAll('*'));
104
- return !descendents.some((el) => el?.tabIndex >= 0);
105
- };
106
- const onKeyDown = (event) => {
107
- if (event.altKey) {
108
- return;
109
- }
110
- switch (event.key) {
111
- case 'Escape':
112
- instance.hide();
113
- break;
114
- case 'Tab':
115
- if (shouldHideOnTab()) {
116
- event.shiftKey && event.preventDefault(); // focus popover target on Shift+Tab
117
- instance.hide();
118
- }
119
- break;
120
- }
121
- };
122
- return {
123
- onShow() {
124
- instance.popper.addEventListener('keydown', onKeyDown);
125
- },
126
- onHide() {
127
- instance.popper.removeEventListener('keydown', onKeyDown);
128
- },
129
- };
130
- },
131
- };
102
+ exports.Popover = React.forwardRef((props, forwardedRef) => {
103
+ const {
104
+ portal = true,
105
+ //
106
+ // popover options
107
+ visible,
108
+ placement,
109
+ onVisibleChange,
110
+ closeOnOutsideClick,
111
+ matchWidth,
112
+ //
113
+ // dom props
114
+ children,
115
+ content,
116
+ applyBackground,
117
+ ...rest
118
+ } = props;
119
+ const popover = (0, exports.usePopover)({
120
+ visible,
121
+ placement,
122
+ onVisibleChange,
123
+ closeOnOutsideClick,
124
+ matchWidth,
125
+ role: 'dialog',
126
+ });
127
+ const [popoverElement, setPopoverElement] = React.useState();
128
+ const popoverRef = (0, index_js_1.useMergedRefs)(
129
+ popover.refs.setFloating,
130
+ forwardedRef,
131
+ setPopoverElement,
132
+ );
133
+ return React.createElement(
134
+ React.Fragment,
135
+ null,
136
+ (0, index_js_1.cloneElementWithRef)(children, (children) => ({
137
+ ...popover.getReferenceProps(children.props),
138
+ ref: popover.refs.setReference,
139
+ })),
140
+ popover.open
141
+ ? React.createElement(
142
+ Portal_js_1.Portal,
143
+ { portal: portal },
144
+ React.createElement(
145
+ index_js_3.ThemeProvider,
146
+ { portalContainer: popoverElement },
147
+ React.createElement(
148
+ react_1.FloatingFocusManager,
149
+ {
150
+ context: popover.context,
151
+ modal: false,
152
+ initialFocus: -1,
153
+ returnFocus: true,
154
+ },
155
+ React.createElement(
156
+ index_js_1.Box,
157
+ {
158
+ as: applyBackground ? index_js_2.Surface : 'div',
159
+ ...popover.getFloatingProps(rest),
160
+ ref: popoverRef,
161
+ },
162
+ content,
163
+ ),
164
+ ),
165
+ ),
166
+ )
167
+ : null,
168
+ );
169
+ });
132
170
  exports.default = exports.Popover;
package/cjs/styles.js CHANGED
@@ -219,10 +219,10 @@ const styles = {
219
219
  'iui-overlay-exiting': '_iui3-overlay-exiting',
220
220
  closeAnimation,
221
221
  'iui-progress-indicator-radial': '_iui3-progress-indicator-radial',
222
- 'iui-ubn95wp': '_iui3-ubn95wp',
222
+ 'iui-ugj3ux4': '_iui3-ugj3ux4',
223
223
  'iui-progress-indicator-linear-label':
224
224
  '_iui3-progress-indicator-linear-label',
225
- 'iui-ubn95xj': '_iui3-ubn95xj',
225
+ 'iui-ugj3uxq': '_iui3-ugj3uxq',
226
226
  'iui-radio': '_iui3-radio',
227
227
  'iui-radio-tile': '_iui3-radio-tile',
228
228
  'iui-radio-tile-icon': '_iui3-radio-tile-icon',
@@ -417,9 +417,6 @@ const styles = {
417
417
  'iui-svg-icon': '_iui3-svg-icon',
418
418
  'iui-notification-marker': '_iui3-notification-marker',
419
419
  pulse,
420
- 'iui-popover': '_iui3-popover',
421
- 'tippy-box': '_iui3-tippy-box',
422
- 'tippy-content': '_iui3-tippy-content',
423
420
  'iui-divider': '_iui3-divider',
424
421
  'iui-flex': '_iui3-flex',
425
422
  'iui-flex-spacer': '_iui3-flex-spacer',
@@ -6,11 +6,7 @@ import * as React from 'react';
6
6
  import cx from 'classnames';
7
7
  import { Button } from '../Button/index.js';
8
8
  import { DropdownMenu } from '../../DropdownMenu/index.js';
9
- import {
10
- SvgCaretDownSmall,
11
- SvgCaretUpSmall,
12
- useMergedRefs,
13
- } from '../../utils/index.js';
9
+ import { SvgCaretDownSmall, SvgCaretUpSmall } from '../../utils/index.js';
14
10
  /**
15
11
  * Button that opens a DropdownMenu.
16
12
  * @example
@@ -20,7 +16,7 @@ import {
20
16
  * ];
21
17
  * <DropdownButton menuItems={menuItems}>Default</DropdownButton>
22
18
  */
23
- export const DropdownButton = React.forwardRef((props, ref) => {
19
+ export const DropdownButton = React.forwardRef((props, forwardedRef) => {
24
20
  const {
25
21
  menuItems,
26
22
  className,
@@ -31,28 +27,17 @@ export const DropdownButton = React.forwardRef((props, ref) => {
31
27
  ...rest
32
28
  } = props;
33
29
  const [isMenuOpen, setIsMenuOpen] = React.useState(false);
34
- const [menuWidth, setMenuWidth] = React.useState(0);
35
- const buttonRef = React.useRef(null);
36
- const refs = useMergedRefs(ref, buttonRef);
37
- React.useEffect(() => {
38
- if (buttonRef.current) {
39
- setMenuWidth(buttonRef.current.offsetWidth);
40
- }
41
- }, [children, size, styleType]);
42
30
  return React.createElement(
43
31
  DropdownMenu,
44
32
  {
45
33
  menuItems: menuItems,
34
+ matchWidth: true,
35
+ visible: isMenuOpen,
46
36
  ...dropdownMenuProps,
47
- onShow: (i) => {
48
- setIsMenuOpen(true);
49
- dropdownMenuProps?.onShow?.(i);
37
+ onVisibleChange: (open) => {
38
+ setIsMenuOpen(open);
39
+ dropdownMenuProps?.onVisibleChange?.(open);
50
40
  },
51
- onHide: (i) => {
52
- setIsMenuOpen(false);
53
- dropdownMenuProps?.onHide?.(i);
54
- },
55
- style: { minInlineSize: menuWidth, ...dropdownMenuProps?.style },
56
41
  },
57
42
  React.createElement(
58
43
  Button,
@@ -63,8 +48,7 @@ export const DropdownButton = React.forwardRef((props, ref) => {
63
48
  endIcon: isMenuOpen
64
49
  ? React.createElement(SvgCaretUpSmall, { 'aria-hidden': true })
65
50
  : React.createElement(SvgCaretDownSmall, { 'aria-hidden': true }),
66
- ref: refs,
67
- 'aria-label': 'Dropdown',
51
+ ref: forwardedRef,
68
52
  ...rest,
69
53
  },
70
54
  children,
@@ -1,8 +1,8 @@
1
1
  import * as React from 'react';
2
2
  import type { ButtonProps } from '../Button/Button.js';
3
3
  import { IconButton } from '../IconButton/index.js';
4
- import type { Placement } from 'tippy.js';
5
- import type { PolymorphicForwardRefComponent } from '../../utils/index.js';
4
+ import type { PolymorphicForwardRefComponent, PortalProps } from '../../utils/index.js';
5
+ import type { Placement } from '@floating-ui/react';
6
6
  export type SplitButtonProps = ButtonProps & {
7
7
  /**
8
8
  * Items in the dropdown menu.
@@ -26,8 +26,8 @@ export type SplitButtonProps = ButtonProps & {
26
26
  /**
27
27
  * Passes props to SplitButton menu button.
28
28
  */
29
- menuButtonProps?: React.ComponentProps<typeof IconButton>;
30
- };
29
+ menuButtonProps?: Omit<React.ComponentProps<typeof IconButton>, 'label' | 'size'>;
30
+ } & Pick<PortalProps, 'portal'>;
31
31
  /**
32
32
  * Split button component with a DropdownMenu.
33
33
  *
@@ -6,13 +6,16 @@ import cx from 'classnames';
6
6
  import * as React from 'react';
7
7
  import { Button } from '../Button/index.js';
8
8
  import { IconButton } from '../IconButton/index.js';
9
- import { DropdownMenu } from '../../DropdownMenu/index.js';
10
9
  import {
11
10
  Box,
11
+ Portal,
12
12
  SvgCaretDownSmall,
13
13
  SvgCaretUpSmall,
14
14
  useId,
15
+ useMergedRefs,
16
+ usePopover,
15
17
  } from '../../utils/index.js';
18
+ import { Menu } from '../../Menu/Menu.js';
16
19
  /**
17
20
  * Split button component with a DropdownMenu.
18
21
  *
@@ -38,21 +41,33 @@ export const SplitButton = React.forwardRef((props, forwardedRef) => {
38
41
  children,
39
42
  wrapperProps,
40
43
  menuButtonProps,
44
+ portal = true,
41
45
  ...rest
42
46
  } = props;
43
- const [isMenuOpen, setIsMenuOpen] = React.useState(false);
44
- const [menuWidth, setMenuWidth] = React.useState(0);
45
- const wrapperRef = React.useRef(null);
46
- React.useEffect(() => {
47
- if (wrapperRef.current) {
48
- setMenuWidth(wrapperRef.current.offsetWidth);
47
+ const buttonRef = React.useRef(null);
48
+ const [visible, setVisible] = React.useState(false);
49
+ const close = React.useCallback(() => {
50
+ setVisible(false);
51
+ buttonRef.current?.focus({ preventScroll: true });
52
+ }, []);
53
+ const menuContent = React.useMemo(() => {
54
+ if (typeof menuItems === 'function') {
55
+ return menuItems(close);
49
56
  }
50
- }, [children, size]);
57
+ return menuItems;
58
+ }, [menuItems, close]);
59
+ const popover = usePopover({
60
+ visible,
61
+ onVisibleChange: (open) => (open ? setVisible(true) : close()),
62
+ placement: menuPlacement,
63
+ matchWidth: true,
64
+ });
51
65
  const labelId = useId();
52
66
  return React.createElement(
53
67
  Box,
54
68
  {
55
69
  ...wrapperProps,
70
+ ref: popover.refs.setPositionReference,
56
71
  className: cx(
57
72
  'iui-button-split',
58
73
  {
@@ -60,7 +75,6 @@ export const SplitButton = React.forwardRef((props, forwardedRef) => {
60
75
  },
61
76
  wrapperProps?.className,
62
77
  ),
63
- ref: wrapperRef,
64
78
  },
65
79
  React.createElement(
66
80
  Button,
@@ -69,35 +83,46 @@ export const SplitButton = React.forwardRef((props, forwardedRef) => {
69
83
  styleType: styleType,
70
84
  size: size,
71
85
  onClick: onClick,
72
- ref: forwardedRef,
86
+ ref: useMergedRefs(buttonRef, forwardedRef),
73
87
  ...rest,
74
88
  labelProps: { id: labelId, ...props.labelProps },
75
89
  },
76
90
  children,
77
91
  ),
78
92
  React.createElement(
79
- DropdownMenu,
93
+ IconButton,
80
94
  {
81
- placement: menuPlacement,
82
- menuItems: menuItems,
83
- style: { minInlineSize: menuWidth },
84
- onShow: React.useCallback(() => setIsMenuOpen(true), []),
85
- onHide: React.useCallback(() => setIsMenuOpen(false), []),
95
+ styleType: styleType,
96
+ size: size,
97
+ disabled: props.disabled,
98
+ 'aria-labelledby': props.labelProps?.id || labelId,
99
+ 'aria-expanded': popover.open,
100
+ ref: popover.refs.setReference,
101
+ ...popover.getReferenceProps(menuButtonProps),
86
102
  },
103
+ visible
104
+ ? React.createElement(SvgCaretUpSmall, null)
105
+ : React.createElement(SvgCaretDownSmall, null),
106
+ ),
107
+ popover.open &&
87
108
  React.createElement(
88
- IconButton,
89
- {
90
- styleType: styleType,
91
- size: size,
92
- disabled: props.disabled,
93
- 'aria-labelledby': props.labelProps?.id || labelId,
94
- ...menuButtonProps,
95
- },
96
- isMenuOpen
97
- ? React.createElement(SvgCaretUpSmall, null)
98
- : React.createElement(SvgCaretDownSmall, null),
109
+ Portal,
110
+ { portal: portal },
111
+ React.createElement(
112
+ Menu,
113
+ {
114
+ ...popover.getFloatingProps({
115
+ onKeyDown: ({ key }) => {
116
+ if (key === 'Tab') {
117
+ close();
118
+ }
119
+ },
120
+ }),
121
+ ref: popover.refs.setFloating,
122
+ },
123
+ menuContent,
124
+ ),
99
125
  ),
100
- ),
101
126
  );
102
127
  });
103
128
  export default SplitButton;
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import type { SelectOption } from '../Select/index.js';
3
3
  import type { Input } from '../Input/Input.js';
4
- import type { PopoverProps, InputContainerProps, CommonProps } from '../utils/index.js';
4
+ import type { InputContainerProps, CommonProps } from '../utils/index.js';
5
5
  type ActionType = 'added' | 'removed';
6
6
  type MultipleOnChangeProps<T> = {
7
7
  value: T;
@@ -48,7 +48,7 @@ export type ComboBoxProps<T> = {
48
48
  /**
49
49
  * Props to customize dropdown menu behavior.
50
50
  */
51
- dropdownMenuProps?: PopoverProps;
51
+ dropdownMenuProps?: React.ComponentProps<'div'>;
52
52
  /**
53
53
  * Message shown when no options are available.
54
54
  * If `JSX.Element` is provided, it will be rendered as is and won't be wrapped with `MenuExtraContent`.