@itwin/itwinui-react 3.10.1 → 3.11.1

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 (49) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/cjs/core/Alert/Alert.d.ts +1 -1
  3. package/cjs/core/Breadcrumbs/Breadcrumbs.js +13 -3
  4. package/cjs/core/Buttons/Button.d.ts +4 -0
  5. package/cjs/core/Buttons/Button.js +6 -4
  6. package/cjs/core/Carousel/Carousel.d.ts +2 -2
  7. package/cjs/core/Carousel/CarouselNavigation.d.ts +2 -2
  8. package/cjs/core/ComboBox/ComboBox.js +2 -2
  9. package/cjs/core/ComboBox/ComboBoxInput.js +2 -4
  10. package/cjs/core/ComboBox/ComboBoxMenu.js +7 -3
  11. package/cjs/core/ExpandableBlock/ExpandableBlock.d.ts +1 -1
  12. package/cjs/core/InputWithDecorations/InputWithDecorations.d.ts +1 -1
  13. package/cjs/core/LabeledSelect/LabeledSelect.d.ts +9 -9
  14. package/cjs/core/Select/Select.js +28 -2
  15. package/cjs/core/Surface/Surface.js +2 -2
  16. package/cjs/core/Table/Table.js +4 -7
  17. package/cjs/core/Table/cells/EditableCell.js +6 -2
  18. package/cjs/core/Tabs/Tabs.d.ts +1 -1
  19. package/cjs/core/Tile/Tile.d.ts +17 -1
  20. package/cjs/core/Tooltip/Tooltip.js +28 -6
  21. package/cjs/core/Tree/TreeNode.d.ts +39 -0
  22. package/cjs/core/Tree/TreeNode.js +11 -11
  23. package/cjs/core/Tree/TreeNodeExpander.d.ts +2 -0
  24. package/cjs/core/Tree/TreeNodeExpander.js +2 -2
  25. package/esm/core/Alert/Alert.d.ts +1 -1
  26. package/esm/core/Breadcrumbs/Breadcrumbs.js +13 -3
  27. package/esm/core/Buttons/Button.d.ts +4 -0
  28. package/esm/core/Buttons/Button.js +6 -4
  29. package/esm/core/Carousel/Carousel.d.ts +2 -2
  30. package/esm/core/Carousel/CarouselNavigation.d.ts +2 -2
  31. package/esm/core/ComboBox/ComboBox.js +2 -2
  32. package/esm/core/ComboBox/ComboBoxInput.js +3 -5
  33. package/esm/core/ComboBox/ComboBoxMenu.js +4 -2
  34. package/esm/core/ExpandableBlock/ExpandableBlock.d.ts +1 -1
  35. package/esm/core/InputWithDecorations/InputWithDecorations.d.ts +1 -1
  36. package/esm/core/LabeledSelect/LabeledSelect.d.ts +9 -9
  37. package/esm/core/Select/Select.js +28 -2
  38. package/esm/core/Surface/Surface.js +2 -2
  39. package/esm/core/Table/Table.js +5 -8
  40. package/esm/core/Table/cells/EditableCell.js +3 -2
  41. package/esm/core/Tabs/Tabs.d.ts +1 -1
  42. package/esm/core/Tile/Tile.d.ts +17 -1
  43. package/esm/core/Tooltip/Tooltip.js +28 -6
  44. package/esm/core/Tree/TreeNode.d.ts +39 -0
  45. package/esm/core/Tree/TreeNode.js +11 -11
  46. package/esm/core/Tree/TreeNodeExpander.d.ts +2 -0
  47. package/esm/core/Tree/TreeNodeExpander.js +2 -2
  48. package/package.json +7 -1
  49. package/styles.css +21 -21
@@ -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
  };
@@ -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 {};
@@ -8,11 +8,11 @@ import { SvgChevronRight, SvgChevronRightSmall } from '../../utils/index.js';
8
8
  import { IconButton } from '../Buttons/IconButton.js';
9
9
  import { TreeContext } from './TreeContext.js';
10
10
  export const TreeNodeExpander = React.forwardRef((props, ref) => {
11
- const { isExpanded, ...rest } = props;
11
+ const { isExpanded, expanderIconProps = {}, ...rest } = props;
12
12
  const size = React.useContext(TreeContext)?.size ?? 'default';
13
13
  const ChevronIcon = size === 'small' ? SvgChevronRightSmall : SvgChevronRight;
14
14
  return (React.createElement(IconButton, { styleType: 'borderless', size: 'small', "aria-label": isExpanded ? 'Collapse' : 'Expand', ref: ref, ...rest },
15
- React.createElement(ChevronIcon, { className: cx('iui-tree-node-content-expander-icon', {
15
+ React.createElement(ChevronIcon, { ...expanderIconProps, className: cx('iui-tree-node-content-expander-icon', expanderIconProps?.className, {
16
16
  'iui-tree-node-content-expander-icon-expanded': isExpanded,
17
17
  }) })));
18
18
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itwin/itwinui-react",
3
- "version": "3.10.1",
3
+ "version": "3.11.1",
4
4
  "author": "Bentley Systems",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -19,6 +19,12 @@
19
19
  }
20
20
  },
21
21
  "./react-table": {
22
+ "import": {
23
+ "types": "./esm/react-table/react-table.d.ts"
24
+ },
25
+ "require": {
26
+ "types": "./cjs/react-table/react-table.d.ts"
27
+ },
22
28
  "types": "./react-table.d.ts"
23
29
  },
24
30
  "./styles.css": "./styles.css",