@itwin/itwinui-react 3.10.1 → 3.11.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 (43) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/cjs/core/Alert/Alert.d.ts +1 -1
  3. package/cjs/core/Buttons/Button.d.ts +4 -0
  4. package/cjs/core/Buttons/Button.js +6 -4
  5. package/cjs/core/Carousel/Carousel.d.ts +2 -2
  6. package/cjs/core/Carousel/CarouselNavigation.d.ts +2 -2
  7. package/cjs/core/ComboBox/ComboBoxInput.js +2 -4
  8. package/cjs/core/ComboBox/ComboBoxMenu.js +7 -3
  9. package/cjs/core/ExpandableBlock/ExpandableBlock.d.ts +1 -1
  10. package/cjs/core/InputWithDecorations/InputWithDecorations.d.ts +1 -1
  11. package/cjs/core/LabeledSelect/LabeledSelect.d.ts +9 -9
  12. package/cjs/core/Select/Select.js +28 -2
  13. package/cjs/core/Surface/Surface.js +2 -2
  14. package/cjs/core/Table/Table.js +4 -7
  15. package/cjs/core/Tabs/Tabs.d.ts +1 -1
  16. package/cjs/core/Tile/Tile.d.ts +17 -1
  17. package/cjs/core/Tooltip/Tooltip.js +28 -6
  18. package/cjs/core/Tree/TreeNode.d.ts +39 -0
  19. package/cjs/core/Tree/TreeNode.js +11 -11
  20. package/cjs/core/Tree/TreeNodeExpander.d.ts +2 -0
  21. package/cjs/core/Tree/TreeNodeExpander.js +2 -2
  22. package/esm/core/Alert/Alert.d.ts +1 -1
  23. package/esm/core/Buttons/Button.d.ts +4 -0
  24. package/esm/core/Buttons/Button.js +6 -4
  25. package/esm/core/Carousel/Carousel.d.ts +2 -2
  26. package/esm/core/Carousel/CarouselNavigation.d.ts +2 -2
  27. package/esm/core/ComboBox/ComboBoxInput.js +3 -5
  28. package/esm/core/ComboBox/ComboBoxMenu.js +4 -2
  29. package/esm/core/ExpandableBlock/ExpandableBlock.d.ts +1 -1
  30. package/esm/core/InputWithDecorations/InputWithDecorations.d.ts +1 -1
  31. package/esm/core/LabeledSelect/LabeledSelect.d.ts +9 -9
  32. package/esm/core/Select/Select.js +28 -2
  33. package/esm/core/Surface/Surface.js +2 -2
  34. package/esm/core/Table/Table.js +5 -8
  35. package/esm/core/Tabs/Tabs.d.ts +1 -1
  36. package/esm/core/Tile/Tile.d.ts +17 -1
  37. package/esm/core/Tooltip/Tooltip.js +28 -6
  38. package/esm/core/Tree/TreeNode.d.ts +39 -0
  39. package/esm/core/Tree/TreeNode.js +11 -11
  40. package/esm/core/Tree/TreeNodeExpander.d.ts +2 -0
  41. package/esm/core/Tree/TreeNodeExpander.js +2 -2
  42. package/package.json +1 -1
  43. package/styles.css +21 -21
@@ -1,7 +1,9 @@
1
+ import * as React from 'react';
1
2
  import type { PolymorphicForwardRefComponent } from '../../utils/index.js';
2
3
  import type { IconButtonProps } from '../Buttons/IconButton.js';
3
4
  type TreeNodeExpanderProps = {
4
5
  isExpanded?: boolean;
6
+ expanderIconProps?: React.ComponentProps<'svg'>;
5
7
  } & IconButtonProps;
6
8
  export declare const TreeNodeExpander: PolymorphicForwardRefComponent<"button", TreeNodeExpanderProps>;
7
9
  export {};
@@ -37,11 +37,11 @@ const index_js_1 = require("../../utils/index.js");
37
37
  const IconButton_js_1 = require("../Buttons/IconButton.js");
38
38
  const TreeContext_js_1 = require("./TreeContext.js");
