@itwin/itwinui-react 3.17.0-dev.1 → 3.17.0-dev.2

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 (82) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/DEV-cjs/core/Dialog/Dialog.js +35 -42
  3. package/DEV-cjs/core/Dialog/DialogBackdrop.js +6 -1
  4. package/DEV-cjs/core/Dialog/DialogMain.js +42 -34
  5. package/DEV-cjs/core/Dialog/DialogMainContext.js +23 -0
  6. package/DEV-cjs/core/Dialog/DialogTitleBar.js +10 -1
  7. package/DEV-cjs/core/Panels/Panels.js +1 -1
  8. package/DEV-cjs/core/SideNavigation/SideNavigation.js +1 -11
  9. package/DEV-cjs/core/Table/actionHandlers/selectHandler.js +7 -8
  10. package/DEV-cjs/core/Tabs/Tabs.js +9 -1
  11. package/DEV-cjs/core/ThemeProvider/ThemeProvider.js +1 -2
  12. package/DEV-cjs/core/Toast/Toast.js +132 -77
  13. package/DEV-cjs/core/Toast/Toaster.js +11 -3
  14. package/DEV-cjs/styles.js +1 -1
  15. package/DEV-cjs/utils/components/index.js +0 -1
  16. package/DEV-esm/core/Dialog/Dialog.js +32 -42
  17. package/DEV-esm/core/Dialog/DialogBackdrop.js +6 -1
  18. package/DEV-esm/core/Dialog/DialogMain.js +42 -34
  19. package/DEV-esm/core/Dialog/DialogMainContext.js +3 -0
  20. package/DEV-esm/core/Dialog/DialogTitleBar.js +10 -1
  21. package/DEV-esm/core/Panels/Panels.js +2 -1
  22. package/DEV-esm/core/SideNavigation/SideNavigation.js +2 -17
  23. package/DEV-esm/core/Table/actionHandlers/selectHandler.js +7 -8
  24. package/DEV-esm/core/Tabs/Tabs.js +9 -1
  25. package/DEV-esm/core/ThemeProvider/ThemeProvider.js +1 -2
  26. package/DEV-esm/core/Toast/Toast.js +131 -75
  27. package/DEV-esm/core/Toast/Toaster.js +11 -3
  28. package/DEV-esm/styles.js +1 -1
  29. package/DEV-esm/utils/components/index.js +0 -1
  30. package/LICENSE.md +1 -1
  31. package/cjs/core/Dialog/Dialog.d.ts +1 -1
  32. package/cjs/core/Dialog/Dialog.js +35 -42
  33. package/cjs/core/Dialog/DialogBackdrop.d.ts +1 -1
  34. package/cjs/core/Dialog/DialogBackdrop.js +6 -1
  35. package/cjs/core/Dialog/DialogMain.js +42 -34
  36. package/cjs/core/Dialog/DialogMainContext.d.ts +7 -0
  37. package/cjs/core/Dialog/DialogMainContext.js +23 -0
  38. package/cjs/core/Dialog/DialogTitleBar.js +10 -1
  39. package/cjs/core/Panels/Panels.js +1 -1
  40. package/cjs/core/SideNavigation/SideNavigation.d.ts +2 -2
  41. package/cjs/core/SideNavigation/SideNavigation.js +1 -11
  42. package/cjs/core/Table/actionHandlers/selectHandler.js +7 -8
  43. package/cjs/core/Tabs/Tabs.js +9 -1
  44. package/cjs/core/ThemeProvider/ThemeProvider.d.ts +2 -0
  45. package/cjs/core/ThemeProvider/ThemeProvider.js +1 -2
  46. package/cjs/core/Toast/Toast.d.ts +1 -1
  47. package/cjs/core/Toast/Toast.js +132 -77
  48. package/cjs/core/Toast/Toaster.d.ts +1 -1
  49. package/cjs/core/Toast/Toaster.js +11 -3
  50. package/cjs/styles.js +1 -1
  51. package/cjs/utils/components/index.d.ts +0 -1
  52. package/cjs/utils/components/index.js +0 -1
  53. package/esm/core/Dialog/Dialog.d.ts +1 -1
  54. package/esm/core/Dialog/Dialog.js +32 -42
  55. package/esm/core/Dialog/DialogBackdrop.d.ts +1 -1
  56. package/esm/core/Dialog/DialogBackdrop.js +6 -1
  57. package/esm/core/Dialog/DialogMain.js +42 -34
  58. package/esm/core/Dialog/DialogMainContext.d.ts +7 -0
  59. package/esm/core/Dialog/DialogMainContext.js +3 -0
  60. package/esm/core/Dialog/DialogTitleBar.js +10 -1
  61. package/esm/core/Panels/Panels.js +2 -1
  62. package/esm/core/SideNavigation/SideNavigation.d.ts +2 -2
  63. package/esm/core/SideNavigation/SideNavigation.js +2 -17
  64. package/esm/core/Table/actionHandlers/selectHandler.js +7 -8
  65. package/esm/core/Tabs/Tabs.js +9 -1
  66. package/esm/core/ThemeProvider/ThemeProvider.d.ts +2 -0
  67. package/esm/core/ThemeProvider/ThemeProvider.js +1 -2
  68. package/esm/core/Toast/Toast.d.ts +1 -1
  69. package/esm/core/Toast/Toast.js +131 -75
  70. package/esm/core/Toast/Toaster.d.ts +1 -1
  71. package/esm/core/Toast/Toaster.js +11 -3
  72. package/esm/styles.js +1 -1
  73. package/esm/utils/components/index.d.ts +0 -1
  74. package/esm/utils/components/index.js +0 -1
  75. package/package.json +3 -5
  76. package/styles.css +10 -10
  77. package/DEV-cjs/utils/components/WithCSSTransition.js +0 -60
  78. package/DEV-esm/utils/components/WithCSSTransition.js +0 -49
  79. package/cjs/utils/components/WithCSSTransition.d.ts +0 -6
  80. package/cjs/utils/components/WithCSSTransition.js +0 -60
  81. package/esm/utils/components/WithCSSTransition.d.ts +0 -6
  82. package/esm/utils/components/WithCSSTransition.js +0 -49
