@itwin/itwinui-react 3.0.0-dev.6 → 3.0.0-dev.7

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 (145) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/cjs/core/Avatar/Avatar.d.ts +3 -2
  3. package/cjs/core/Avatar/Avatar.js +21 -19
  4. package/cjs/core/AvatarGroup/AvatarGroup.js +3 -8
  5. package/cjs/core/Buttons/Button/Button.d.ts +15 -2
  6. package/cjs/core/Buttons/Button/Button.js +23 -9
  7. package/cjs/core/Buttons/DropdownButton/DropdownButton.js +1 -1
  8. package/cjs/core/Buttons/IconButton/IconButton.d.ts +5 -1
  9. package/cjs/core/Buttons/IconButton/IconButton.js +11 -5
  10. package/cjs/core/Buttons/SplitButton/SplitButton.d.ts +9 -0
  11. package/cjs/core/Buttons/SplitButton/SplitButton.js +22 -13
  12. package/cjs/core/Carousel/Carousel.d.ts +6 -4
  13. package/cjs/core/Carousel/Carousel.js +2 -2
  14. package/cjs/core/Carousel/CarouselDot.js +1 -3
  15. package/cjs/core/Carousel/CarouselNavigation.d.ts +6 -4
  16. package/cjs/core/ColorPicker/ColorBuilder.js +2 -1
  17. package/cjs/core/ComboBox/ComboBoxInput.js +1 -1
  18. package/cjs/core/ComboBox/ComboBoxMenu.js +5 -5
  19. package/cjs/core/DatePicker/DatePicker.js +7 -1
  20. package/cjs/core/Dialog/Dialog.js +1 -2
  21. package/cjs/core/Dialog/DialogMain.js +5 -5
  22. package/cjs/core/ExpandableBlock/ExpandableBlock.js +1 -3
  23. package/cjs/core/FileUpload/FileUpload.d.ts +4 -0
  24. package/cjs/core/FileUpload/FileUpload.js +24 -3
  25. package/cjs/core/Header/HeaderBasicButton.js +3 -16
  26. package/cjs/core/Header/HeaderDropdownButton.js +1 -1
  27. package/cjs/core/Header/HeaderSplitButton.js +2 -4
  28. package/cjs/core/ProgressIndicators/ProgressLinear.d.ts +4 -0
  29. package/cjs/core/ProgressIndicators/ProgressLinear.js +9 -1
  30. package/cjs/core/Select/Select.js +2 -2
  31. package/cjs/core/SideNavigation/SideNavigation.d.ts +16 -0
  32. package/cjs/core/SideNavigation/SideNavigation.js +40 -9
  33. package/cjs/core/Slider/Slider.d.ts +24 -0
  34. package/cjs/core/Slider/Slider.js +58 -10
  35. package/cjs/core/Slider/Thumb.js +2 -2
  36. package/cjs/core/Slider/Track.d.ts +1 -1
  37. package/cjs/core/Slider/Track.js +17 -6
  38. package/cjs/core/Stepper/Stepper.d.ts +26 -1
  39. package/cjs/core/Stepper/Stepper.js +35 -6
  40. package/cjs/core/Stepper/StepperStep.d.ts +17 -0
  41. package/cjs/core/Stepper/StepperStep.js +33 -8
  42. package/cjs/core/Stepper/WorkflowDiagram.d.ts +11 -1
  43. package/cjs/core/Stepper/WorkflowDiagram.js +23 -10
  44. package/cjs/core/Stepper/WorkflowDiagramStep.d.ts +6 -1
  45. package/cjs/core/Stepper/WorkflowDiagramStep.js +9 -2
  46. package/cjs/core/Table/SubRowExpander.js +1 -1
  47. package/cjs/core/Table/Table.js +0 -1
  48. package/cjs/core/Table/TableCell.js +1 -1
  49. package/cjs/core/Table/TablePaginator.js +1 -3
  50. package/cjs/core/Tabs/Tab.js +1 -2
  51. package/cjs/core/ThemeProvider/ThemeContext.d.ts +1 -1
  52. package/cjs/core/ThemeProvider/ThemeProvider.d.ts +23 -3
  53. package/cjs/core/ThemeProvider/ThemeProvider.js +56 -23
  54. package/cjs/core/Tile/Tile.d.ts +3 -2
  55. package/cjs/core/Toast/Toast.js +4 -9
  56. package/cjs/core/Tooltip/Tooltip.d.ts +1 -1
  57. package/cjs/core/Tooltip/Tooltip.js +1 -2
  58. package/cjs/core/Tree/TreeNode.js +1 -1
  59. package/cjs/core/utils/components/ButtonBase.d.ts +14 -0
  60. package/cjs/core/utils/components/ButtonBase.js +46 -0
  61. package/cjs/core/utils/components/Popover.js +5 -3
  62. package/cjs/core/utils/components/VirtualScroll.js +4 -4
  63. package/cjs/core/utils/components/index.d.ts +1 -0
  64. package/cjs/core/utils/components/index.js +1 -0
  65. package/cjs/core/utils/functions/colors.d.ts +1 -1
  66. package/cjs/core/utils/functions/colors.js +1 -13
  67. package/cjs/core/utils/hooks/index.d.ts +1 -0
  68. package/cjs/core/utils/hooks/index.js +1 -0
  69. package/cjs/core/utils/hooks/useGlobals.d.ts +1 -1
  70. package/cjs/core/utils/hooks/useUncontrolledState.d.ts +6 -0
  71. package/cjs/core/utils/hooks/useUncontrolledState.js +18 -0
  72. package/cjs/styles.js +3 -9
  73. package/esm/core/Avatar/Avatar.d.ts +3 -2
  74. package/esm/core/Avatar/Avatar.js +21 -17
  75. package/esm/core/AvatarGroup/AvatarGroup.js +3 -8
  76. package/esm/core/Buttons/Button/Button.d.ts +15 -2
  77. package/esm/core/Buttons/Button/Button.js +18 -10
  78. package/esm/core/Buttons/DropdownButton/DropdownButton.js +1 -1
  79. package/esm/core/Buttons/IconButton/IconButton.d.ts +5 -1
  80. package/esm/core/Buttons/IconButton/IconButton.js +9 -6
  81. package/esm/core/Buttons/SplitButton/SplitButton.d.ts +9 -0
  82. package/esm/core/Buttons/SplitButton/SplitButton.js +22 -13
  83. package/esm/core/Carousel/Carousel.d.ts +6 -4
  84. package/esm/core/Carousel/Carousel.js +8 -3
  85. package/esm/core/Carousel/CarouselDot.js +2 -4
  86. package/esm/core/Carousel/CarouselNavigation.d.ts +6 -4
  87. package/esm/core/ColorPicker/ColorBuilder.js +2 -1
  88. package/esm/core/ComboBox/ComboBoxInput.js +1 -1
  89. package/esm/core/ComboBox/ComboBoxMenu.js +5 -5
  90. package/esm/core/DatePicker/DatePicker.js +8 -1
  91. package/esm/core/Dialog/Dialog.js +1 -1
  92. package/esm/core/Dialog/DialogMain.js +5 -5
  93. package/esm/core/ExpandableBlock/ExpandableBlock.js +2 -3
  94. package/esm/core/FileUpload/FileUpload.d.ts +4 -0
  95. package/esm/core/FileUpload/FileUpload.js +26 -3
  96. package/esm/core/Header/HeaderBasicButton.js +4 -17
  97. package/esm/core/Header/HeaderDropdownButton.js +1 -1
  98. package/esm/core/Header/HeaderSplitButton.js +8 -5
  99. package/esm/core/ProgressIndicators/ProgressLinear.d.ts +4 -0
  100. package/esm/core/ProgressIndicators/ProgressLinear.js +9 -1
  101. package/esm/core/Select/Select.js +2 -2
  102. package/esm/core/SideNavigation/SideNavigation.d.ts +16 -0
  103. package/esm/core/SideNavigation/SideNavigation.js +31 -9
  104. package/esm/core/Slider/Slider.d.ts +24 -0
  105. package/esm/core/Slider/Slider.js +43 -10
  106. package/esm/core/Slider/Thumb.js +2 -2
  107. package/esm/core/Slider/Track.d.ts +1 -1
  108. package/esm/core/Slider/Track.js +14 -6
  109. package/esm/core/Stepper/Stepper.d.ts +26 -1
  110. package/esm/core/Stepper/Stepper.js +32 -6
  111. package/esm/core/Stepper/StepperStep.d.ts +17 -0
  112. package/esm/core/Stepper/StepperStep.js +27 -8
  113. package/esm/core/Stepper/WorkflowDiagram.d.ts +11 -1
  114. package/esm/core/Stepper/WorkflowDiagram.js +10 -7
  115. package/esm/core/Stepper/WorkflowDiagramStep.d.ts +6 -1
  116. package/esm/core/Stepper/WorkflowDiagramStep.js +6 -2
  117. package/esm/core/Table/SubRowExpander.js +1 -1
  118. package/esm/core/Table/Table.js +0 -1
  119. package/esm/core/Table/TableCell.js +1 -1
  120. package/esm/core/Table/TablePaginator.js +2 -3
  121. package/esm/core/Tabs/Tab.js +2 -3
  122. package/esm/core/ThemeProvider/ThemeContext.d.ts +1 -1
  123. package/esm/core/ThemeProvider/ThemeProvider.d.ts +23 -3
  124. package/esm/core/ThemeProvider/ThemeProvider.js +64 -24
  125. package/esm/core/Tile/Tile.d.ts +3 -2
  126. package/esm/core/Toast/Toast.js +5 -9
  127. package/esm/core/Tooltip/Tooltip.d.ts +1 -1
  128. package/esm/core/Tooltip/Tooltip.js +1 -1
  129. package/esm/core/Tree/TreeNode.js +1 -1
  130. package/esm/core/utils/components/ButtonBase.d.ts +14 -0
  131. package/esm/core/utils/components/ButtonBase.js +42 -0
  132. package/esm/core/utils/components/Popover.js +5 -3
  133. package/esm/core/utils/components/VirtualScroll.js +4 -4
  134. package/esm/core/utils/components/index.d.ts +1 -0
  135. package/esm/core/utils/components/index.js +1 -0
  136. package/esm/core/utils/functions/colors.d.ts +1 -1
  137. package/esm/core/utils/functions/colors.js +1 -13
  138. package/esm/core/utils/hooks/index.d.ts +1 -0
  139. package/esm/core/utils/hooks/index.js +1 -0
  140. package/esm/core/utils/hooks/useGlobals.d.ts +1 -1
  141. package/esm/core/utils/hooks/useUncontrolledState.d.ts +6 -0
  142. package/esm/core/utils/hooks/useUncontrolledState.js +13 -0
  143. package/esm/styles.js +3 -9
  144. package/package.json +2 -2
  145. package/styles.css +37 -37