39
39
  exports.TreeNodeExpander = React.forwardRef((props, ref) => {
40
- const { isExpanded, ...rest } = props;
40
+ const { isExpanded, expanderIconProps = {}, ...rest } = props;
41
41
  const size = React.useContext(TreeContext_js_1.TreeContext)?.size ?? 'default';
42
42
  const ChevronIcon = size === 'small' ? index_js_1.SvgChevronRightSmall : index_js_1.SvgChevronRight;
43
43
  return (React.createElement(IconButton_js_1.IconButton, { styleType: 'borderless', size: 'small', "aria-label": isExpanded ? 'Collapse' : 'Expand', ref: ref, ...rest },
44
- React.createElement(ChevronIcon, { className: (0, classnames_1.default)('iui-tree-node-content-expander-icon', {
44
+ React.createElement(ChevronIcon, { ...expanderIconProps, className: (0, classnames_1.default)('iui-tree-node-content-expander-icon', expanderIconProps?.className, {
45
45
  'iui-tree-node-content-expander-icon-expanded': isExpanded,
46
46
  }) })));
47
47
  });
@@ -60,7 +60,7 @@ export declare const Alert: PolymorphicForwardRefComponent<"div", AlertOwnProps
60
60
  * Type of the alert.
61
61
  * @default 'informational'
62
62
  */
63
- fill?: "default" | import("../../utils/types.js").AnyString | "informational" | "negative" | "positive" | "warning" | undefined;
63
+ fill?: "default" | "positive" | "negative" | "warning" | import("../../utils/types.js").AnyString | "informational" | undefined;
64
64
  padded?: boolean | undefined;
65
65
  } & Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & {
66
66
  as?: "span" | undefined;
@@ -38,6 +38,10 @@ export type ButtonProps = {
38
38
  * This is useful on narrow containers and mobile views.
39
39
  */
40
40
  stretched?: boolean;
41
+ /**
42
+ * Specify a loading state for the button.
43
+ */
44
+ loading?: boolean;
41
45
  } & Pick<React.ComponentProps<typeof ButtonBase>, 'htmlDisabled'>;
42
46
  /**
43
47
  * Generic button component
@@ -5,6 +5,7 @@
5
5
  import cx from 'classnames';
6
6
  import * as React from 'react';
7
7
  import { Box, ButtonBase } from '../../utils/index.js';
8
+ import { ProgressRadial } from '../ProgressIndicators/ProgressRadial.js';
8
9
  /**
9
10
  * Generic button component
10
11
  * @example
@@ -15,12 +16,13 @@ import { Box, ButtonBase } from '../../utils/index.js';
15
16
  * <Button startIcon={<SvgAdd />}>New</Button>
16
17
  */
17
18
  export const Button = React.forwardRef((props, ref) => {
18
- const { children, className, size, styleType = 'default', startIcon, endIcon, labelProps, startIconProps, endIconProps, stretched, ...rest } = props;
19
- return (React.createElement(ButtonBase, { ref: ref, className: cx('iui-button', 'iui-field', className), "data-iui-variant": styleType !== 'default' ? styleType : undefined, "data-iui-size": size, ...rest, style: {
19
+ const { children, className, size, styleType = 'default', startIcon, endIcon, labelProps, startIconProps, endIconProps, stretched, loading: loading, disabled: disabledProp, ...rest } = props;
20
+ return (React.createElement(ButtonBase, { ref: ref, className: cx('iui-button', 'iui-field', className), "data-iui-variant": styleType !== 'default' ? styleType : undefined, "data-iui-size": size, "data-iui-loading": loading ? 'true' : undefined, disabled: disabledProp || loading, ...rest, style: {
20
21
  '--_iui-width': stretched ? '100%' : undefined,
21
22
  ...props.style,
22
23
  } },
23
24
  startIcon && (React.createElement(Box, { as: 'span', "aria-hidden": true, ...startIconProps, className: cx('iui-button-icon', startIconProps?.className) }, startIcon)),
24
- children && React.createElement("span", { ...labelProps }, children),
25
- endIcon && (React.createElement(Box, { as: 'span', "aria-hidden": true, ...endIconProps, className: cx('iui-button-icon', endIconProps?.className) }, endIcon))));
25
+ children && (React.createElement(Box, { as: 'span', ...labelProps, className: cx('iui-button-label', labelProps?.className) }, children)),
26
+ endIcon && (React.createElement(Box, { as: 'span', "aria-hidden": true, ...endIconProps, className: cx('iui-button-icon', endIconProps?.className) }, endIcon)),
27
+ loading && (React.createElement(ProgressRadial, { size: size === 'small' ? 'x-small' : 'small', className: 'iui-button-spinner', "aria-hidden": true }))));
26
28
  });
@@ -42,7 +42,7 @@ export declare const Carousel: PolymorphicForwardRefComponent<"section", Carouse
42
42
  Navigation: PolymorphicForwardRefComponent<"div", {}> & {
43
43
  PreviousButton: PolymorphicForwardRefComponent<"button", Omit<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
44
44
  ref?: ((instance: HTMLButtonElement | null) => void) | React.RefObject<HTMLButtonElement> | null | undefined;
45
- }, "label" | "as" | "size" | "htmlDisabled" | "styleType" | "labelProps" | "stretched" | "isActive" | "iconProps"> & {
45
+ }, "label" | "as" | "loading" | "size" | "htmlDisabled" | "styleType" | "labelProps" | "stretched" | "isActive" | "iconProps"> & {
46
46
  isActive?: boolean | undefined;
47
47
  label?: React.ReactNode;
48
48
  labelProps?: Omit<Omit<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
@@ -105,7 +105,7 @@ export declare const Carousel: PolymorphicForwardRefComponent<"section", Carouse
105
105
  }>;
106
106
  NextButton: PolymorphicForwardRefComponent<"button", Omit<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
107
107
  ref?: ((instance: HTMLButtonElement | null) => void) | React.RefObject<HTMLButtonElement> | null | undefined;
108
- }, "label" | "as" | "size" | "htmlDisabled" | "styleType" | "labelProps" | "stretched" | "isActive" | "iconProps"> & {
108
+ }, "label" | "as" | "loading" | "size" | "htmlDisabled" | "styleType" | "labelProps" | "stretched" | "isActive" | "iconProps"> & {
109
109
  isActive?: boolean | undefined;
110
110
  label?: React.ReactNode;
111
111
  labelProps?: Omit<Omit<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
@@ -9,7 +9,7 @@ import type { PolymorphicForwardRefComponent } from '../../utils/index.js';
9
9
  export declare const CarouselNavigation: PolymorphicForwardRefComponent<"div", {}> & {
10
10
  PreviousButton: PolymorphicForwardRefComponent<"button", Omit<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
11
11
  ref?: ((instance: HTMLButtonElement | null) => void) | React.RefObject<HTMLButtonElement> | null | undefined;
12
- }, "label" | "as" | "size" | "htmlDisabled" | "styleType" | "labelProps" | "stretched" | "isActive" | "iconProps"> & {
12
+ }, "label" | "as" | "loading" | "size" | "htmlDisabled" | "styleType" | "labelProps" | "stretched" | "isActive" | "iconProps"> & {
13
13
  isActive?: boolean | undefined;
14
14
  label?: React.ReactNode;
15
15
  labelProps?: Omit<Omit<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
@@ -72,7 +72,7 @@ export declare const CarouselNavigation: PolymorphicForwardRefComponent<"div", {
72
72
  }>;
73
73
  NextButton: PolymorphicForwardRefComponent<"button", Omit<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
74
74
  ref?: ((instance: HTMLButtonElement | null) => void) | React.RefObject<HTMLButtonElement> | null | undefined;
75
- }, "label" | "as" | "size" | "htmlDisabled" | "styleType" | "labelProps" | "stretched" | "isActive" | "iconProps"> & {
75
+ }, "label" | "as" | "loading" | "size" | "htmlDisabled" | "styleType" | "labelProps" | "stretched" | "isActive" | "iconProps"> & {
76
76
  isActive?: boolean | undefined;
77
77
  label?: React.ReactNode;
78
78
  labelProps?: Omit<Omit<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
@@ -4,7 +4,7 @@
4
4
  *--------------------------------------------------------------------------------------------*/
5
5
  import * as React from 'react';
6
6
  import { Input } from '../Input/Input.js';
7
- import { useSafeContext, useMergedRefs, useContainerWidth, mergeEventHandlers, } from '../../utils/index.js';
7
+ import { useSafeContext, useMergedRefs, useContainerWidth, mergeEventHandlers, useLatestRef, } from '../../utils/index.js';
8
8
  import { ComboBoxMultipleContainer } from './ComboBoxMultipleContainer.js';
9
9
  import { ComboBoxStateContext, ComboBoxActionContext, ComboBoxRefsContext, } from './helpers.js';
10
10
  export const ComboBoxInput = React.forwardRef((props, forwardedRef) => {
@@ -13,10 +13,7 @@ export const ComboBoxInput = React.forwardRef((props, forwardedRef) => {
13
13
  const dispatch = useSafeContext(ComboBoxActionContext);
14
14
  const { inputRef, menuRef, optionsExtraInfoRef } = useSafeContext(ComboBoxRefsContext);
15
15
  const refs = useMergedRefs(inputRef, popover.refs.setReference, forwardedRef);
16
- const focusedIndexRef = React.useRef(focusedIndex ?? -1);
17
- React.useEffect(() => {
18
- focusedIndexRef.current = focusedIndex ?? -1;
19
- }, [focusedIndex]);
16
+ const focusedIndexRef = useLatestRef(focusedIndex ?? -1);
20
17
  const getIdFromIndex = (index) => {
21
18
  return (menuRef.current?.querySelector(`[data-iui-index="${index}"]`)?.id ?? '');
22
19
  };
@@ -114,6 +111,7 @@ export const ComboBoxInput = React.forwardRef((props, forwardedRef) => {
114
111
  }, [
115
112
  dispatch,
116
113
  enableVirtualization,
114
+ focusedIndexRef,
117
115
  isOpen,
118
116
  menuRef,
119
117
  onClickHandler,
@@ -3,9 +3,11 @@
3
3
  * See LICENSE.md in the project root for license terms and full copyright notice.
4
4
  *--------------------------------------------------------------------------------------------*/
5
5
  import * as React from 'react';
6
+ import cx from 'classnames';
6
7
  import { Menu } from '../Menu/Menu.js';
7
8
  import { useSafeContext, useMergedRefs, useVirtualization, Portal, Box, } from '../../utils/index.js';
8
9
  import { ComboBoxStateContext, ComboBoxRefsContext } from './helpers.js';
10
+ import { List } from '../List/List.js';
9
11
  const VirtualizedComboBoxMenu = (props) => {
10
12
  const { children, ...rest } = props;
11
13
  const { filteredOptions, getMenuItem, focusedIndex } = useSafeContext(ComboBoxStateContext);
@@ -32,12 +34,12 @@ const VirtualizedComboBoxMenu = (props) => {
32
34
  React.createElement("div", { ...innerProps, ref: innerProps.ref }, visibleChildren)));
33
35
  };
34
36
  export const ComboBoxMenu = React.forwardRef((props, forwardedRef) => {
35
- const { children, style, ...rest } = props;
37
+ const { className, children, style, ...rest } = props;
36
38
  const { id, enableVirtualization, popover } = useSafeContext(ComboBoxStateContext);
37
39
  const { menuRef } = useSafeContext(ComboBoxRefsContext);
38
40
  const refs = useMergedRefs(popover.refs.setFloating, forwardedRef, menuRef);
39
41
  return (popover.open && (React.createElement(Portal, { portal: true },
40
- React.createElement(Menu, { id: `${id}-list`, setFocus: false, role: 'listbox', ref: refs, ...popover.getFloatingProps({
42
+ React.createElement(List, { as: 'div', className: cx('iui-menu', className), id: `${id}-list`, role: 'listbox', ref: refs, ...popover.getFloatingProps({
41
43
  style: !enableVirtualization
42
44
  ? style
43
45
  : {
@@ -107,7 +107,7 @@ export declare const ExpandableBlock: PolymorphicForwardRefComponent<"div", Expa
107
107
  ref?: ((instance: HTMLSpanElement | null) => void) | React.RefObject<HTMLSpanElement> | null | undefined;
108
108
  }, "fill" | "as" | "key" | "size" | keyof React.HTMLAttributes<HTMLSpanElement> | "padded"> & {
109
109
  size?: "small" | "auto" | "medium" | "large" | import("../../utils/types.js").AnyString | undefined;
110
- fill?: "default" | import("../../utils/types.js").AnyString | "informational" | "negative" | "positive" | "warning" | undefined;
110
+ fill?: "default" | "positive" | "negative" | "warning" | import("../../utils/types.js").AnyString | "informational" | undefined;
111
111
  padded?: boolean | undefined;
112
112
  } & Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & {
113
113
  as?: "span" | undefined;
@@ -32,7 +32,7 @@ export declare const InputWithDecorations: PolymorphicForwardRefComponent<"div",
32
32
  */
33
33
  Button: PolymorphicForwardRefComponent<"button", Omit<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
34
34
  ref?: ((instance: HTMLButtonElement | null) => void) | React.RefObject<HTMLButtonElement> | null | undefined;
35
- }, "label" | "as" | "size" | "htmlDisabled" | "styleType" | "labelProps" | "stretched" | "isActive" | "iconProps"> & Omit<import("../Buttons/IconButton.js").IconButtonProps, "styleType"> & {
35
+ }, "label" | "as" | "loading" | "size" | "htmlDisabled" | "styleType" | "labelProps" | "stretched" | "isActive" | "iconProps"> & Omit<import("../Buttons/IconButton.js").IconButtonProps, "styleType"> & {
36
36
  styleType?: "default" | "cta" | "high-visibility" | "borderless" | undefined;
37
37
  } & {
38
38
  as?: "button" | undefined;
@@ -131,7 +131,7 @@ export declare const LabeledSelect: <T>(props: ({
131
131
  * Status of the select.
132
132
  * @default ''
133
133
  */
134
- status?: "negative" | "positive" | "warning" | undefined;
134
+ status?: "positive" | "negative" | "warning" | undefined;
135
135
  /**
136
136
  * @deprecated Pass a `<StatusMessage startIcon={svgIcon} />` to the `message` prop instead.
137
137
  *
@@ -173,7 +173,7 @@ export declare const LabeledSelect: <T>(props: ({
173
173
  ref?: ((instance: HTMLSpanElement | null) => void) | React.RefObject<HTMLSpanElement> | null | undefined;
174
174
  }, "fill" | "as" | "key" | "size" | keyof React.HTMLAttributes<HTMLSpanElement> | "padded"> & {
175
175
  size?: "small" | "auto" | "medium" | "large" | import("../../utils/types.js").AnyString | undefined;
176
- fill?: "default" | import("../../utils/types.js").AnyString | "informational" | "negative" | "positive" | "warning" | undefined;
176
+ fill?: "default" | "positive" | "negative" | "warning" | import("../../utils/types.js").AnyString | "informational" | undefined;
177
177
  padded?: boolean | undefined;
178
178
  } & Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & {
179
179
  as?: "span" | undefined;
@@ -183,7 +183,7 @@ export declare const LabeledSelect: <T>(props: ({
183
183
  } & {
184
184
  disabled?: boolean | undefined;
185
185
  size?: "small" | "large" | undefined;
186
- status?: "negative" | "positive" | "warning" | undefined;
186
+ status?: "positive" | "negative" | "warning" | undefined;
187
187
  } & {
188
188
  value?: string | null | undefined;
189
189
  onChange?: ((value: string, event: React.ChangeEvent<HTMLSelectElement>) => void) | undefined;
@@ -237,7 +237,7 @@ export declare const LabeledSelect: <T>(props: ({
237
237
  * Status of the select.
238
238
  * @default ''
239
239
  */
240
- status?: "negative" | "positive" | "warning" | undefined;
240
+ status?: "positive" | "negative" | "warning" | undefined;
241
241
  /**
242
242
  * @deprecated Pass a `<StatusMessage startIcon={svgIcon} />` to the `message` prop instead.
243
243
  *
@@ -279,7 +279,7 @@ export declare const LabeledSelect: <T>(props: ({
279
279
  ref?: ((instance: HTMLSpanElement | null) => void) | React.RefObject<HTMLSpanElement> | null | undefined;
280
280
  }, "fill" | "as" | "key" | "size" | keyof React.HTMLAttributes<HTMLSpanElement> | "padded"> & {
281
281
  size?: "small" | "auto" | "medium" | "large" | import("../../utils/types.js").AnyString | undefined;
282
- fill?: "default" | import("../../utils/types.js").AnyString | "informational" | "negative" | "positive" | "warning" | undefined;
282
+ fill?: "default" | "positive" | "negative" | "warning" | import("../../utils/types.js").AnyString | "informational" | undefined;
283
283
  padded?: boolean | undefined;
284
284
  } & Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & {
285
285
  as?: "span" | undefined;
@@ -289,7 +289,7 @@ export declare const LabeledSelect: <T>(props: ({
289
289
  } & {
290
290
  disabled?: boolean | undefined;
291
291
  size?: "small" | "large" | undefined;
292
- status?: "negative" | "positive" | "warning" | undefined;
292
+ status?: "positive" | "negative" | "warning" | undefined;
293
293
  } & {
294
294
  placeholder?: React.ReactNode;
295
295
  options: import("../Select/Select.js").SelectOption<T>[];
@@ -378,7 +378,7 @@ export declare const LabeledSelect: <T>(props: ({
378
378
  * Status of the select.
379
379
  * @default ''
380
380
  */
381
- status?: "negative" | "positive" | "warning" | undefined;
381
+ status?: "positive" | "negative" | "warning" | undefined;
382
382
  /**
383
383
  * @deprecated Pass a `<StatusMessage startIcon={svgIcon} />` to the `message` prop instead.
384
384
  *
@@ -420,7 +420,7 @@ export declare const LabeledSelect: <T>(props: ({
420
420
  ref?: ((instance: HTMLSpanElement | null) => void) | React.RefObject<HTMLSpanElement> | null | undefined;
421
421
  }, "fill" | "as" | "key" | "size" | keyof React.HTMLAttributes<HTMLSpanElement> | "padded"> & {
422
422
  size?: "small" | "auto" | "medium" | "large" | import("../../utils/types.js").AnyString | undefined;
423
- fill?: "default" | import("../../utils/types.js").AnyString | "informational" | "negative" | "positive" | "warning" | undefined;
423
+ fill?: "default" | "positive" | "negative" | "warning" | import("../../utils/types.js").AnyString | "informational" | undefined;
424
424
  padded?: boolean | undefined;
425
425
  } & Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & {
426
426
  as?: "span" | undefined;
@@ -430,7 +430,7 @@ export declare const LabeledSelect: <T>(props: ({
430
430
  } & {
431
431
  disabled?: boolean | undefined;
432
432
  size?: "small" | "large" | undefined;
433
- status?: "negative" | "positive" | "warning" | undefined;
433
+ status?: "positive" | "negative" | "warning" | undefined;
434
434
  } & {
435
435
  placeholder?: React.ReactNode;
436
436
  options: import("../Select/Select.js").SelectOption<T>[];
@@ -4,13 +4,14 @@
4
4
  *--------------------------------------------------------------------------------------------*/
5
5
  import * as React from 'react';
6
6
  import cx from 'classnames';
7
- import { Menu } from '../Menu/Menu.js';
8
7
  import { MenuItem } from '../Menu/MenuItem.js';
9
8
  import { SvgCaretDownSmall, useId, AutoclearingHiddenLiveRegion, Box, Portal, useMergedRefs, SvgCheckmark, useLatestRef, InputWithIcon, mergeEventHandlers, } from '../../utils/index.js';
10
9
  import { SelectTag } from './SelectTag.js';
11
10
  import { SelectTagContainer } from './SelectTagContainer.js';
12
11
  import { Icon } from '../Icon/Icon.js';
13
12
  import { usePopover } from '../Popover/Popover.js';
13
+ import { List } from '../List/List.js';
14
+ import { Composite, CompositeItem } from '@floating-ui/react';
14
15
  // ----------------------------------------------------------------------------
15
16
  /**
16
17
  * Select component to select value from options.
@@ -187,6 +188,16 @@ const CustomSelect = React.forwardRef((props, forwardedRef) => {
187
188
  ? options.filter((option) => value.some((val) => val === option.value))
188
189
  : options.find((option) => option.value === value);
189
190
  }, [multiple, options, value]);
191
+ const defaultFocusedIndex = React.useMemo(() => {
192
+ let index = 0;
193
+ if (Array.isArray(value) && value.length > 0) {
194
+ index = options.findIndex((option) => option.value === value[0]);
195
+ }
196
+ else if (value) {
197
+ index = options.findIndex((option) => option.value === value);
198
+ }
199
+ return index >= 0 ? index : 0;
200
+ }, [options, value]);
190
201
  const tagRenderer = React.useCallback((item) => {
191
202
  return React.createElement(SelectTag, { key: item.label, label: item.label });
192
203
  }, []);
@@ -207,7 +218,7 @@ const CustomSelect = React.forwardRef((props, forwardedRef) => {
207
218
  React.createElement(SelectEndIcon, { disabled: disabled, isOpen: isOpen }),
208
219
  multiple ? (React.createElement(AutoclearingHiddenLiveRegion, { text: liveRegionSelection })) : null),
209
220
  popover.open && (React.createElement(Portal, null,
210
- React.createElement(Menu, { role: 'listbox', className: menuClassName, id: `${uid}-menu`, key: `${uid}-menu`, ...popover.getFloatingProps({
221
+ React.createElement(SelectListbox, { defaultFocusedIndex: defaultFocusedIndex, className: menuClassName, id: `${uid}-menu`, key: `${uid}-menu`, ...popover.getFloatingProps({
211
222
  style: menuStyle,
212
223
  onKeyDown: ({ key }) => {
213
224
  if (key === 'Tab') {
@@ -262,3 +273,18 @@ const MultipleSelectButton = ({ selectedItems, selectedItemsRenderer, tagRendere
262
273
  selectedItems && !selectedItemsRenderer && (React.createElement(Box, { as: 'span', className: 'iui-content' },
263
274
  React.createElement(SelectTagContainer, { tags: selectedItemsElements })))));
264
275
  };
276
+ // ----------------------------------------------------------------------------
277
+ const SelectListbox = React.forwardRef((props, forwardedRef) => {
278
+ const { defaultFocusedIndex = 0, autoFocus = true, children: childrenProp, className, ...rest } = props;
279
+ const [focusedIndex, setFocusedIndex] = React.useState(defaultFocusedIndex);
280
+ const autoFocusRef = React.useCallback((element) => {
281
+ queueMicrotask(() => {
282
+ const firstFocusable = element?.querySelector('[tabindex="0"]');
283
+ firstFocusable?.focus();
284
+ });
285
+ }, []);
286
+ const children = React.useMemo(() => {
287
+ return React.Children.map(childrenProp, (child, index) => React.isValidElement(child) ? (React.createElement(CompositeItem, { key: index, render: child, ref: child.props.ref || child.ref })) : (child));
288
+ }, [childrenProp]);
289
+ return (React.createElement(Composite, { render: React.createElement(List, { as: 'div', className: cx('iui-menu', className) }), orientation: 'vertical', role: 'listbox', activeIndex: focusedIndex, onNavigate: setFocusedIndex, ref: useMergedRefs(forwardedRef, autoFocus ? autoFocusRef : undefined), ...rest }, children));
290
+ });
@@ -23,7 +23,7 @@ const getSurfaceElevationValue = (elevation) => {
23
23
  case 5:
24
24
  return 'var(--iui-shadow-5)';
25
25
  default:
26
- return '';
26
+ return undefined;
27
27
  }
28
28
  };
29
29
  /** Returns correct border value based on prop */
@@ -34,7 +34,7 @@ const getBorderValue = (border) => {
34
34
  if (border === false) {
35
35
  return 'none';
36
36
  }
37
- return '';
37
+ return undefined;
38
38
  };
39
39
  // ----------------------------------------------------------------------------
40
40
  // Surface.Header component
@@ -6,7 +6,7 @@ import * as React from 'react';
6
6
  import cx from 'classnames';
7
7
  import { actions as TableActions, useFlexLayout, useFilters, useRowSelect, useSortBy, useTable, useExpanded, usePagination, useColumnOrder, useGlobalFilter, } from 'react-table';
8
8
  import { ProgressRadial } from '../ProgressIndicators/ProgressRadial.js';
9
- import { useGlobals, useResizeObserver, SvgSortDown, SvgSortUp, useLayoutEffect, Box, createWarningLogger, ShadowRoot, LineClamp, useMergedRefs, } from '../../utils/index.js';
9
+ import { useGlobals, useResizeObserver, SvgSortDown, SvgSortUp, useLayoutEffect, Box, createWarningLogger, ShadowRoot, LineClamp, useMergedRefs, useLatestRef, } from '../../utils/index.js';
10
10
  import { TableColumnsContext, getCellStyle, getStickyStyle, getSubRowStyle, } from './utils.js';
11
11
  import { TableRowMemoized } from './TableRowMemoized.js';
12
12
  import { FilterToggle } from './filters/index.js';
@@ -81,13 +81,8 @@ export const Table = (props) => {
81
81
  minWidth: 0,
82
82
  width: 0,
83
83
  }), []);
84
- // useRef prevents from rerendering when one of these callbacks changes
85
- const onBottomReachedRef = React.useRef(onBottomReached);
86
- const onRowInViewportRef = React.useRef(onRowInViewport);
87
- React.useEffect(() => {
88
- onBottomReachedRef.current = onBottomReached;
89
- onRowInViewportRef.current = onRowInViewport;
90
- }, [onBottomReached, onRowInViewport]);
84
+ const onBottomReachedRef = useLatestRef(onBottomReached);
85
+ const onRowInViewportRef = useLatestRef(onRowInViewport);
91
86
  const hasManualSelectionColumn = React.useMemo(() => {
92
87
  const flatColumns = flattenColumns(columns);
93
88
  return flatColumns.some((column) => column.id === SELECTION_CELL_ID);
@@ -357,6 +352,8 @@ export const Table = (props) => {
357
352
  enableVirtualization,
358
353
  tableRowRef,
359
354
  density,
355
+ onBottomReachedRef,
356
+ onRowInViewportRef,
360
357
  ]);
361
358
  const virtualizedItemRenderer = React.useCallback((index) => getPreparedRow(index), [getPreparedRow]);
362
359
  const updateStickyState = () => {
@@ -269,7 +269,7 @@ export declare const Tabs: PolymorphicForwardRefComponent<"div", TabsLegacyProps
269
269
  ref?: ((instance: HTMLSpanElement | null) => void) | React.RefObject<HTMLSpanElement> | null | undefined;
270
270
  }, "fill" | "as" | "key" | "size" | keyof React.HTMLAttributes<HTMLSpanElement> | "padded"> & {
271
271
  size?: "small" | "auto" | "medium" | "large" | import("../../utils/types.js").AnyString | undefined;
272
- fill?: "default" | import("../../utils/types.js").AnyString | "informational" | "negative" | "positive" | "warning" | undefined;
272
+ fill?: "default" | "positive" | "negative" | "warning" | import("../../utils/types.js").AnyString | "informational" | undefined;
273
273
  padded?: boolean | undefined;
274
274
  } & Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & {
275
275
  as?: "span" | undefined;
@@ -249,7 +249,7 @@ export declare const Tile: PolymorphicForwardRefComponent<"div", TileLegacyProps
249
249
  */
250
250
  IconButton: PolymorphicForwardRefComponent<"button", Omit<Omit<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
251
251
  ref?: ((instance: HTMLButtonElement | null) => void) | React.RefObject<HTMLButtonElement> | null | undefined;
252
- }, "label" | "as" | "size" | "htmlDisabled" | "styleType" | "labelProps" | "stretched" | "isActive" | "iconProps"> & {
252
+ }, "label" | "as" | "loading" | "size" | "htmlDisabled" | "styleType" | "labelProps" | "stretched" | "isActive" | "iconProps"> & {
253
253
  isActive?: boolean | undefined;
254
254
  label?: React.ReactNode;
255
255
  labelProps?: Omit<Omit<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
@@ -262,6 +262,14 @@ export declare const Tile: PolymorphicForwardRefComponent<"div", TileLegacyProps
262
262
  ancestorScroll?: boolean | undefined;
263
263
  ancestorResize?: boolean | undefined;
264
264
  elementResize?: boolean | undefined;
265
+ /**
266
+ * Flag whether the tile is disabled.
267
+ *
268
+ * Note: This only affects the tile. You need to manually disable
269
+ * the buttons and other interactive elements inside the tile.
270
+ *
271
+ * @default false
272
+ */
265
273
  animationFrame?: boolean | undefined;
266
274
  layoutShift?: boolean | undefined;
267
275
  } | undefined;
@@ -288,6 +296,14 @@ export declare const Tile: PolymorphicForwardRefComponent<"div", TileLegacyProps
288
296
  ancestorScroll?: boolean | undefined;
289
297
  ancestorResize?: boolean | undefined;
290
298
  elementResize?: boolean | undefined;
299
+ /**
300
+ * Flag whether the tile is disabled.
301
+ *
302
+ * Note: This only affects the tile. You need to manually disable
303
+ * the buttons and other interactive elements inside the tile.
304
+ *
305
+ * @default false
306
+ */
291
307
  animationFrame?: boolean | undefined;
292
308
  layoutShift?: boolean | undefined;
293
309
  } | undefined;
@@ -6,10 +6,22 @@ import * as React from 'react';
6
6
  import cx from 'classnames';
7
7
  import { useFloating, autoUpdate, offset, flip, shift, useHover, useFocus, useDismiss, useInteractions, safePolygon, size, autoPlacement, hide, inline, useDelayGroupContext, useDelayGroup, } from '@floating-ui/react';
8
8
  import { Box, Portal, cloneElementWithRef, useControlledState, useId, useMergedRefs, } from '../../utils/index.js';
9
+ // ----------------------------------------------------------------------------
9
10
  const useTooltip = (options = {}) => {
10
11
  const uniqueId = useId();
11
12
  const { placement = 'top', visible, onVisibleChange, middleware = { flip: true, shift: true }, autoUpdateOptions = {}, reference, ariaStrategy = 'description', id = uniqueId, ...props } = options;
12
13
  const [open, onOpenChange] = useControlledState(false, visible, onVisibleChange);
14
+ const syncWithControlledState = React.useCallback((element) => {
15
+ // Using a microtask ensures that the popover is mounted before calling togglePopover
16
+ queueMicrotask(() => {
17
+ try {
18
+ element?.togglePopover?.(open);
19
+ }
20
+ catch {
21
+ // Fail silently, to avoid crashing the page
22
+ }
23
+ });
24
+ }, [open]);
13
25
  const floating = useFloating({
14
26
  placement,
15
27
  open,
@@ -92,19 +104,29 @@ const useTooltip = (options = {}) => {
92
104
  const getReferenceProps = React.useCallback((userProps) => {
93
105
  return interactions.getReferenceProps({ ...userProps, ...ariaProps });
94
106
  }, [interactions, ariaProps]);
95
- const floatingProps = React.useMemo(() => interactions.getFloatingProps({
96
- hidden: !open,
97
- 'aria-hidden': 'true',
98
- ...props,
99
- id,
107
+ const floatingProps = React.useMemo(() => ({
108
+ ...interactions.getFloatingProps({
109
+ hidden: !open,
110
+ 'aria-hidden': 'true',
111
+ ...props,
112
+ id,
113
+ }),
114
+ popover: 'manual',
100
115
  }), [interactions, props, id, open]);
101
116
  return React.useMemo(() => ({
102
117
  getReferenceProps,
103
118
  floatingProps,
104
119
  ...floating,
120
+ refs: {
121
+ ...floating.refs,
122
+ setFloating: (element) => {
123
+ floating.refs.setFloating(element);
124
+ syncWithControlledState(element);
125
+ },
126
+ },
105
127
  // styles are not relevant when tooltip is not open
106
128
  floatingStyles: floating.context.open ? floating.floatingStyles : {},
107
- }), [getReferenceProps, floatingProps, floating]);
129
+ }), [getReferenceProps, floatingProps, floating, syncWithControlledState]);
108
130
  };
109
131
  /**
110
132
  * Basic tooltip component to display informative content when an element is hovered or focused.
@@ -1,28 +1,53 @@
1
1
  import * as React from 'react';
2
2
  import type { CommonProps } from '../../utils/index.js';
3
+ import { TreeNodeExpander } from './TreeNodeExpander.js';
3
4
  type TreeNodeProps = {
4
5
  /**
5
6
  * Unique id of the node.
6
7
  * It has to be compatible with HTML id attribute.
7
8
  */
8
9
  nodeId: string;
10
+ /**
11
+ * Props for treeNode
12
+ */
13
+ nodeProps?: React.ComponentProps<'div'>;
9
14
  /**
10
15
  * The main text displayed on the node.
11
16
  */
12
17
  label: React.ReactNode;
18
+ /**
19
+ * Props for TreeNode label(affects both the main and sub label).
20
+ */
21
+ labelProps?: React.ComponentProps<'div'>;
22
+ /**
23
+ * Props for the TreeNode's main label.
24
+ */
25
+ titleProps?: React.ComponentProps<'div'>;
13
26
  /**
14
27
  * Small note displayed below main label.
15
28
  */
16
29
  sublabel?: React.ReactNode;
30
+ /**
31
+ * Props for TreeNode sublabel
32
+ */
33
+ sublabelProps?: React.ComponentProps<'div'>;
17
34
  /**
18
35
  * Icon shown before label and sublabel content.
19
36
  */
20
37
  icon?: JSX.Element;
38
+ /**
39
+ * Props for TreeNode Icon
40
+ */
41
+ iconProps?: React.ComponentProps<'span'>;
21
42
  /**
22
43
  * Flag whether the node has child sub-nodes. It is used to show expander icon.
23
44
  * @default false
24
45
  */
25
46
  hasSubNodes?: boolean;
47
+ /**
48
+ * Props for subTree list(affects all subnodes of this node).
49
+ */
50
+ subTreeProps?: React.ComponentProps<'ul'>;
26
51
  /**
27
52
  * Flag whether the node is disabled.
28
53
  * @default false
@@ -54,10 +79,24 @@ type TreeNodeProps = {
54
79
  * Recommended to use `Checkbox` component.
55
80
  */
56
81
  checkbox?: React.ReactNode;
82
+ /**
83
+ * Props for TreeNode checkbox.
84
+ */
85
+ checkboxProps?: React.ComponentProps<'div'>;
57
86
  /**
58
87
  * Custom expander element. If `hasSubNodes` is false, it won't be shown.
59
88
  */
60
89
  expander?: React.ReactNode;
90
+ /**
91
+ * Props for the default TreeNodeExpander that is shown when there are sub nodes and no expander is given.
92
+ */
93
+ expanderProps?: React.ComponentProps<typeof TreeNodeExpander>;
94
+ /**
95
+ * Props for content of the TreeNode.
96
+ * This affects all passed in children of the node, as well as the label, sublabel, icon, and expander.
97
+ * Note that this does not affect the checkbox.
98
+ */
99
+ contentProps?: React.ComponentProps<'div'>;
61
100
  /**
62
101
  * Content shown after `TreeNode`.
63
102
  */
@@ -27,7 +27,7 @@ import { useTreeContext } from './TreeContext.js';
27
27
  />
28
28
  */
29
29
  export const TreeNode = (props) => {
30
- const { nodeId, label, sublabel, children, className, icon, hasSubNodes = false, isDisabled = false, isExpanded = false, isSelected = false, onSelected, onExpanded, checkbox, expander, ...rest } = props;
30
+ const { nodeId, nodeProps = {}, label, labelProps = {}, sublabel, sublabelProps = {}, children, className, icon, iconProps = {}, hasSubNodes = false, isDisabled = false, isExpanded = false, isSelected = false, onSelected, onExpanded, checkbox, checkboxProps = {}, subTreeProps = {}, contentProps = {}, titleProps = {}, expanderProps = {}, expander, ...rest } = props;
31
31
  const { nodeDepth, subNodeIds = [], parentNodeId, scrollToParent, groupSize, indexInGroup, } = useTreeContext();
32
32
  const [isFocused, setIsFocused] = React.useState(false);
33
33
  const nodeRef = React.useRef(null);
@@ -107,22 +107,22 @@ export const TreeNode = (props) => {
107
107
  }, onBlur: () => {
108
108
  setIsFocused(false);
109
109
  }, ref: nodeRef, onKeyDown: onKeyDown, ...rest },
110
- React.createElement(Box, { className: cx('iui-tree-node', {
110
+ React.createElement(Box, { as: 'div', style: { '--level': nodeDepth }, onClick: () => !isDisabled && onSelected?.(nodeId, !isSelected), ...nodeProps, className: cx('iui-tree-node', {
111
111
  'iui-active': isSelected,
112
112
  'iui-disabled': isDisabled,
113
- }), style: { '--level': nodeDepth }, onClick: () => !isDisabled && onSelected?.(nodeId, !isSelected) },
114
- checkbox && (React.createElement(Box, { className: 'iui-tree-node-checkbox' }, React.isValidElement(checkbox)
113
+ }, nodeProps?.className) },
114
+ checkbox && (React.createElement(Box, { as: 'div', ...checkboxProps, className: cx('iui-tree-node-checkbox', checkboxProps?.className) }, React.isValidElement(checkbox)
115
115
  ? React.cloneElement(checkbox, {
116
116
  tabIndex: isFocused ? 0 : -1,
117
117
  })
118
118
  : checkbox)),
119
- React.createElement(Box, { className: 'iui-tree-node-content' },
119
+ React.createElement(Box, { as: 'div', ...contentProps, className: cx('iui-tree-node-content', contentProps?.className) },
120
120
  hasSubNodes && expander,
121
- hasSubNodes && !expander && (React.createElement(TreeNodeExpander, { isExpanded: isExpanded, disabled: isDisabled, onClick: onExpanderClick, tabIndex: isFocused ? 0 : -1 })),
122
- icon && (React.createElement(Box, { as: 'span', className: 'iui-tree-node-content-icon', "aria-hidden": true }, icon)),
123
- React.createElement(Box, { className: 'iui-tree-node-content-label' },
124
- React.createElement(Box, { className: 'iui-tree-node-content-title' }, label),
125
- sublabel && (React.createElement(Box, { className: 'iui-tree-node-content-caption' }, sublabel))),
121
+ hasSubNodes && !expander && (React.createElement(TreeNodeExpander, { isExpanded: isExpanded, disabled: isDisabled, onClick: onExpanderClick, tabIndex: isFocused ? 0 : -1, ...expanderProps })),
122
+ icon && (React.createElement(Box, { as: 'span', "aria-hidden": true, ...iconProps, className: cx('iui-tree-node-content-icon', iconProps?.className) }, icon)),
123
+ React.createElement(Box, { as: 'div', ...labelProps, className: cx('iui-tree-node-content-label', labelProps?.className) },
124
+ React.createElement(Box, { as: 'div', ...titleProps, className: cx('iui-tree-node-content-title', titleProps?.className) }, label),
125
+ sublabel && (React.createElement(Box, { as: 'div', ...sublabelProps, className: cx('iui-tree-node-content-caption', sublabelProps?.className) }, sublabel))),
126
126
  children)),
127
- hasSubNodes && (React.createElement(Box, { as: 'ul', className: 'iui-sub-tree', role: 'group', "aria-owns": subNodeIds.join(' ') }))));
127
+ hasSubNodes && (React.createElement(Box, { as: 'ul', role: 'group', "aria-owns": subNodeIds.join(' '), ...subTreeProps, className: cx('iui-sub-tree', subTreeProps?.className) }))));
128
128
  };