@@ -20,7 +20,6 @@ _export(exports, {
20
20
  const _interop_require_default = require('@swc/helpers/_/_interop_require_default');
21
21
  const _interop_require_wildcard = require('@swc/helpers/_/_interop_require_wildcard');
22
22
  const _react = _interop_require_wildcard._(require('react'));
23
- const _reacttransitiongroup = require('react-transition-group');
24
23
  const _classnames = _interop_require_default._(require('classnames'));
25
24
  const _index = require('../../utils/index.js');
26
25
  const _IconButton = require('../Buttons/IconButton.js');
@@ -48,9 +47,6 @@ const Toast = (props) => {
48
47
  let [height, setHeight] = _react.useState(0);
49
48
  let thisElement = _react.useRef(null);
50
49
  let [margin, setMargin] = _react.useState(0);
51
- let motionOk = (0, _index.useMediaQuery)(
52
- '(prefers-reduced-motion: no-preference)',
53
- );
54
50
  let marginStyle = () => {
55
51
  if ('top' === placementPosition)
56
52
  return {
@@ -90,81 +86,41 @@ const Toast = (props) => {
90
86
  setHeight(height);
91
87
  }
92
88
  };
93
- let calculateOutAnimation = (node) => {
94
- let translateX = 0;
95
- let translateY = 0;
96
- if (animateOutTo && node) {
97
- let { x: startX, y: startY } = node.getBoundingClientRect();
98
- let { x: endX, y: endY } = animateOutTo.getBoundingClientRect();
99
- translateX = endX - startX;
100
- translateY = endY - startY;
101
- }
102
- return {
103
- translateX,
104
- translateY,
105
- };
106
- };
107
- return _react.createElement(
108
- _reacttransitiongroup.Transition,
109
- {
110
- timeout: {
111
- enter: 240,
112
- exit: animateOutTo ? 400 : 120,
113
- },
114
- in: isVisible,
115
- appear: true,
116
- unmountOnExit: true,
117
- onEnter: (node) => {
118
- if (motionOk) {
119
- node.style.transform = 'translateY(15%)';
120
- node.style.transitionTimingFunction = 'ease';
121
- }
122
- },
123
- onEntered: (node) => {
124
- if (motionOk) node.style.transform = 'translateY(0)';
125
- },
126
- onExiting: (node) => {
127
- if (motionOk) {
128
- let { translateX, translateY } = calculateOutAnimation(node);
129
- node.style.transform = animateOutTo
130
- ? `scale(0.9) translate(${translateX}px,${translateY}px)`
131
- : 'scale(0.9)';
132
- node.style.opacity = '0';
133
- node.style.transitionDuration = animateOutTo ? '400ms' : '120ms';
134
- node.style.transitionTimingFunction = 'cubic-bezier(0.4, 0, 1, 1)';
135
- }
136
- },
137
- onExited: onRemove,
138
- },
139
- _react.createElement(
140
- _index.Box,
141
- {
142
- ref: thisElement,
143
- className: 'iui-toast-all',
144
- style: {
145
- height,
146
- ...marginStyle(),
147
- },
148
- },
149
- _react.createElement(
150
- 'div',
89
+ let shouldBeMounted = useAnimateToastBasedOnVisibility(isVisible, {
90
+ thisElement,
91
+ animateOutTo,
92
+ onRemove,
93
+ });
94
+ return shouldBeMounted
95
+ ? _react.createElement(
96
+ _index.Box,
151
97
  {
152
- ref: onRef,
98
+ ref: thisElement,
99
+ className: 'iui-toast-all',
100
+ style: {
101
+ height,
102
+ ...marginStyle(),
103
+ },
153
104
  },
154
- _react.createElement(ToastPresentation, {
155
- as: 'div',
156
- category: category,
157
- content: content,
158
- link: link,
159
- type: type,
160
- hasCloseButton: hasCloseButton,
161
- onClose: close,
162
- ...domProps?.toastProps,
163
- contentProps: domProps?.contentProps,
164
- }),
165
- ),
166
- ),
167
- );
105
+ _react.createElement(
106
+ 'div',
107
+ {
108
+ ref: onRef,
109
+ },
110
+ _react.createElement(ToastPresentation, {
111
+ as: 'div',
112
+ category: category,
113
+ content: content,
114
+ link: link,
115
+ type: type,
116
+ hasCloseButton: hasCloseButton,
117
+ onClose: close,
118
+ ...domProps?.toastProps,
119
+ contentProps: domProps?.contentProps,
120
+ }),
121
+ ),
122
+ )
123
+ : null;
168
124
  };
169
125
  const ToastPresentation = _react.forwardRef((props, forwardedRef) => {
170
126
  let {
@@ -239,3 +195,102 @@ const ToastPresentation = _react.forwardRef((props, forwardedRef) => {
239
195
  ),
240
196
  );
241
197
  });
198
+ const useAnimateToastBasedOnVisibility = (isVisible, args) => {
199
+ let { thisElement, animateOutTo, onRemove } = args;
200
+ let [shouldBeMounted, setShouldBeMounted] = _react.useState(isVisible);
201
+ let motionOk = (0, _index.useMediaQuery)(
202
+ '(prefers-reduced-motion: no-preference)',
203
+ );
204
+ let onRemoveRef = (0, _index.useLatestRef)(onRemove);
205
+ let [prevIsVisible, setPrevIsVisible] = _react.useState(void 0);
206
+ _react.useEffect(() => {
207
+ if (prevIsVisible !== isVisible) {
208
+ setPrevIsVisible(isVisible);
209
+ if (isVisible) safeAnimateIn();
210
+ else safeAnimateOut();
211
+ }
212
+ function calculateOutAnimation(node) {
213
+ let translateX = 0;
214
+ let translateY = 0;
215
+ if (animateOutTo && node) {
216
+ let { x: startX, y: startY } = node.getBoundingClientRect();
217
+ let { x: endX, y: endY } = animateOutTo.getBoundingClientRect();
218
+ translateX = endX - startX;
219
+ translateY = endY - startY;
220
+ }
221
+ return {
222
+ translateX,
223
+ translateY,
224
+ };
225
+ }
226
+ function safeAnimateIn() {
227
+ setShouldBeMounted(true);
228
+ queueMicrotask(() => {
229
+ animateIn();
230
+ });
231
+ }
232
+ function safeAnimateOut() {
233
+ if (motionOk) {
234
+ let animation = animateOut();
235
+ animation?.addEventListener('finish', () => {
236
+ setShouldBeMounted(false);
237
+ onRemoveRef.current?.();
238
+ });
239
+ } else {
240
+ setShouldBeMounted(false);
241
+ onRemoveRef.current?.();
242
+ }
243
+ }
244
+ function animateIn() {
245
+ if (!motionOk) return;
246
+ thisElement.current?.animate?.(
247
+ [
248
+ {
249
+ transform: 'translateY(15%)',
250
+ },
251
+ {
252
+ transform: 'translateY(0)',
253
+ },
254
+ ],
255
+ {
256
+ duration: 240,
257
+ fill: 'forwards',
258
+ },
259
+ );
260
+ }
261
+ function animateOut() {
262
+ if (null == thisElement.current || !motionOk) return;
263
+ let { translateX, translateY } = calculateOutAnimation(
264
+ thisElement.current,
265
+ );
266
+ let animationDuration = animateOutTo ? 400 : 120;
267
+ let animation = thisElement.current?.animate?.(
268
+ [
269
+ {
270
+ transform: animateOutTo
271
+ ? `scale(0.9) translate(${translateX}px,${translateY}px)`
272
+ : 'scale(0.9)',
273
+ opacity: 0,
274
+ transitionDuration: `${animationDuration}ms`,
275
+ transitionTimingFunction: 'cubic-bezier(0.4, 0, 1, 1)',
276
+ },
277
+ ],
278
+ {
279
+ duration: animationDuration,
280
+ iterations: 1,
281
+ fill: 'forwards',
282
+ },
283
+ );
284
+ return animation;
285
+ }
286
+ }, [
287
+ isVisible,
288
+ prevIsVisible,
289
+ animateOutTo,
290
+ motionOk,
291
+ thisElement,
292
+ setShouldBeMounted,
293
+ onRemoveRef,
294
+ ]);
295
+ return shouldBeMounted;
296
+ };
@@ -38,7 +38,7 @@ export declare const Toaster: () => React.JSX.Element;
38
38
  export declare const ToastProvider: ({ children, inherit, }: {
39
39
  children: React.ReactNode;
40
40
  inherit?: boolean;
41
- }) => string | number | boolean | Iterable<React.ReactNode> | React.JSX.Element | null | undefined;
41
+ }) => React.JSX.Element;
42
42
  export declare const ToasterStateContext: React.Context<ToasterState | undefined>;
43
43
  type ToasterState = {
44
44
  toasts: ToastProps[];
@@ -96,16 +96,24 @@ const ToastProvider = ({ children, inherit = false }) => {
96
96
  placement: 'top',
97
97
  },
98
98
  });
99
- if (_react.useContext(ToasterStateContext) && inherit) return children;
99
+ let toasterDispatchContext = _react.useContext(ToasterDispatchContext);
100
+ let toasterStateContext = _react.useContext(ToasterStateContext);
101
+ let shouldReuse = toasterStateContext && inherit;
102
+ let toasterDispatchContextValue = shouldReuse
103
+ ? toasterDispatchContext
104
+ : dispatch;
105
+ let toasterStateContextValue = shouldReuse
106
+ ? toasterStateContext
107
+ : toasterState;
100
108
  return _react.createElement(
101
109
  ToasterDispatchContext.Provider,
102
110
  {
103
- value: dispatch,
111
+ value: toasterDispatchContextValue,
104
112
  },
105
113
  _react.createElement(
106
114
  ToasterStateContext.Provider,
107
115
  {
108
- value: toasterState,
116
+ value: toasterStateContextValue,
109
117
  },
110
118
  children,
111
119
  ),
package/cjs/styles.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3
- const e = '3.17.0-dev.1';
3
+ const e = '3.17.0-dev.2';
4
4
  const u = new Proxy(
5
5
  {},
6
6
  {
@@ -3,7 +3,6 @@ export * from './FocusTrap.js';
3
3
  export * from './InputContainer.js';
4
4
  export * from './InputFlexContainer.js';
5
5
  export * from './InputWithIcon.js';
6
- export * from './WithCSSTransition.js';
7
6
  export * from './MiddleTextTruncation.js';
8
7
  export * from './AutoclearingHiddenLiveRegion.js';
9
8
  export * from './Box.js';
@@ -8,7 +8,6 @@ _export_star._(require('./FocusTrap.js'), exports);
8
8
  _export_star._(require('./InputContainer.js'), exports);
9
9
  _export_star._(require('./InputFlexContainer.js'), exports);
10
10
  _export_star._(require('./InputWithIcon.js'), exports);
11
- _export_star._(require('./WithCSSTransition.js'), exports);
12
11
  _export_star._(require('./MiddleTextTruncation.js'), exports);
13
12
  _export_star._(require('./AutoclearingHiddenLiveRegion.js'), exports);
14
13
  _export_star._(require('./Box.js'), exports);
@@ -6,7 +6,7 @@ type DialogProps = {
6
6
  * Dialog content.
7
7
  */
8
8
  children: React.ReactNode;
9
- } & Omit<DialogContextProps, 'dialogRootRef'>;
9
+ } & DialogContextProps;
10
10
  /**
11
11
  * Dialog component.
12
12
  * @example
@@ -7,7 +7,6 @@ import { DialogContext } from './DialogContext.js';
7
7
  import { DialogButtonBar } from './DialogButtonBar.js';
8
8
  import { DialogMain } from './DialogMain.js';
9
9
  import { useMergedRefs, Box, Portal } from '../../utils/index.js';
10
- import { Transition } from 'react-transition-group';
11
10
  let DialogComponent = React.forwardRef((props, ref) => {
12
11
  let {
13
12
  trapFocus = false,
@@ -27,49 +26,40 @@ let DialogComponent = React.forwardRef((props, ref) => {
27
26
  ...rest
28
27
  } = props;
29
28
  let dialogRootRef = React.useRef(null);
30
- return React.createElement(
31
- Transition,
32
- {
33
- in: isOpen,
34
- timeout: {
35
- exit: 600,
36
- },
37
- mountOnEnter: true,
38
- unmountOnExit: true,
39
- },
40
- React.createElement(
41
- DialogContext.Provider,
42
- {
43
- value: {
44
- isOpen,
45
- onClose,
46
- closeOnEsc,
47
- closeOnExternalClick,
48
- isDismissible,
49
- preventDocumentScroll,
50
- trapFocus,
51
- setFocus,
52
- isDraggable,
53
- isResizable,
54
- relativeTo,
55
- dialogRootRef,
56
- placement,
57
- },
58
- },
59
- React.createElement(
60
- Portal,
29
+ let mergedRefs = useMergedRefs(ref, dialogRootRef);
30
+ return isOpen
31
+ ? React.createElement(
32
+ DialogContext.Provider,
61
33
  {
62
- portal: portal,
34
+ value: {
35
+ isOpen,
36
+ onClose,
37
+ closeOnEsc,
38
+ closeOnExternalClick,
39
+ isDismissible,
40
+ preventDocumentScroll,
41
+ trapFocus,
42
+ setFocus,
43
+ isDraggable,
44
+ isResizable,
45
+ relativeTo,
46
+ placement,
47
+ },
63
48
  },
64
- React.createElement(Box, {
65
- className: cx('iui-dialog-wrapper', className),
66
- 'data-iui-relative': 'container' === relativeTo,
67
- ref: useMergedRefs(ref, dialogRootRef),
68
- ...rest,
69
- }),
70
- ),
71
- ),
72
- );
49
+ React.createElement(
50
+ Portal,
51
+ {
52
+ portal: portal,
53
+ },
54
+ React.createElement(Box, {
55
+ className: cx('iui-dialog-wrapper', className),
56
+ 'data-iui-relative': 'container' === relativeTo,
57
+ ref: mergedRefs,
58
+ ...rest,
59
+ }),
60
+ ),
61
+ )
62
+ : null;
73
63
  });
74
64
  export const Dialog = Object.assign(DialogComponent, {
75
65
  Backdrop: DialogBackdrop,
@@ -1,6 +1,6 @@
1
1
  import type { BackdropProps } from '../Backdrop/Backdrop.js';
2
2
  import type { PolymorphicForwardRefComponent } from '../../utils/index.js';
3
- import type { DialogContextProps } from './DialogContext.js';
3
+ import { type DialogContextProps } from './DialogContext.js';
4
4
  type DialogBackdropProps = BackdropProps & Pick<DialogContextProps, 'onClose' | 'isDismissible' | 'closeOnExternalClick' | 'relativeTo'>;
5
5
  /**
6
6
  * Backdrop component for dialog. Recommended to be used with `Dialog`
@@ -2,9 +2,11 @@ import * as React from 'react';
2
2
  import { Backdrop } from '../Backdrop/Backdrop.js';
3
3
  import { useMergedRefs } from '../../utils/index.js';
4
4
  import { useDialogContext } from './DialogContext.js';
5
+ import { useDialogMainContext } from './DialogMainContext.js';
5
6
  import cx from 'classnames';
6
7
  export const DialogBackdrop = React.forwardRef((props, ref) => {
7
8
  let dialogContext = useDialogContext();
9
+ let dialogMainContext = useDialogMainContext();
8
10
  let {
9
11
  isVisible = dialogContext.isOpen,
10
12
  isDismissible = dialogContext.isDismissible,
@@ -21,7 +23,10 @@ export const DialogBackdrop = React.forwardRef((props, ref) => {
21
23
  let handleMouseDown = (event) => {
22
24
  event.persist();
23
25
  if (event.target !== backdropRef.current) return;
24
- if (isDismissible && closeOnExternalClick && onClose) onClose(event);
26
+ if (isDismissible && closeOnExternalClick && onClose) {
27
+ dialogMainContext?.beforeClose();
28
+ onClose(event);
29
+ }
25
30
  onMouseDown?.(event);
26
31
  };
27
32
  return React.createElement(Backdrop, {
@@ -10,9 +10,9 @@ import {
10
10
  ShadowRoot,
11
11
  } from '../../utils/index.js';
12
12
  import { useDialogContext } from './DialogContext.js';
13
- import { Transition } from 'react-transition-group';
14
13
  import { DialogDragContext } from './DialogDragContext.js';
15
14
  import { useDragAndDrop } from '../../utils/hooks/useDragAndDrop.js';
15
+ import { DialogMainContext } from './DialogMainContext.js';
16
16
  export const DialogMain = React.forwardRef((props, ref) => {
17
17
  let dialogContext = useDialogContext();
18
18
  let {
@@ -33,12 +33,13 @@ export const DialogMain = React.forwardRef((props, ref) => {
33
33
  placement = dialogContext.placement,
34
34
  ...rest
35
35
  } = props;
36
- let [style, setStyle] = React.useState();
36
+ let { dialogRootRef } = dialogContext;
37
37
  let dialogRef = React.useRef(null);
38
- let hasBeenResized = React.useRef(false);
39
38
  let previousFocusedElement = React.useRef();
39
+ let [style, setStyle] = React.useState();
40
+ let hasBeenResized = React.useRef(false);
40
41
  let originalBodyOverflow = React.useRef('');
41
- React.useEffect(() => {
42
+ useLayoutEffect(() => {
42
43
  if (isOpen) originalBodyOverflow.current = document.body.style.overflow;
43
44
  }, [isOpen]);
44
45
  React.useEffect(() => {
@@ -54,17 +55,19 @@ export const DialogMain = React.forwardRef((props, ref) => {
54
55
  return () => {
55
56
  ownerDocument.body.style.overflow = originalBodyOverflow.current;
56
57
  };
57
- }, [isOpen, preventDocumentScroll]);
58
+ }, [dialogRef, isOpen, preventDocumentScroll]);
58
59
  let handleKeyDown = (event) => {
59
60
  if (event.altKey) return;
60
61
  event.persist();
61
- if (isDismissible && closeOnEsc && 'Escape' === event.key && onClose)
62
+ if (isDismissible && closeOnEsc && 'Escape' === event.key && onClose) {
63
+ beforeClose();
62
64
  onClose(event);
65
+ }
63
66
  onKeyDown?.(event);
64
67
  };
65
68
  let { onPointerDown, transform } = useDragAndDrop(
66
69
  dialogRef,
67
- dialogContext.dialogRootRef,
70
+ dialogRootRef,
68
71
  isDraggable,
69
72
  );
70
73
  let handlePointerDown = React.useCallback(
@@ -84,13 +87,35 @@ export const DialogMain = React.forwardRef((props, ref) => {
84
87
  insetBlockStart: dialogRef.current?.offsetTop,
85
88
  transform: `translate(${translateX}px,${translateY}px)`,
86
89
  }));
87
- }, [isDraggable, isOpen]);
90
+ }, [dialogRef, isDraggable, isOpen]);
88
91
  let setResizeStyle = React.useCallback((newStyle) => {
89
92
  setStyle((oldStyle) => ({
90
93
  ...oldStyle,
91
94
  ...newStyle,
92
95
  }));
93
96
  }, []);
97
+ let onEnter = React.useCallback(() => {
98
+ previousFocusedElement.current =
99
+ dialogRef.current?.ownerDocument.activeElement;
100
+ if (setFocus)
101
+ dialogRef.current?.focus({
102
+ preventScroll: true,
103
+ });
104
+ }, [dialogRef, previousFocusedElement, setFocus]);
105
+ let beforeClose = React.useCallback(() => {
106
+ if (
107
+ dialogRef.current?.contains(
108
+ dialogRef.current?.ownerDocument.activeElement,
109
+ )
110
+ )
111
+ previousFocusedElement.current?.focus();
112
+ }, [dialogRef, previousFocusedElement]);
113
+ let mountRef = React.useCallback(
114
+ (element) => {
115
+ if (element) onEnter();
116
+ },
117
+ [onEnter],
118
+ );
94
119
  let content = React.createElement(
95
120
  Box,
96
121
  {
@@ -105,7 +130,7 @@ export const DialogMain = React.forwardRef((props, ref) => {
105
130
  className,
106
131
  ),
107
132
  role: 'dialog',
108
- ref: useMergedRefs(dialogRef, ref),
133
+ ref: useMergedRefs(dialogRef, mountRef, ref),
109
134
  onKeyDown: handleKeyDown,
110
135
  tabIndex: -1,
111
136
  'data-iui-placement': placement,
@@ -123,7 +148,7 @@ export const DialogMain = React.forwardRef((props, ref) => {
123
148
  isResizable &&
124
149
  React.createElement(Resizer, {
125
150
  elementRef: dialogRef,
126
- containerRef: dialogContext.dialogRootRef,
151
+ containerRef: dialogRootRef,
127
152
  onResizeStart: () => {
128
153
  if (!hasBeenResized.current) {
129
154
  hasBeenResized.current = true;
@@ -138,31 +163,14 @@ export const DialogMain = React.forwardRef((props, ref) => {
138
163
  children,
139
164
  );
140
165
  return React.createElement(
141
- Transition,
166
+ DialogMainContext.Provider,
142
167
  {
143
- in: isOpen,
144
- appear: true,
145
- timeout: {
146
- exit: 600,
147
- },
148
- onEntered: () => {
149
- previousFocusedElement.current =
150
- dialogRef.current?.ownerDocument.activeElement;
151
- setFocus &&
152
- dialogRef.current?.focus({
153
- preventScroll: true,
154
- });
155
- },
156
- onExit: () => {
157
- if (
158
- dialogRef.current?.contains(
159
- dialogRef.current?.ownerDocument.activeElement,
160
- )
161
- )
162
- previousFocusedElement.current?.focus();
163
- },
164
- unmountOnExit: true,
165
- nodeRef: dialogRef,
168
+ value: React.useMemo(
169
+ () => ({
170
+ beforeClose,
171
+ }),
172
+ [beforeClose],
173
+ ),
166
174
  },
167
175
  React.createElement(
168
176
  DialogDragContext.Provider,
@@ -0,0 +1,7 @@
1
+ import * as React from 'react';
2
+ type DialogMainContextProps = {
3
+ beforeClose: () => void;
4
+ };
5
+ export declare const DialogMainContext: React.Context<DialogMainContextProps | null>;
6
+ export declare const useDialogMainContext: () => DialogMainContextProps | null;
7
+ export {};
@@ -0,0 +1,3 @@
1
+ import * as React from 'react';
2
+ export const DialogMainContext = React.createContext(null);
3
+ export const useDialogMainContext = () => React.useContext(DialogMainContext);
@@ -3,11 +3,13 @@ import cx from 'classnames';
3
3
  import { SvgClose, mergeEventHandlers, Box } from '../../utils/index.js';
4
4
  import { IconButton } from '../Buttons/IconButton.js';
5
5
  import { useDialogContext } from './DialogContext.js';
6
+ import { useDialogMainContext } from './DialogMainContext.js';
6
7
  import { DialogTitleBarTitle } from './DialogTitleBarTitle.js';
7
8
  import { useDialogDragContext } from './DialogDragContext.js';
8
9
  export const DialogTitleBar = Object.assign(
9
10
  React.forwardRef((props, ref) => {
10
11
  let dialogContext = useDialogContext();
12
+ let dialogMainContext = useDialogMainContext();
11
13
  let {
12
14
  children,
13
15
  titleText,
@@ -19,6 +21,13 @@ export const DialogTitleBar = Object.assign(
19
21
  ...rest
20
22
  } = props;
21
23
  let { onPointerDown } = useDialogDragContext();
24
+ let onClick = React.useCallback(
25
+ (e) => {
26
+ dialogMainContext?.beforeClose();
27
+ onClose?.(e);
28
+ },
29
+ [dialogMainContext, onClose],
30
+ );
22
31
  return React.createElement(
23
32
  Box,
24
33
  {
@@ -41,7 +50,7 @@ export const DialogTitleBar = Object.assign(
41
50
  {
42
51
  size: 'small',
43
52
  styleType: 'borderless',
44
- onClick: onClose,
53
+ onClick: onClick,
45
54
  'aria-label': 'Close',
46
55
  'data-iui-shift': 'right',
47
56
  },
@@ -12,6 +12,7 @@ import {
12
12
  useWarningLogger,
13
13
  useLayoutEffect,
14
14
  useLatestRef,
15
+ useId,
15
16
  } from '../../utils/index.js';
16
17
  import { IconButton } from '../Buttons/IconButton.js';
17
18
  import { Flex } from '../Flex/Flex.js';
@@ -152,7 +153,7 @@ let PanelTrigger = (props) => {
152
153
  panels,
153
154
  } = useSafeContext(PanelsWrapperContext);
154
155
  let { id: panelId } = useSafeContext(PanelContext);
155
- let fallbackId = React.useId();
156
+ let fallbackId = useId();
156
157
  let triggerId = children.props.id || fallbackId;
157
158
  let onClick = React.useCallback(() => {
158
159
  if (null == activePanel) return;
@@ -25,12 +25,12 @@ type SideNavigationProps = {
25
25
  */
26
26
  onExpanderClick?: () => void;
27
27
  /**
28
- * Submenu to show supplemental info assicated to the main item.
28
+ * Submenu to show supplemental info associated to the main item.
29
29
  *
30
30
  * Should be used with the `isSubmenuOpen` props from both `SideNavigation` and `SidenavButton`.
31
31
  * @example
32
32
  * <SideNavigation
33
- * // ...
33
+ * //
34
34
  * submenu={(
35
35
  * <SidenavSubmenu>
36
36
  * <SidenavSubmenuHeader>Documents</SidenavSubmenuHeader>