@@ -17,6 +17,10 @@ export const StepperStep = React.forwardRef((props, forwardedRef) => {
17
17
  description,
18
18
  className,
19
19
  style,
20
+ stepProps,
21
+ trackContentProps,
22
+ circleProps,
23
+ nameProps,
20
24
  ...rest
21
25
  } = props;
22
26
  const isPast = currentStepNumber > index;
@@ -42,17 +46,17 @@ export const StepperStep = React.forwardRef((props, forwardedRef) => {
42
46
  Box,
43
47
  {
44
48
  as: 'li',
49
+ ...stepProps,
45
50
  className: cx(
46
51
  'iui-stepper-step',
47
- {
48
- 'iui-current': isActive,
49
- 'iui-clickable': isClickable,
50
- },
52
+ { 'iui-current': isActive, 'iui-clickable': isClickable },
51
53
  className,
54
+ stepProps?.className,
52
55
  ),
53
56
  style: {
54
- width: type === 'default' ? `${100 / totalSteps}%` : undefined,
57
+ inlineSize: type === 'default' ? `${100 / totalSteps}%` : undefined,
55
58
  ...style,
59
+ ...stepProps?.style,
56
60
  },
57
61
  onClick: onCompletedClick,
58
62
  onKeyDown: onKeyDown,
@@ -63,17 +67,32 @@ export const StepperStep = React.forwardRef((props, forwardedRef) => {
63
67
  },
64
68
  React.createElement(
65
69
  Box,
66
- { className: 'iui-stepper-track-content' },
70
+ {
71
+ as: 'div',
72
+ ...trackContentProps,
73
+ className: cx(
74
+ 'iui-stepper-track-content',
75
+ trackContentProps?.className,
76
+ ),
77
+ },
67
78
  React.createElement(
68
79
  Box,
69
- { as: 'span', className: 'iui-stepper-circle' },
80
+ {
81
+ as: 'span',
82
+ ...circleProps,
83
+ className: cx('iui-stepper-circle', circleProps?.className),
84
+ },
70
85
  index + 1,
71
86
  ),
72
87
  ),
73
88
  type === 'default' &&
74
89
  React.createElement(
75
90
  Box,
76
- { as: 'span', className: 'iui-stepper-step-name' },
91
+ {
92
+ as: 'span',
93
+ ...nameProps,
94
+ className: cx('iui-stepper-step-name', nameProps?.className),
95
+ },
77
96
  title,
78
97
  ),
79
98
  );
@@ -1,5 +1,15 @@
1
+ import * as React from 'react';
1
2
  import type { PolymorphicForwardRefComponent } from '../utils/index.js';
2
3
  import type { StepperProps } from './Stepper.js';
3
- type WorkflowDiagramProps = Pick<StepperProps, 'steps'>;
4
+ type WorkflowDiagramProps = Pick<StepperProps, 'steps'> & {
5
+ /**
6
+ * Allows props to be passed for diagram.
7
+ */
8
+ contentProps?: (index: number) => React.ComponentProps<'span'>;
9
+ /**
10
+ * Allows props to be passed for diagram wrapper.
11
+ */
12
+ wrapperProps?: React.ComponentProps<'div'>;
13
+ };
4
14
  export declare const WorkflowDiagram: PolymorphicForwardRefComponent<"ol", WorkflowDiagramProps>;
5
15
  export default WorkflowDiagram;
@@ -3,25 +3,28 @@
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 { Box } from '../utils/index.js';
7
8
  import { WorkflowDiagramStep } from './WorkflowDiagramStep.js';
8
9
  export const WorkflowDiagram = React.forwardRef(
9
10
  // TODO: Remove this ref cast. ref and rest props should be applied on the same element
10
11
  (props, ref) => {
11
- const { steps, ...rest } = props;
12
+ const { steps, className, contentProps, wrapperProps, ...rest } = props;
12
13
  return React.createElement(
13
14
  Box,
14
- { ref: ref },
15
+ { as: 'div', ...wrapperProps, ref: ref },
15
16
  React.createElement(
16
17
  Box,
17
- { as: 'ol', className: 'iui-workflow-diagram', ...rest },
18
- steps.map((s, index) =>
19
- React.createElement(WorkflowDiagramStep, {
18
+ { as: 'ol', className: cx('iui-workflow-diagram', className), ...rest },
19
+ steps.map((s, index) => {
20
+ const thisContentProps = contentProps?.(index);
21
+ return React.createElement(WorkflowDiagramStep, {
22
+ contentProps: thisContentProps,
20
23
  key: index,
21
24
  title: s.name,
22
25
  description: s.description,
23
- }),
24
- ),
26
+ });
27
+ }),
25
28
  ),
26
29
  );
27
30
  },
@@ -1,5 +1,10 @@
1
1
  import * as React from 'react';
2
2
  import { type CommonProps } from '../utils/index.js';
3
3
  import type { StepperStepProps } from './StepperStep.js';
4
- export type WorkflowDiagramStepProps = Pick<StepperStepProps, 'title' | 'description'> & Omit<CommonProps, 'title'>;
4
+ export type WorkflowDiagramStepProps = {
5
+ /**
6
+ * Allows props to be passed for diagram content.
7
+ */
8
+ contentProps?: React.ComponentProps<'span'>;
9
+ } & Pick<StepperStepProps, 'title' | 'description'> & Omit<CommonProps, 'title'>;
5
10
  export declare const WorkflowDiagramStep: (props: WorkflowDiagramStepProps) => React.JSX.Element;
@@ -7,7 +7,7 @@ import * as React from 'react';
7
7
  import { Tooltip } from '../Tooltip/index.js';
8
8
  import { Box } from '../utils/index.js';
9
9
  export const WorkflowDiagramStep = (props) => {
10
- const { title, description, className, style, ...rest } = props;
10
+ const { title, description, className, style, contentProps, ...rest } = props;
11
11
  const stepShape = React.createElement(
12
12
  Box,
13
13
  {
@@ -18,7 +18,11 @@ export const WorkflowDiagramStep = (props) => {
18
18
  },
19
19
  React.createElement(
20
20
  Box,
21
- { as: 'span', className: 'iui-workflow-diagram-content' },
21
+ {
22
+ as: 'span',
23
+ ...contentProps,
24
+ className: cx('iui-workflow-diagram-content', contentProps?.className),
25
+ },
22
26
  title,
23
27
  ),
24
28
  );
@@ -16,7 +16,7 @@ export const SubRowExpander = (props) => {
16
16
  IconButton,
17
17
  {
18
18
  style: {
19
- marginRight:
19
+ marginInlineEnd:
20
20
  density === 'default' || density === undefined ? 8 : 4,
21
21
  },
22
22
  className: 'iui-table-row-expander',
@@ -798,7 +798,6 @@ export const Table = (props) => {
798
798
  React.createElement(ProgressRadial, {
799
799
  indeterminate: true,
800
800
  size: 'small',
801
- style: { float: 'none', marginLeft: 0 },
802
801
  }),
803
802
  ),
804
803
  ),
@@ -39,7 +39,7 @@ export const TableCell = (props) => {
39
39
  }
40
40
  const multiplier = 26 + expanderMargin; // 26 = expander width
41
41
  return {
42
- paddingLeft: cellPadding + dynamicMargin * multiplier,
42
+ paddingInlineStart: cellPadding + dynamicMargin * multiplier,
43
43
  };
44
44
  };
45
45
  const cellElementProps = cell.getCellProps({
@@ -15,6 +15,7 @@ import {
15
15
  SvgChevronLeft,
16
16
  SvgChevronRight,
17
17
  Box,
18
+ ButtonBase,
18
19
  } from '../utils/index.js';
19
20
  const defaultLocalization = {
20
21
  pageSizeLabel: (size) => `${size} per page`,
@@ -86,11 +87,9 @@ export const TablePaginator = (props) => {
86
87
  const pageButton = React.useCallback(
87
88
  (index, tabIndex = index === focusedIndex ? 0 : -1) =>
88
89
  React.createElement(
89
- Box,
90
+ ButtonBase,
90
91
  {
91
- as: 'button',
92
92
  key: index,
93
- type: 'button',
94
93
  className: cx('iui-table-paginator-page-button', {
95
94
  'iui-table-paginator-page-button-small': buttonSize === 'small',
96
95
  }),
@@ -4,7 +4,7 @@
4
4
  *--------------------------------------------------------------------------------------------*/
5
5
  import cx from 'classnames';
6
6
  import * as React from 'react';
7
- import { Box } from '../utils/index.js';
7
+ import { Box, ButtonBase } from '../utils/index.js';
8
8
  /**
9
9
  * Individual tab component to be used in the `labels` prop of `Tabs`.
10
10
  * @example
@@ -24,9 +24,8 @@ export const Tab = React.forwardRef((props, forwardedRef) => {
24
24
  ...rest
25
25
  } = props;
26
26
  return React.createElement(
27
- Box,
27
+ ButtonBase,
28
28
  {
29
- as: 'button',
30
29
  className: cx('iui-tab', { 'iui-active': active }, className),
31
30
  role: 'tab',
32
31
  tabIndex: -1,
@@ -3,5 +3,5 @@ import type { ThemeOptions, ThemeType } from './ThemeProvider.js';
3
3
  export declare const ThemeContext: React.Context<{
4
4
  theme?: ThemeType | undefined;
5
5
  themeOptions?: ThemeOptions | undefined;
6
- portalContainerRef?: React.RefObject<HTMLElement> | undefined;
6
+ portalContainer?: HTMLElement | null | undefined;
7
7
  } | undefined>;
@@ -44,11 +44,31 @@ type RootProps = {
44
44
  type ThemeProviderOwnProps = Pick<RootProps, 'theme'> & {
45
45
  themeOptions?: RootProps['themeOptions'];
46
46
  children: Required<React.ReactNode>;
47
+ /**
48
+ * The element used as the portal for floating elements (Tooltip, Toast, DropdownMenu, Dialog, etc).
49
+ *
50
+ * Defaults to a `<div>` rendered at the end of the ThemeProvider.
51
+ *
52
+ * When passing an element, it is recommended to use state.
53
+ *
54
+ * @example
55
+ * const [myPortal, setMyPortal] = React.useState(null);
56
+ *
57
+ * <div ref={setMyPortal} />
58
+ * <ThemeProvider
59
+ * portalContainer={myPortal}
60
+ * >
61
+ * ...
62
+ * </ThemeProvider>
63
+ */
64
+ portalContainer?: HTMLElement;
47
65
  };
48
66
  /**
49
- * This component provides global styles and applies theme to the entire tree
50
- * that it is wrapping around. The `theme` prop is optional and defaults to the
51
- * light theme.
67
+ * This component provides global state and applies theme to the entire tree
68
+ * that it is wrapping around.
69
+ *
70
+ * The `theme` prop defaults to "inherit", which looks upwards for closest ThemeProvider
71
+ * and falls back to "light" theme if one is not found.
52
72
  *
53
73
  * If you want to theme the entire app, you should use this component at the root. You can also
54
74
  * use this component to apply a different theme to only a part of the tree.
@@ -3,14 +3,23 @@
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 * as ReactDOM from 'react-dom';
6
7
  import cx from 'classnames';
7
- import { useMediaQuery, useMergedRefs, Box } from '../utils/index.js';
8
+ import {
9
+ useMediaQuery,
10
+ useMergedRefs,
11
+ Box,
12
+ useIsomorphicLayoutEffect,
13
+ useUncontrolledState,
14
+ } from '../utils/index.js';
8
15
  import { ThemeContext } from './ThemeContext.js';
9
16
  import { ToastProvider, Toaster } from '../Toast/Toaster.js';
10
17
  /**
11
- * This component provides global styles and applies theme to the entire tree
12
- * that it is wrapping around. The `theme` prop is optional and defaults to the
13
- * light theme.
18
+ * This component provides global state and applies theme to the entire tree
19
+ * that it is wrapping around.
20
+ *
21
+ * The `theme` prop defaults to "inherit", which looks upwards for closest ThemeProvider
22
+ * and falls back to "light" theme if one is not found.
14
23
  *
15
24
  * If you want to theme the entire app, you should use this component at the root. You can also
16
25
  * use this component to apply a different theme to only a part of the tree.
@@ -33,18 +42,23 @@ import { ToastProvider, Toaster } from '../Toast/Toaster.js';
33
42
  * <App />
34
43
  * </ThemeProvider>
35
44
  */
36
- export const ThemeProvider = React.forwardRef((props, ref) => {
37
- const { theme: themeProp, children, themeOptions, ...rest } = props;
38
- const portalContainerRef = React.useRef(null);
39
- const parentContext = React.useContext(ThemeContext);
40
- const theme =
41
- themeProp === 'inherit' ? parentContext?.theme ?? 'light' : themeProp;
42
- const shouldApplyBackground =
43
- themeOptions?.applyBackground ??
44
- (themeProp === 'inherit' ? false : !parentContext);
45
+ export const ThemeProvider = React.forwardRef((props, forwardedRef) => {
46
+ const {
47
+ theme: themeProp = 'inherit',
48
+ children,
49
+ themeOptions,
50
+ portalContainer: portalContainerProp,
51
+ ...rest
52
+ } = props;
53
+ const [portalContainer, setPortalContainer] = useUncontrolledState(
54
+ portalContainerProp || null,
55
+ );
56
+ const [parentTheme, rootRef] = useParentTheme();
57
+ const theme = themeProp === 'inherit' ? parentTheme || 'light' : themeProp;
58
+ const shouldApplyBackground = themeOptions?.applyBackground ?? !parentTheme;
45
59
  const contextValue = React.useMemo(
46
- () => ({ theme, themeOptions, portalContainerRef }),
47
- [theme, themeOptions],
60
+ () => ({ theme, themeOptions, portalContainer }),
61
+ [theme, themeOptions, portalContainer],
48
62
  );
49
63
  return React.createElement(
50
64
  ThemeContext.Provider,
@@ -55,23 +69,29 @@ export const ThemeProvider = React.forwardRef((props, ref) => {
55
69
  theme: theme,
56
70
  shouldApplyBackground: shouldApplyBackground,
57
71
  themeOptions: themeOptions,
58
- ref: ref,
72
+ ref: useMergedRefs(forwardedRef, rootRef),
59
73
  ...rest,
60
74
  },
61
75
  React.createElement(
62
76
  ToastProvider,
63
77
  null,
64
78
  children,
65
- React.createElement(
66
- 'div',
67
- { ref: portalContainerRef },
68
- React.createElement(Toaster, null),
69
- ),
79
+ portalContainerProp
80
+ ? ReactDOM.createPortal(
81
+ React.createElement(Toaster, null),
82
+ portalContainerProp,
83
+ )
84
+ : React.createElement(
85
+ 'div',
86
+ { ref: setPortalContainer },
87
+ React.createElement(Toaster, null),
88
+ ),
70
89
  ),
71
90
  ),
72
91
  );
73
92
  });
74
93
  export default ThemeProvider;
94
+ // ----------------------------------------------------------------------------
75
95
  const Root = React.forwardRef((props, forwardedRef) => {
76
96
  const {
77
97
  theme,
@@ -81,8 +101,6 @@ const Root = React.forwardRef((props, forwardedRef) => {
81
101
  className,
82
102
  ...rest
83
103
  } = props;
84
- const ref = React.useRef(null);
85
- const mergedRefs = useMergedRefs(ref, forwardedRef);
86
104
  const prefersDark = useMediaQuery('(prefers-color-scheme: dark)');
87
105
  const prefersHighContrast = useMediaQuery('(prefers-contrast: more)');
88
106
  const shouldApplyDark = theme === 'dark' || (theme === 'os' && prefersDark);
@@ -97,9 +115,31 @@ const Root = React.forwardRef((props, forwardedRef) => {
97
115
  ),
98
116
  'data-iui-theme': shouldApplyDark ? 'dark' : 'light',
99
117
  'data-iui-contrast': shouldApplyHC ? 'high' : 'default',
100
- ref: mergedRefs,
118
+ ref: forwardedRef,
101
119
  ...rest,
102
120
  },
103
121
  children,
104
122
  );
105
123
  });
124
+ // ----------------------------------------------------------------------------
125
+ /**
126
+ * Returns theme from either parent context or by reading the closest
127
+ * data-iui-theme attribute if context is not found.
128
+ */
129
+ const useParentTheme = () => {
130
+ const parentContext = React.useContext(ThemeContext);
131
+ const rootRef = React.useRef(null);
132
+ const [parentThemeState, setParentTheme] = React.useState(
133
+ parentContext?.theme,
134
+ );
135
+ useIsomorphicLayoutEffect(() => {
136
+ setParentTheme(
137
+ (old) =>
138
+ old ||
139
+ rootRef.current?.parentElement
140
+ ?.closest('[data-iui-theme]')
141
+ ?.getAttribute('data-iui-theme'),
142
+ );
143
+ }, []);
144
+ return [parentContext?.theme ?? parentThemeState, rootRef];
145
+ };
@@ -125,10 +125,11 @@ export declare const Tile: PolymorphicForwardRefComponent<"div", TileOwnProps> &
125
125
  */
126
126
  IconButton: PolymorphicForwardRefComponent<"button", Omit<Omit<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
127
127
  ref?: ((instance: HTMLButtonElement | null) => void) | React.RefObject<HTMLButtonElement> | null | undefined;
128
- }, "label" | "as" | "size" | "styleType" | "isActive"> & {
128
+ }, "label" | "as" | "size" | "htmlDisabled" | "styleType" | "isActive" | "iconProps"> & {
129
129
  isActive?: boolean | undefined;
130
130
  label?: React.ReactNode;
131
- } & Omit<import("../Buttons/Button/Button.js").ButtonProps, "startIcon" | "endIcon"> & {
131
+ iconProps?: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> | undefined;
132
+ } & Omit<import("../Buttons/Button/Button.js").ButtonProps, "startIcon" | "endIcon" | "labelProps" | "startIconProps" | "endIconProps"> & {
132
133
  as?: "button" | undefined;
133
134
  }, "ref">>;
134
135
  /**
@@ -11,6 +11,7 @@ import {
11
11
  SvgCloseSmall,
12
12
  Box,
13
13
  useSafeContext,
14
+ ButtonBase,
14
15
  } from '../utils/index.js';
15
16
  import { IconButton } from '../Buttons/index.js';
16
17
  import { ToasterStateContext } from './Toaster.js';
@@ -46,9 +47,9 @@ export const Toast = (props) => {
46
47
  const [margin, setMargin] = React.useState(0);
47
48
  const marginStyle = () => {
48
49
  if (placementPosition === 'top') {
49
- return { marginBottom: margin };
50
+ return { marginBlockEnd: margin };
50
51
  }
51
- return { marginTop: margin };
52
+ return { marginBlockStart: margin };
52
53
  };
53
54
  React.useEffect(() => {
54
55
  if (type === 'temporary') {
@@ -185,13 +186,8 @@ export const ToastPresentation = (props) => {
185
186
  React.createElement(Box, { className: 'iui-message' }, content),
186
187
  link &&
187
188
  React.createElement(
188
- Box,
189
- {
190
- as: 'button',
191
- className: 'iui-toast-anchor',
192
- ...link,
193
- title: undefined,
194
- },
189
+ ButtonBase,
190
+ { className: 'iui-toast-anchor', ...link, title: undefined },
195
191
  link.title,
196
192
  ),
197
193
  (type === 'persisting' || hasCloseButton) &&
@@ -55,7 +55,7 @@ type TooltipOwnProps = {
55
55
  children?: React.ReactNode;
56
56
  /**
57
57
  * Element to portal tooltip to.
58
- * Portals to ThemeProvider portalContainerRef by default.
58
+ * Portals to ThemeProvider portalContainer by default.
59
59
  * @default true;
60
60
  */
61
61
  portal?: boolean | {
@@ -135,7 +135,7 @@ export const Tooltip = React.forwardRef((props, forwardRef) => {
135
135
  typeof portal !== 'boolean'
136
136
  ? portal.to
137
137
  : portal
138
- ? context?.portalContainerRef?.current ?? getDocument()?.body
138
+ ? context?.portalContainer || getDocument()?.body
139
139
  : null;
140
140
  const contentBox = React.createElement(
141
141
  Box,
@@ -221,7 +221,7 @@ export const TreeNode = (props) => {
221
221
  as: 'ul',
222
222
  className: 'iui-sub-tree',
223
223
  role: 'group',
224
- 'aria-owns': subNodeIds.join(','),
224
+ 'aria-owns': subNodeIds.join(' '),
225
225
  }),
226
226
  );
227
227
  };
@@ -0,0 +1,14 @@
1
+ import type { PolymorphicForwardRefComponent } from '../props.js';
2
+ export declare const ButtonBase: PolymorphicForwardRefComponent<"button", ButtonBaseProps>;
3
+ type ButtonBaseProps = {
4
+ /**
5
+ * Custom `disabled` prop that keeps the button focusable, prevents
6
+ * clicks, applied disabled styling, and adds `aria-disabled`.
7
+ */
8
+ disabled?: boolean;
9
+ /**
10
+ * Built-in html `disabled` attribute
11
+ */
12
+ htmlDisabled?: boolean;
13
+ };
14
+ export {};
@@ -0,0 +1,42 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
+ * See LICENSE.md in the project root for license terms and full copyright notice.
4
+ *--------------------------------------------------------------------------------------------*/
5
+ import * as React from 'react';
6
+ import cx from 'classnames';
7
+ import { Box } from './Box.js';
8
+ import { useIsClient } from '../hooks/useIsClient.js';
9
+ export const ButtonBase = React.forwardRef((props, forwardedRef) => {
10
+ const {
11
+ as: asProp = 'button',
12
+ disabled: disabledProp,
13
+ htmlDisabled,
14
+ ...rest
15
+ } = props;
16
+ const isClient = useIsClient();
17
+ const ariaDisabled =
18
+ disabledProp &&
19
+ !htmlDisabled && // htmlDisabled prop takes preference
20
+ isClient && // progressively enhance after first render
21
+ asProp === 'button'; // ignore if not button, e.g. links
22
+ const handleIfEnabled = (handler) => (e) => {
23
+ if (disabledProp) {
24
+ return;
25
+ }
26
+ handler?.(e);
27
+ };
28
+ return React.createElement(Box, {
29
+ as: asProp,
30
+ type: asProp === 'button' ? 'button' : undefined,
31
+ ref: forwardedRef,
32
+ 'aria-disabled': ariaDisabled ? 'true' : undefined,
33
+ 'data-iui-disabled': disabledProp ? 'true' : undefined,
34
+ disabled: htmlDisabled ?? (!isClient && disabledProp) ? true : undefined,
35
+ ...rest,
36
+ className: cx('iui-button-base', props.className),
37
+ onClick: handleIfEnabled(props.onClick),
38
+ onPointerDown: handleIfEnabled(props.onPointerDown),
39
+ onPointerUp: handleIfEnabled(props.onPointerUp),
40
+ });
41
+ });
42
+ ButtonBase.displayName = 'ButtonBase';
@@ -36,8 +36,7 @@ export const Popover = React.forwardRef((props, ref) => {
36
36
  const computedProps = {
37
37
  allowHTML: true,
38
38
  animation: false,
39
- appendTo: (el) =>
40
- themeInfo?.portalContainerRef?.current || el.ownerDocument.body,
39
+ appendTo: (el) => themeInfo?.portalContainer || el.ownerDocument.body,
41
40
  arrow: false,
42
41
  duration: 0,
43
42
  interactive: true,
@@ -62,7 +61,10 @@ export const Popover = React.forwardRef((props, ref) => {
62
61
  ...props.popperOptions,
63
62
  modifiers: [
64
63
  { name: 'flip' },
65
- { name: 'preventOverflow', options: { padding: 0 } },
64
+ {
65
+ name: 'preventOverflow',
66
+ options: { padding: 0 },
67
+ },
66
68
  ...(props.popperOptions?.modifiers || []),
67
69
  ],
68
70
  },
@@ -36,8 +36,8 @@ const getElementHeightWithMargins = (element) => {
36
36
  return undefined;
37
37
  }
38
38
  const margin =
39
- parseFloat(getElementStyle(element, 'margin-top')) +
40
- parseFloat(getElementStyle(element, 'margin-bottom'));
39
+ parseFloat(getElementStyle(element, 'margin-block-start')) +
40
+ parseFloat(getElementStyle(element, 'margin-block-end'));
41
41
  return getElementHeight(element) + (isNaN(margin) ? 0 : margin);
42
42
  };
43
43
  const getNumberOfNodesInHeight = (childHeight, totalHeight) => {
@@ -344,13 +344,13 @@ export const useVirtualization = (props) => {
344
344
  return {
345
345
  outerProps: {
346
346
  style: {
347
- minHeight:
347
+ minBlockSize:
348
348
  itemsLength > 1
349
349
  ? Math.max(itemsLength - 2, 0) * childHeight.current.middle +
350
350
  childHeight.current.first +
351
351
  childHeight.current.last
352
352
  : childHeight.current.middle,
353
- minWidth: '100%',
353
+ minInlineSize: '100%',
354
354
  ...style,
355
355
  },
356
356
  ...rest,
@@ -13,3 +13,4 @@ export * from './Divider.js';
13
13
  export * from './LinkAction.js';
14
14
  export * from './AutoclearingHiddenLiveRegion.js';
15
15
  export * from './Box.js';
16
+ export * from './ButtonBase.js';
@@ -17,3 +17,4 @@ export * from './Divider.js';
17
17
  export * from './LinkAction.js';
18
18
  export * from './AutoclearingHiddenLiveRegion.js';
19
19
  export * from './Box.js';
20
+ export * from './ButtonBase.js';
@@ -17,4 +17,4 @@ export declare const isSoftBackground: (value: string) => value is "skyblue" | "
17
17
  * Generate color from user name or email.
18
18
  * Recommended to use for `backgroundColor` in `Avatar` component.
19
19
  */
20
- export declare const getUserColor: (emailOrName: string) => string;
20
+ export declare const getUserColor: (emailOrName: string) => "var(--iui-color-background-skyblue)" | "var(--iui-color-background-celery)" | "var(--iui-color-background-froly)" | "var(--iui-color-background-steelblue)" | "var(--iui-color-background-sunglow)" | "var(--iui-color-background-seabuckthorn)" | "var(--iui-color-background-montecarlo)" | "var(--iui-color-background-poloblue)" | "var(--iui-color-background-bouquet)" | "var(--iui-color-background-ash)" | "var(--iui-color-background-oak)";
@@ -19,19 +19,7 @@ export const SoftBackgrounds = {
19
19
  export const isSoftBackground = (value) => {
20
20
  return Object.keys(SoftBackgrounds).includes(value);
21
21
  };
22
- const USER_COLORS = [
23
- '#6AB9EC',
24
- '#B1C854',
25
- '#F7706C',
26
- '#4585A5',
27
- '#FFC335',
28
- '#F7963E',
29
- '#73C7C1',
30
- '#85A9CF',
31
- '#A3779F',
32
- '#C8C2B4',
33
- '#A47854',
34
- ];
22
+ const USER_COLORS = Object.values(SoftBackgrounds);
35
23
  /**
36
24
  * Generate color from user name or email.
37
25
  * Recommended to use for `backgroundColor` in `Avatar` component.
@@ -11,3 +11,4 @@ export * from './useLatestRef.js';
11
11
  export * from './useIsomorphicLayoutEffect.js';
12
12
  export * from './useIsClient.js';
13
13
  export * from './useId.js';
14
+ export * from './useUncontrolledState.js';
@@ -15,3 +15,4 @@ export * from './useLatestRef.js';
15
15
  export * from './useIsomorphicLayoutEffect.js';
16
16
  export * from './useIsClient.js';
17
17
  export * from './useId.js';
18
+ export * from './useUncontrolledState.js';