@itwin/itwinui-react 3.14.2 → 3.15.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 (101) hide show
  1. package/CHANGELOG.md +68 -2
  2. package/DEV-cjs/core/Carousel/CarouselDotsList.js +11 -4
  3. package/DEV-cjs/core/Carousel/CarouselSlider.js +3 -3
  4. package/DEV-cjs/core/ColorPicker/ColorBuilder.js +72 -24
  5. package/DEV-cjs/core/ColorPicker/ColorInputPanel.js +35 -7
  6. package/DEV-cjs/core/ColorPicker/ColorPalette.js +21 -3
  7. package/DEV-cjs/core/ComboBox/ComboBox.js +2 -1
  8. package/DEV-cjs/core/ComboBox/ComboBoxMenu.js +2 -2
  9. package/DEV-cjs/core/DropdownMenu/DropdownMenu.js +20 -19
  10. package/DEV-cjs/core/Overlay/Overlay.js +0 -18
  11. package/DEV-cjs/core/Popover/Popover.js +17 -10
  12. package/DEV-cjs/core/Select/Select.js +4 -2
  13. package/DEV-cjs/core/Table/Table.js +50 -25
  14. package/DEV-cjs/core/Table/TableExpandableContentMemoized.js +47 -0
  15. package/DEV-cjs/core/Table/TableRowMemoized.js +0 -18
  16. package/DEV-cjs/core/Table/hooks/useColumnDragAndDrop.js +12 -14
  17. package/DEV-cjs/core/ThemeProvider/ThemeProvider.js +18 -0
  18. package/DEV-cjs/core/Toast/Toast.js +6 -7
  19. package/DEV-cjs/styles.js +1 -1
  20. package/DEV-cjs/utils/components/ShadowRoot.js +22 -8
  21. package/DEV-cjs/utils/hooks/useWarningLogger.js +5 -3
  22. package/DEV-esm/core/Carousel/CarouselDotsList.js +10 -5
  23. package/DEV-esm/core/Carousel/CarouselSlider.js +2 -3
  24. package/DEV-esm/core/ColorPicker/ColorBuilder.js +56 -22
  25. package/DEV-esm/core/ColorPicker/ColorInputPanel.js +37 -8
  26. package/DEV-esm/core/ColorPicker/ColorPalette.js +18 -3
  27. package/DEV-esm/core/ComboBox/ComboBox.js +2 -1
  28. package/DEV-esm/core/ComboBox/ComboBoxMenu.js +2 -2
  29. package/DEV-esm/core/DropdownMenu/DropdownMenu.js +20 -19
  30. package/DEV-esm/core/Overlay/Overlay.js +1 -19
  31. package/DEV-esm/core/Popover/Popover.js +18 -10
  32. package/DEV-esm/core/Select/Select.js +4 -2
  33. package/DEV-esm/core/Table/Table.js +50 -25
  34. package/DEV-esm/core/Table/TableExpandableContentMemoized.js +33 -0
  35. package/DEV-esm/core/Table/TableRowMemoized.js +1 -21
  36. package/DEV-esm/core/Table/hooks/useColumnDragAndDrop.js +12 -6
  37. package/DEV-esm/core/ThemeProvider/ThemeProvider.js +18 -0
  38. package/DEV-esm/core/Toast/Toast.js +5 -5
  39. package/DEV-esm/styles.js +1 -1
  40. package/DEV-esm/utils/components/ShadowRoot.js +22 -8
  41. package/DEV-esm/utils/hooks/useWarningLogger.js +4 -3
  42. package/cjs/core/Buttons/SplitButton.d.ts +5 -0
  43. package/cjs/core/Carousel/CarouselDotsList.js +11 -4
  44. package/cjs/core/Carousel/CarouselSlider.js +3 -3
  45. package/cjs/core/ColorPicker/ColorBuilder.d.ts +22 -1
  46. package/cjs/core/ColorPicker/ColorBuilder.js +72 -24
  47. package/cjs/core/ColorPicker/ColorInputPanel.d.ts +18 -0
  48. package/cjs/core/ColorPicker/ColorInputPanel.js +35 -7
  49. package/cjs/core/ColorPicker/ColorPalette.d.ts +8 -0
  50. package/cjs/core/ColorPicker/ColorPalette.js +21 -3
  51. package/cjs/core/ComboBox/ComboBox.d.ts +3 -2
  52. package/cjs/core/ComboBox/ComboBox.js +2 -1
  53. package/cjs/core/ComboBox/ComboBoxMenu.js +2 -2
  54. package/cjs/core/DropdownMenu/DropdownMenu.d.ts +11 -0
  55. package/cjs/core/DropdownMenu/DropdownMenu.js +20 -19
  56. package/cjs/core/Overlay/Overlay.js +0 -18
  57. package/cjs/core/Popover/Popover.d.ts +4 -1
  58. package/cjs/core/Popover/Popover.js +17 -10
  59. package/cjs/core/Select/Select.d.ts +14 -2
  60. package/cjs/core/Select/Select.js +4 -2
  61. package/cjs/core/Table/Table.js +50 -25
  62. package/cjs/core/Table/TableExpandableContentMemoized.d.ts +10 -0
  63. package/cjs/core/Table/TableExpandableContentMemoized.js +47 -0
  64. package/cjs/core/Table/TableRowMemoized.js +0 -18
  65. package/cjs/core/Table/hooks/useColumnDragAndDrop.js +12 -14
  66. package/cjs/core/ThemeProvider/ThemeProvider.js +18 -0
  67. package/cjs/core/Toast/Toast.js +6 -7
  68. package/cjs/styles.js +1 -1
  69. package/cjs/utils/components/ShadowRoot.js +22 -8
  70. package/cjs/utils/hooks/useWarningLogger.js +1 -0
  71. package/esm/core/Buttons/SplitButton.d.ts +5 -0
  72. package/esm/core/Carousel/CarouselDotsList.js +10 -5
  73. package/esm/core/Carousel/CarouselSlider.js +2 -3
  74. package/esm/core/ColorPicker/ColorBuilder.d.ts +22 -1
  75. package/esm/core/ColorPicker/ColorBuilder.js +56 -22
  76. package/esm/core/ColorPicker/ColorInputPanel.d.ts +18 -0
  77. package/esm/core/ColorPicker/ColorInputPanel.js +37 -8
  78. package/esm/core/ColorPicker/ColorPalette.d.ts +8 -0
  79. package/esm/core/ColorPicker/ColorPalette.js +18 -3
  80. package/esm/core/ComboBox/ComboBox.d.ts +3 -2
  81. package/esm/core/ComboBox/ComboBox.js +2 -1
  82. package/esm/core/ComboBox/ComboBoxMenu.js +2 -2
  83. package/esm/core/DropdownMenu/DropdownMenu.d.ts +11 -0
  84. package/esm/core/DropdownMenu/DropdownMenu.js +20 -19
  85. package/esm/core/Overlay/Overlay.js +1 -19
  86. package/esm/core/Popover/Popover.d.ts +4 -1
  87. package/esm/core/Popover/Popover.js +18 -10
  88. package/esm/core/Select/Select.d.ts +14 -2
  89. package/esm/core/Select/Select.js +4 -2
  90. package/esm/core/Table/Table.js +50 -25
  91. package/esm/core/Table/TableExpandableContentMemoized.d.ts +10 -0
  92. package/esm/core/Table/TableExpandableContentMemoized.js +33 -0
  93. package/esm/core/Table/TableRowMemoized.js +1 -21
  94. package/esm/core/Table/hooks/useColumnDragAndDrop.js +12 -6
  95. package/esm/core/ThemeProvider/ThemeProvider.js +18 -0
  96. package/esm/core/Toast/Toast.js +5 -5
  97. package/esm/styles.js +1 -1
  98. package/esm/utils/components/ShadowRoot.js +22 -8
  99. package/esm/utils/hooks/useWarningLogger.js +1 -0
  100. package/package.json +8 -6
  101. package/styles.css +8 -8
@@ -6,6 +6,7 @@ import {
6
6
  useEventListener,
7
7
  useMergedRefs,
8
8
  Box,
9
+ mergeEventHandlers,
9
10
  } from '../../utils/index.js';
10
11
  import { Slider } from '../Slider/Slider.js';
11
12
  import { useColorPickerContext } from './ColorPickerContext.js';
@@ -18,7 +19,14 @@ let getHorizontalPercentageOfRectangle = (rect, pointer) => {
18
19
  return ((position - rect.left) / rect.width) * 100;
19
20
  };
20
21
  export const ColorBuilder = React.forwardRef((props, ref) => {
21
- let { className, ...rest } = props;
22
+ let {
23
+ className,
24
+ colorFieldProps,
25
+ colorDotProps,
26
+ opacitySliderProps,
27
+ hueSliderProps,
28
+ ...rest
29
+ } = props;
22
30
  let builderRef = React.useRef();
23
31
  let refs = useMergedRefs(builderRef, ref);
24
32
  let {
@@ -206,54 +214,74 @@ export const ColorBuilder = React.forwardRef((props, ref) => {
206
214
  React.createElement(
207
215
  Box,
208
216
  {
209
- className: 'iui-color-field',
217
+ as: 'div',
218
+ ...colorFieldProps,
219
+ className: cx('iui-color-field', colorFieldProps?.className),
210
220
  style: {
211
221
  '--iui-color-field-hue': hueColorString,
212
222
  '--iui-color-picker-selected-color': dotColorString,
223
+ ...colorFieldProps?.style,
213
224
  },
214
- ref: squareRef,
215
- onPointerDown: (event) => {
216
- event.preventDefault();
217
- updateSquareValue(event, 'onClick');
218
- setColorDotActive(true);
219
- colorDotRef.current?.focus();
220
- },
225
+ ref: useMergedRefs(squareRef, colorFieldProps?.ref),
226
+ onPointerDown: mergeEventHandlers(
227
+ colorFieldProps?.onPointerDown,
228
+ (event) => {
229
+ event.preventDefault();
230
+ updateSquareValue(event, 'onClick');
231
+ setColorDotActive(true);
232
+ colorDotRef.current?.focus();
233
+ },
234
+ ),
221
235
  },
222
236
  React.createElement(Box, {
223
- className: 'iui-color-dot',
237
+ as: 'div',
238
+ ...colorDotProps,
239
+ className: cx('iui-color-dot', colorDotProps?.className),
224
240
  style: {
225
241
  '--iui-color-dot-inset-block': `${squareTop.toString()}% auto`,
226
242
  '--iui-color-dot-inset-inline': `${squareLeft.toString()}% auto`,
243
+ ...colorDotProps?.style,
227
244
  },
228
- onPointerDown: () => {
245
+ onPointerDown: mergeEventHandlers(colorDotProps?.onPointerDown, () => {
229
246
  setColorDotActive(true);
230
247
  colorDotRef.current?.focus();
231
- },
232
- onKeyDown: handleColorDotKeyDown,
233
- onKeyUp: handleColorDotKeyUp,
248
+ }),
249
+ onKeyDown: mergeEventHandlers(
250
+ colorDotProps?.onKeyDown,
251
+ handleColorDotKeyDown,
252
+ ),
253
+ onKeyUp: mergeEventHandlers(
254
+ colorDotProps?.onKeyUp,
255
+ handleColorDotKeyUp,
256
+ ),
234
257
  tabIndex: 0,
235
- ref: colorDotRef,
258
+ ref: useMergedRefs(colorDotRef, colorDotProps?.ref),
236
259
  }),
237
260
  ),
238
261
  React.createElement(Slider, {
239
262
  minLabel: '',
240
263
  maxLabel: '',
241
264
  values: [sliderValue],
242
- className: 'iui-hue-slider',
243
265
  trackDisplayMode: 'none',
266
+ min: 0,
267
+ max: 359,
268
+ ...hueSliderProps,
269
+ className: cx('iui-hue-slider', hueSliderProps?.className),
244
270
  tooltipProps: () => ({
245
271
  visible: false,
272
+ ...hueSliderProps?.tooltipProps,
246
273
  }),
247
274
  onChange: (values) => {
275
+ hueSliderProps?.onChange?.(values);
248
276
  updateHueSlider(values[0], true);
249
277
  },
250
278
  onUpdate: (values) => {
279
+ hueSliderProps?.onUpdate?.(values);
251
280
  updateHueSlider(values[0], false);
252
281
  },
253
- min: 0,
254
- max: 359,
255
282
  thumbProps: () => ({
256
283
  'aria-label': 'Hue',
284
+ ...hueSliderProps?.thumbProps,
257
285
  }),
258
286
  }),
259
287
  showAlpha &&
@@ -261,25 +289,31 @@ export const ColorBuilder = React.forwardRef((props, ref) => {
261
289
  minLabel: '',
262
290
  maxLabel: '',
263
291
  values: [alphaValue],
264
- className: 'iui-opacity-slider',
265
292
  trackDisplayMode: 'none',
293
+ min: 0,
294
+ max: 1,
295
+ step: 0.01,
296
+ ...opacitySliderProps,
297
+ className: cx('iui-opacity-slider', opacitySliderProps?.className),
266
298
  tooltipProps: () => ({
267
299
  visible: false,
300
+ ...opacitySliderProps?.tooltipProps,
268
301
  }),
269
302
  onChange: (values) => {
303
+ opacitySliderProps?.onChange?.(values);
270
304
  updateOpacitySlider(values[0], true);
271
305
  },
272
306
  onUpdate: (values) => {
307
+ opacitySliderProps?.onUpdate?.(values);
273
308
  updateOpacitySlider(values[0], false);
274
309
  },
275
- min: 0,
276
- max: 1,
277
- step: 0.01,
278
310
  style: {
279
311
  '--iui-color-picker-selected-color': hueColorString,
312
+ ...opacitySliderProps?.style,
280
313
  },
281
314
  thumbProps: () => ({
282
315
  'aria-label': 'Opacity',
316
+ ...opacitySliderProps?.thumbProps,
283
317
  }),
284
318
  }),
285
319
  );
@@ -1,3 +1,5 @@
1
+ import * as React from 'react';
2
+ import { IconButton } from '../Buttons/IconButton.js';
1
3
  import type { PolymorphicForwardRefComponent } from '../../utils/index.js';
2
4
  type ColorInputPanelProps = {
3
5
  /**
@@ -12,6 +14,22 @@ type ColorInputPanelProps = {
12
14
  * @default ['hsl', 'rgb', 'hex']
13
15
  */
14
16
  allowedColorFormats?: ('hsl' | 'rgb' | 'hex')[];
17
+ /**
18
+ * Passes props to the color picker section label.
19
+ */
20
+ panelLabelProps?: React.ComponentProps<'div'>;
21
+ /**
22
+ * Passes props to the color input container.
23
+ */
24
+ colorInputContainerProps?: React.ComponentProps<'div'>;
25
+ /**
26
+ * Passes props to the color input fields group.
27
+ */
28
+ inputFieldsGroupProps?: React.ComponentProps<'div'>;
29
+ /**
30
+ * Passes props to the swap color format button.
31
+ */
32
+ swapColorFormatButtonProps?: React.ComponentProps<typeof IconButton>;
15
33
  };
16
34
  /**
17
35
  * `ColorInputPanel` shows input fields to enter precise color values in the specified format.
@@ -2,13 +2,24 @@ import * as React from 'react';
2
2
  import cx from 'classnames';
3
3
  import { IconButton } from '../Buttons/IconButton.js';
4
4
  import { Input } from '../Input/Input.js';
5
- import { ColorValue, SvgSwap, Box, useId } from '../../utils/index.js';
5
+ import {
6
+ ColorValue,
7
+ SvgSwap,
8
+ Box,
9
+ useId,
10
+ useMergedRefs,
11
+ mergeEventHandlers,
12
+ } from '../../utils/index.js';
6
13
  import { useColorPickerContext } from './ColorPickerContext.js';
7
14
  export const ColorInputPanel = React.forwardRef((props, ref) => {
8
15
  let {
9
16
  defaultColorFormat,
10
17
  allowedColorFormats = ['hsl', 'rgb', 'hex'],
11
18
  className,
19
+ colorInputContainerProps,
20
+ panelLabelProps,
21
+ inputFieldsGroupProps,
22
+ swapColorFormatButtonProps,
12
23
  ...rest
13
24
  } = props;
14
25
  let inputsContainerRef = React.useRef(null);
@@ -352,10 +363,12 @@ export const ColorInputPanel = React.forwardRef((props, ref) => {
352
363
  Number(input[3]) < 0 || Number(input[3]) > 1 ? 'negative' : void 0,
353
364
  }),
354
365
  );
355
- let labelId = useId();
366
+ let fallbackLabelId = useId();
367
+ let labelId = panelLabelProps?.id ?? fallbackLabelId;
356
368
  return React.createElement(
357
369
  Box,
358
370
  {
371
+ as: 'div',
359
372
  className: cx('iui-color-input-wrapper', className),
360
373
  ref: ref,
361
374
  ...rest,
@@ -363,7 +376,12 @@ export const ColorInputPanel = React.forwardRef((props, ref) => {
363
376
  React.createElement(
364
377
  Box,
365
378
  {
366
- className: 'iui-color-picker-section-label',
379
+ as: 'div',
380
+ ...panelLabelProps,
381
+ className: cx(
382
+ 'iui-color-picker-section-label',
383
+ panelLabelProps?.className,
384
+ ),
367
385
  id: labelId,
368
386
  },
369
387
  showAlpha && 'hex' !== currentFormat
@@ -373,26 +391,37 @@ export const ColorInputPanel = React.forwardRef((props, ref) => {
373
391
  React.createElement(
374
392
  Box,
375
393
  {
376
- className: 'iui-color-input',
394
+ as: 'div',
395
+ ...colorInputContainerProps,
396
+ className: cx('iui-color-input', colorInputContainerProps?.className),
377
397
  },
378
398
  allowedColorFormats.length > 1 &&
379
399
  React.createElement(
380
400
  IconButton,
381
401
  {
382
- styleType: 'borderless',
383
- onClick: swapColorFormat,
384
402
  size: 'small',
403
+ styleType: 'borderless',
385
404
  label: 'Switch format',
405
+ ...swapColorFormatButtonProps,
406
+ onClick: mergeEventHandlers(
407
+ swapColorFormatButtonProps?.onClick,
408
+ swapColorFormat,
409
+ ),
386
410
  },
387
411
  React.createElement(SvgSwap, null),
388
412
  ),
389
413
  React.createElement(
390
414
  Box,
391
415
  {
392
- ref: inputsContainerRef,
393
- className: 'iui-color-input-fields',
416
+ as: 'div',
394
417
  role: 'hex' !== currentFormat ? 'group' : void 0,
395
418
  'aria-labelledby': 'hex' !== currentFormat ? labelId : void 0,
419
+ ...inputFieldsGroupProps,
420
+ ref: useMergedRefs(inputsContainerRef, inputFieldsGroupProps?.ref),
421
+ className: cx(
422
+ 'iui-color-input-fields',
423
+ inputFieldsGroupProps?.className,
424
+ ),
396
425
  },
397
426
  'hex' === currentFormat && hexInputField,
398
427
  'rgb' === currentFormat && rgbInputs,
@@ -6,6 +6,10 @@ export type ColorPaletteProps = {
6
6
  * Label shown above the palette.
7
7
  */
8
8
  label?: React.ReactNode;
9
+ /**
10
+ * Passes props to the color picker section label.
11
+ */
12
+ labelProps?: React.ComponentProps<'div'>;
9
13
  /**
10
14
  * List of colors shown as swatches in the palette.
11
15
  */
@@ -14,6 +18,10 @@ export type ColorPaletteProps = {
14
18
  * Pass any custom swatches as children.
15
19
  */
16
20
  children?: React.ReactNode;
21
+ /**
22
+ * Passes props to the color palette container.
23
+ */
24
+ paletteContainerProps?: React.ComponentProps<'div'>;
17
25
  };
18
26
  /**
19
27
  * `ColorPalette` is used to show a group of `ColorSwatch` components.
@@ -5,7 +5,15 @@ import { getColorValue } from './ColorPicker.js';
5
5
  import { ColorSwatch } from './ColorSwatch.js';
6
6
  import { useColorPickerContext } from './ColorPickerContext.js';
7
7
  export const ColorPalette = React.forwardRef((props, ref) => {
8
- let { colors, label, className, children, ...rest } = props;
8
+ let {
9
+ colors,
10
+ label,
11
+ labelProps,
12
+ className,
13
+ children,
14
+ paletteContainerProps,
15
+ ...rest
16
+ } = props;
9
17
  let { activeColor, setActiveColor, onChangeComplete } =
10
18
  useColorPickerContext();
11
19
  return React.createElement(
@@ -19,14 +27,21 @@ export const ColorPalette = React.forwardRef((props, ref) => {
19
27
  React.createElement(
20
28
  Box,
21
29
  {
22
- className: 'iui-color-picker-section-label',
30
+ as: 'div',
31
+ ...labelProps,
32
+ className: cx(
33
+ 'iui-color-picker-section-label',
34
+ labelProps?.className,
35
+ ),
23
36
  },
24
37
  label,
25
38
  ),
26
39
  React.createElement(
27
40
  Box,
28
41
  {
29
- className: 'iui-color-palette',
42
+ as: 'div',
43
+ ...paletteContainerProps,
44
+ className: cx('iui-color-palette', paletteContainerProps?.className),
30
45
  },
31
46
  children,
32
47
  colors &&
@@ -1,7 +1,8 @@
1
1
  import * as React from 'react';
2
2
  import type { SelectOption } from '../Select/Select.js';
3
3
  import type { Input } from '../Input/Input.js';
4
- import type { InputContainerProps, CommonProps } from '../../utils/index.js';
4
+ import { usePopover } from '../Popover/Popover.js';
5
+ import type { InputContainerProps, CommonProps, PortalProps } from '../../utils/index.js';
5
6
  import { ComboBoxEndIcon } from './ComboBoxEndIcon.js';
6
7
  type ActionType = 'added' | 'removed';
7
8
  type MultipleOnChangeProps<T> = {
@@ -59,7 +60,7 @@ export type ComboBoxProps<T> = {
59
60
  /**
60
61
  * Props to customize dropdown menu behavior.
61
62
  */
62
- dropdownMenuProps?: React.ComponentProps<'div'>;
63
+ dropdownMenuProps?: React.ComponentProps<'div'> & Pick<Parameters<typeof usePopover>['0'], 'middleware'> & Pick<PortalProps, 'portal'>;
63
64
  /**
64
65
  * End icon props.
65
66
  */
@@ -38,7 +38,7 @@ export const ComboBox = React.forwardRef((props, forwardedRef) => {
38
38
  filterFunction = defaultFilterFunction,
39
39
  inputProps,
40
40
  endIconProps,
41
- dropdownMenuProps,
41
+ dropdownMenuProps: { middleware, ...dropdownMenuProps } = {},
42
42
  emptyStateMessage = 'No options found',
43
43
  itemRenderer,
44
44
  enableVirtualization = false,
@@ -318,6 +318,7 @@ export const ComboBox = React.forwardRef((props, forwardedRef) => {
318
318
  size: {
319
319
  maxHeight: 'var(--iui-menu-max-height)',
320
320
  },
321
+ ...middleware,
321
322
  },
322
323
  closeOnOutsideClick: true,
323
324
  interactions: {
@@ -90,7 +90,7 @@ let VirtualizedComboBoxMenu = (props) => {
90
90
  );
91
91
  };
92
92
  export const ComboBoxMenu = React.forwardRef((props, forwardedRef) => {
93
- let { className, children, style, ...rest } = props;
93
+ let { className, children, style, portal = true, ...rest } = props;
94
94
  let { id, enableVirtualization, popover } =
95
95
  useSafeContext(ComboBoxStateContext);
96
96
  let { menuRef } = useSafeContext(ComboBoxRefsContext);
@@ -100,7 +100,7 @@ export const ComboBoxMenu = React.forwardRef((props, forwardedRef) => {
100
100
  React.createElement(
101
101
  Portal,
102
102
  {
103
- portal: true,
103
+ portal: portal,
104
104
  },
105
105
  React.createElement(
106
106
  List,
@@ -16,6 +16,17 @@ export type DropdownMenuProps = {
16
16
  * Child element to wrap dropdown with.
17
17
  */
18
18
  children: React.ReactNode;
19
+ /**
20
+ * Middleware options.
21
+ *
22
+ * By default, `hide` is enabled. If the menu gets hidden even when it shouldn't (e.g. some custom styles interfering
23
+ * with the trigger's hide detection) consider disabling the `hide` middleware.
24
+ *
25
+ * @see https://floating-ui.com/docs/middleware
26
+ */
27
+ middleware?: {
28
+ hide?: boolean;
29
+ };
19
30
  } & Pick<Parameters<typeof usePopover>[0], 'visible' | 'onVisibleChange' | 'placement' | 'matchWidth'> & Pick<PortalProps, 'portal'>;
20
31
  /**
21
32
  * Dropdown menu component.
@@ -22,6 +22,7 @@ let DropdownMenuContent = React.forwardRef((props, forwardedRef) => {
22
22
  matchWidth = false,
23
23
  onVisibleChange,
24
24
  portal = true,
25
+ middleware,
25
26
  ...rest
26
27
  } = props;
27
28
  let [visible, setVisible] = useControlledState(
@@ -35,28 +36,28 @@ let DropdownMenuContent = React.forwardRef((props, forwardedRef) => {
35
36
  return menuItems;
36
37
  }, [menuItems, setVisible]);
37
38
  return React.createElement(
38
- React.Fragment,
39
- null,
40
- React.createElement(
41
- Menu,
42
- {
43
- trigger: children,
44
- onKeyDown: mergeEventHandlers(props.onKeyDown, (e) => {
45
- if (e.defaultPrevented) return;
46
- if ('Tab' === e.key) setVisible(false);
47
- }),
48
- role: role,
49
- ref: forwardedRef,
50
- portal: portal,
51
- popoverProps: {
39
+ Menu,
40
+ {
41
+ trigger: children,
42
+ onKeyDown: mergeEventHandlers(props.onKeyDown, (e) => {
43
+ if (e.defaultPrevented) return;
44
+ if ('Tab' === e.key) setVisible(false);
45
+ }),
46
+ role: role,
47
+ ref: forwardedRef,
48
+ portal: portal,
49
+ popoverProps: React.useMemo(
50
+ () => ({
52
51
  placement,
53
52
  matchWidth,
54
53
  visible,
55
54
  onVisibleChange: setVisible,
56
- },
57
- ...rest,
58
- },
59
- menuContent,
60
- ),
55
+ middleware,
56
+ }),
57
+ [matchWidth, middleware, placement, setVisible, visible],
58
+ ),
59
+ ...rest,
60
+ },
61
+ menuContent,
61
62
  );
62
63
  });
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { Box, isUnitTest, polymorphic } from '../../utils/index.js';
2
+ import { Box, polymorphic } from '../../utils/index.js';
3
3
  let OverlayComponent = React.forwardRef((props, forwardedRef) => {
4
4
  let { content, children, ...rest } = props;
5
5
  return React.createElement(
@@ -14,7 +14,6 @@ let OverlayComponent = React.forwardRef((props, forwardedRef) => {
14
14
  });
15
15
  let OverlayHiddenContent = React.forwardRef((props, ref) => {
16
16
  let { children, ...rest } = props;
17
- useInertPolyfill();
18
17
  return React.createElement(
19
18
  Box,
20
19
  {
@@ -32,20 +31,3 @@ export const Overlay = Object.assign(OverlayComponent, {
32
31
  HiddenContent: OverlayHiddenContent,
33
32
  Overlay: OverlayOverlay,
34
33
  });
35
- let useInertPolyfill = () => {
36
- let loaded = React.useRef(false);
37
- let modulePath =
38
- 'https://cdn.jsdelivr.net/npm/wicg-inert@3.1.2/dist/inert.min.js';
39
- React.useEffect(() => {
40
- (async () => {
41
- if (
42
- !HTMLElement.prototype.hasOwnProperty('inert') &&
43
- !loaded.current &&
44
- !isUnitTest
45
- ) {
46
- await new Function('url', 'return import(url)')(modulePath);
47
- loaded.current = true;
48
- }
49
- })();
50
- }, []);
51
- };
@@ -26,7 +26,10 @@ type PopoverOptions = {
26
26
  /**
27
27
  * Middleware options.
28
28
  *
29
- * By default, `flip`, `shift` and `size` are enabled.
29
+ * By default, `flip`, `shift`, `size`, and `hide` are enabled.
30
+ *
31
+ * If the floating content gets hidden even when it shouldn't (e.g. some custom styles interfering with the trigger's
32
+ * hide detection) consider disabling the `hide` middleware.
30
33
  *
31
34
  * @see https://floating-ui.com/docs/middleware
32
35
  */
@@ -25,6 +25,7 @@ import {
25
25
  Box,
26
26
  ShadowRoot,
27
27
  cloneElementWithRef,
28
+ isUnitTest,
28
29
  mergeEventHandlers,
29
30
  useControlledState,
30
31
  useId,
@@ -47,21 +48,22 @@ export const usePopover = (options) => {
47
48
  } = options;
48
49
  let mergedInteractions = React.useMemo(
49
50
  () => ({
50
- click: true,
51
- dismiss: true,
52
- hover: false,
53
- focus: false,
54
51
  ...interactionsProp,
52
+ click: interactionsProp?.click ?? true,
53
+ dismiss: interactionsProp?.dismiss ?? true,
54
+ hover: interactionsProp?.hover ?? false,
55
+ focus: interactionsProp?.focus ?? false,
55
56
  }),
56
57
  [interactionsProp],
57
58
  );
58
59
  let tree = useFloatingTree();
59
60
  let middleware = React.useMemo(
60
61
  () => ({
61
- flip: true,
62
- shift: true,
63
- size: true,
64
62
  ...options.middleware,
63
+ flip: options.middleware?.flip ?? true,
64
+ shift: options.middleware?.shift ?? true,
65
+ size: options.middleware?.size ?? true,
66
+ hide: options.middleware?.hide || !isUnitTest,
65
67
  }),
66
68
  [options.middleware],
67
69
  );
@@ -166,17 +168,23 @@ export const usePopover = (options) => {
166
168
  maxInlineSize: `min(${2 * referenceWidth}px, 90vw)`,
167
169
  }
168
170
  : {}),
171
+ ...(middleware.hide &&
172
+ floating.middlewareData.hide?.referenceHidden && {
173
+ visibility: 'hidden',
174
+ }),
169
175
  ...userProps?.style,
170
176
  },
171
177
  }),
172
178
  [
173
- floating.floatingStyles,
174
179
  interactions,
175
- matchWidth,
176
- referenceWidth,
180
+ floating.floatingStyles,
181
+ floating.middlewareData.hide?.referenceHidden,
177
182
  middleware.size,
183
+ middleware.hide,
178
184
  availableHeight,
179
185
  maxHeight,
186
+ matchWidth,
187
+ referenceWidth,
180
188
  ],
181
189
  );
182
190
  let getReferenceProps = React.useCallback(
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import type { CommonProps } from '../../utils/index.js';
2
+ import type { CommonProps, PortalProps } from '../../utils/index.js';
3
3
  import { usePopover } from '../Popover/Popover.js';
4
4
  /**
5
5
  * Select component to select value from options.
@@ -182,7 +182,19 @@ export type CustomSelectProps<T> = SelectCommonProps & {
182
182
  /**
183
183
  * Props to customize Popover behavior.
184
184
  */
185
- popoverProps?: Pick<Parameters<typeof usePopover>[0], 'visible' | 'onVisibleChange' | 'placement' | 'matchWidth' | 'closeOnOutsideClick'>;
185
+ popoverProps?: Pick<Parameters<typeof usePopover>[0], 'visible' | 'onVisibleChange' | 'placement' | 'matchWidth' | 'closeOnOutsideClick'> & {
186
+ /**
187
+ * Middleware options.
188
+ *
189
+ * By default, `hide` is enabled. If the floating options get hidden even when they shouldn't (e.g. some custom
190
+ * styles interfering with the trigger's hide detection) consider disabling the `hide` middleware.
191
+ *
192
+ * @see https://floating-ui.com/docs/middleware
193
+ */
194
+ middleware?: {
195
+ hide?: boolean;
196
+ };
197
+ } & Pick<PortalProps, 'portal'>;
186
198
  /**
187
199
  * Props to pass to the select button (trigger) element.
188
200
  */
@@ -109,7 +109,7 @@ let CustomSelect = React.forwardRef((props, forwardedRef) => {
109
109
  multiple = false,
110
110
  triggerProps,
111
111
  status,
112
- popoverProps,
112
+ popoverProps: { portal = true, ...popoverProps } = {},
113
113
  styleType,
114
114
  ...rest
115
115
  } = props;
@@ -303,7 +303,9 @@ let CustomSelect = React.forwardRef((props, forwardedRef) => {
303
303
  popover.open &&
304
304
  React.createElement(
305
305
  Portal,
306
- null,
306
+ {
307
+ portal: portal,
308
+ },
307
309
  React.createElement(
308
310
  SelectListbox,
309
311
  {