react-panel-layout 0.6.0 → 0.6.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.
- package/dist/{FloatingPanelFrame-SgYLc6Ud.js → FloatingPanelFrame-3eU9AwPo.js} +2 -2
- package/dist/{FloatingPanelFrame-SgYLc6Ud.js.map → FloatingPanelFrame-3eU9AwPo.js.map} +1 -1
- package/dist/FloatingWindow-CUXnEtrb.js +827 -0
- package/dist/FloatingWindow-CUXnEtrb.js.map +1 -0
- package/dist/FloatingWindow-DMwyK0eK.cjs +2 -0
- package/dist/FloatingWindow-DMwyK0eK.cjs.map +1 -0
- package/dist/GridLayout-DKTg_N61.cjs +2 -0
- package/dist/{GridLayout-B4VRsC0r.cjs.map → GridLayout-DKTg_N61.cjs.map} +1 -1
- package/dist/{GridLayout-BltqeCPK.js → GridLayout-UWNxXw77.js} +34 -35
- package/dist/{GridLayout-BltqeCPK.js.map → GridLayout-UWNxXw77.js.map} +1 -1
- package/dist/{HorizontalDivider-WF1k_qND.js → HorizontalDivider-DdxzfV0l.js} +3 -3
- package/dist/{HorizontalDivider-WF1k_qND.js.map → HorizontalDivider-DdxzfV0l.js.map} +1 -1
- package/dist/{HorizontalDivider-B5Z-KZLk.cjs → HorizontalDivider-_pgV4Mcv.cjs} +2 -2
- package/dist/{HorizontalDivider-B5Z-KZLk.cjs.map → HorizontalDivider-_pgV4Mcv.cjs.map} +1 -1
- package/dist/{PanelSystem-Dr1TBhxM.js → PanelSystem-BqUzNtf2.js} +5 -5
- package/dist/{PanelSystem-Dr1TBhxM.js.map → PanelSystem-BqUzNtf2.js.map} +1 -1
- package/dist/{PanelSystem-Bs8bQwQF.cjs → PanelSystem-D603LKKv.cjs} +2 -2
- package/dist/{PanelSystem-Bs8bQwQF.cjs.map → PanelSystem-D603LKKv.cjs.map} +1 -1
- package/dist/ResizeHandle-CBcAS918.cjs +2 -0
- package/dist/{ResizeHandle-CScipO5l.cjs.map → ResizeHandle-CBcAS918.cjs.map} +1 -1
- package/dist/{ResizeHandle-CdA_JYfN.js → ResizeHandle-CXjc1meV.js} +28 -29
- package/dist/{ResizeHandle-CdA_JYfN.js.map → ResizeHandle-CXjc1meV.js.map} +1 -1
- package/dist/SwipePivotTabBar-DWrCuwEI.js +411 -0
- package/dist/SwipePivotTabBar-DWrCuwEI.js.map +1 -0
- package/dist/SwipePivotTabBar-fjjXkpj7.cjs +2 -0
- package/dist/SwipePivotTabBar-fjjXkpj7.cjs.map +1 -0
- package/dist/components/gesture/SwipeSafeZone.d.ts +40 -0
- package/dist/components/window/Drawer.d.ts +3 -1
- package/dist/components/window/DrawerLayers.d.ts +1 -1
- package/dist/components/window/drawerStyles.d.ts +69 -0
- package/dist/components/window/drawerSwipeConfig.d.ts +29 -0
- package/dist/components/window/useDrawerSwipeTransform.d.ts +23 -0
- package/dist/config.cjs +1 -1
- package/dist/config.js +3 -3
- package/dist/constants/styles.d.ts +17 -0
- package/dist/dialog/index.d.ts +69 -0
- package/dist/floating.js +1 -1
- package/dist/grid.cjs +1 -1
- package/dist/grid.js +2 -2
- package/dist/hooks/gesture/testing/createGestureSimulator.d.ts +7 -0
- package/dist/hooks/gesture/types.d.ts +48 -5
- package/dist/hooks/gesture/utils.d.ts +19 -0
- package/dist/hooks/useAnimationFrame.d.ts +2 -0
- package/dist/hooks/useOperationContinuity.d.ts +64 -0
- package/dist/hooks/useResizeObserver.d.ts +33 -1
- package/dist/hooks/useSharedElementTransition.d.ts +112 -0
- package/dist/hooks/useSwipeContentTransform.d.ts +9 -2
- package/dist/index.cjs +1 -1
- package/dist/index.js +7 -7
- package/dist/modules/dialog/AlertDialog.d.ts +9 -0
- package/dist/modules/dialog/DialogContainer.d.ts +37 -0
- package/dist/modules/dialog/Modal.d.ts +26 -0
- package/dist/modules/dialog/SwipeDialogContainer.d.ts +16 -0
- package/dist/modules/dialog/dialogAnimationUtils.d.ts +113 -0
- package/dist/modules/dialog/types.d.ts +183 -0
- package/dist/modules/dialog/useDialog.d.ts +39 -0
- package/dist/modules/dialog/useDialogContainer.d.ts +47 -0
- package/dist/modules/dialog/useDialogSwipeInput.d.ts +70 -0
- package/dist/modules/dialog/useDialogTransform.d.ts +82 -0
- package/dist/modules/drawer/types.d.ts +74 -0
- package/dist/modules/drawer/useDrawerSwipeInput.d.ts +24 -0
- package/dist/modules/pivot/SwipePivotTabBar.d.ts +3 -0
- package/dist/modules/stack/SwipeStackContent.d.ts +6 -3
- package/dist/modules/stack/SwipeStackOutlet.d.ts +4 -4
- package/dist/modules/stack/computeSwipeStackTransform.d.ts +1 -1
- package/dist/panels.cjs +1 -1
- package/dist/panels.js +1 -1
- package/dist/pivot.cjs +1 -1
- package/dist/pivot.js +1 -1
- package/dist/resizer.cjs +1 -1
- package/dist/resizer.js +2 -2
- package/dist/stack.cjs +1 -1
- package/dist/stack.cjs.map +1 -1
- package/dist/stack.js +503 -762
- package/dist/stack.js.map +1 -1
- package/dist/sticky-header/calculateStickyMetrics.d.ts +28 -0
- package/dist/sticky-header.cjs +1 -1
- package/dist/sticky-header.cjs.map +1 -1
- package/dist/sticky-header.js +59 -51
- package/dist/sticky-header.js.map +1 -1
- package/dist/{styles-DPPuJ0sf.js → styles-NkjuMOVS.js} +13 -13
- package/dist/{styles-DPPuJ0sf.js.map → styles-NkjuMOVS.js.map} +1 -1
- package/dist/styles-qf6ptVLD.cjs.map +1 -1
- package/dist/types.d.ts +16 -0
- package/dist/useDocumentPointerEvents-DXxw3qWj.js +54 -0
- package/dist/useDocumentPointerEvents-DXxw3qWj.js.map +1 -0
- package/dist/useDocumentPointerEvents-DxDSOtip.cjs +2 -0
- package/dist/useDocumentPointerEvents-DxDSOtip.cjs.map +1 -0
- package/dist/useNativeGestureGuard-C7TSqEkr.cjs +2 -0
- package/dist/useNativeGestureGuard-C7TSqEkr.cjs.map +1 -0
- package/dist/useNativeGestureGuard-CGYo6O0r.js +347 -0
- package/dist/useNativeGestureGuard-CGYo6O0r.js.map +1 -0
- package/dist/window/index.d.ts +2 -0
- package/dist/window.cjs +1 -1
- package/dist/window.cjs.map +1 -1
- package/dist/window.js +114 -103
- package/dist/window.js.map +1 -1
- package/package.json +6 -1
- package/src/components/gesture/SwipeSafeZone.tsx +69 -0
- package/src/components/window/Drawer.tsx +249 -162
- package/src/components/window/DrawerLayers.tsx +13 -3
- package/src/components/window/drawerStyles.spec.ts +263 -0
- package/src/components/window/drawerStyles.ts +228 -0
- package/src/components/window/drawerSwipeConfig.spec.ts +131 -0
- package/src/components/window/drawerSwipeConfig.ts +112 -0
- package/src/components/window/useDrawerSwipeTransform.spec.ts +234 -0
- package/src/components/window/useDrawerSwipeTransform.ts +129 -0
- package/src/constants/styles.ts +19 -0
- package/src/demo/pages/Dialog/alerts/index.tsx +22 -0
- package/src/demo/pages/Dialog/card/index.tsx +22 -0
- package/src/demo/pages/Dialog/components/AlertDialogDemo.tsx +124 -0
- package/src/demo/pages/Dialog/components/CardExpandDemo.module.css +243 -0
- package/src/demo/pages/Dialog/components/CardExpandDemo.tsx +204 -0
- package/src/demo/pages/Dialog/components/CustomAlertDialogDemo.tsx +219 -0
- package/src/demo/pages/Dialog/components/DialogDemos.module.css +77 -0
- package/src/demo/pages/Dialog/components/ModalBasics.tsx +45 -0
- package/src/demo/pages/Dialog/components/SwipeDialogDemo.module.css +77 -0
- package/src/demo/pages/Dialog/components/SwipeDialogDemo.tsx +181 -0
- package/src/demo/pages/Dialog/custom-alert/index.tsx +22 -0
- package/src/demo/pages/Dialog/modal/index.tsx +17 -0
- package/src/demo/pages/Dialog/swipe/index.tsx +22 -0
- package/src/demo/pages/Drawer/components/DrawerSwipe.module.css +316 -0
- package/src/demo/pages/Drawer/components/DrawerSwipe.tsx +178 -0
- package/src/demo/pages/Drawer/swipe/index.tsx +17 -0
- package/src/demo/pages/Pivot/components/SwipeTabsPivot.tsx +54 -23
- package/src/demo/pages/Pivot/swipe-debug/index.tsx +1 -1
- package/src/demo/pages/Stack/components/StackBasics.spec.tsx +152 -0
- package/src/demo/pages/Stack/components/StackBasics.tsx +179 -95
- package/src/demo/pages/Stack/components/StackTablet.spec.tsx +120 -0
- package/src/demo/pages/Stack/components/StackTablet.tsx +42 -21
- package/src/demo/routes.tsx +22 -1
- package/src/dialog/index.ts +85 -0
- package/src/hooks/gesture/testing/createGestureSimulator.spec.ts +68 -64
- package/src/hooks/gesture/testing/createGestureSimulator.ts +112 -37
- package/src/hooks/gesture/types.ts +83 -6
- package/src/hooks/gesture/useEdgeSwipeInput.spec.ts +22 -14
- package/src/hooks/gesture/useNativeGestureGuard.spec.ts +91 -31
- package/src/hooks/gesture/useNativeGestureGuard.ts +3 -1
- package/src/hooks/gesture/utils.ts +91 -0
- package/src/hooks/useAnimatedVisibility.spec.ts +44 -24
- package/src/hooks/useAnimatedVisibility.ts +28 -2
- package/src/hooks/useAnimationFrame.ts +8 -0
- package/src/hooks/useOperationContinuity.spec.ts +387 -0
- package/src/hooks/useOperationContinuity.ts +135 -0
- package/src/hooks/useResizeObserver.spec.tsx +277 -0
- package/src/hooks/useResizeObserver.tsx +108 -39
- package/src/hooks/useScrollContainer.ts +4 -10
- package/src/hooks/useSharedElementTransition.ts +333 -0
- package/src/hooks/useSwipeContentTransform.spec.ts +18 -18
- package/src/hooks/useSwipeContentTransform.ts +166 -28
- package/src/modules/dialog/AlertDialog.spec.tsx +387 -0
- package/src/modules/dialog/AlertDialog.tsx +221 -0
- package/src/modules/dialog/DialogContainer.spec.tsx +228 -0
- package/src/modules/dialog/DialogContainer.tsx +188 -0
- package/src/modules/dialog/Modal.spec.tsx +220 -0
- package/src/modules/dialog/Modal.tsx +182 -0
- package/src/modules/dialog/SwipeDialogContainer.tsx +208 -0
- package/src/modules/dialog/dialogAnimationUtils.spec.ts +253 -0
- package/src/modules/dialog/dialogAnimationUtils.ts +297 -0
- package/src/modules/dialog/types.ts +186 -0
- package/src/modules/dialog/useDialog.spec.tsx +447 -0
- package/src/modules/dialog/useDialog.ts +214 -0
- package/src/modules/dialog/useDialogContainer.spec.ts +331 -0
- package/src/modules/dialog/useDialogContainer.ts +150 -0
- package/src/modules/dialog/useDialogSwipeInput.spec.ts +157 -0
- package/src/modules/dialog/useDialogSwipeInput.ts +319 -0
- package/src/modules/dialog/useDialogTransform.spec.ts +370 -0
- package/src/modules/dialog/useDialogTransform.ts +407 -0
- package/src/modules/drawer/types.ts +102 -0
- package/src/modules/drawer/useDrawerSwipeInput.spec.ts +566 -0
- package/src/modules/drawer/useDrawerSwipeInput.ts +399 -0
- package/src/modules/panels/rendering/ContentRegistry.spec.tsx +21 -14
- package/src/modules/pivot/SwipePivotContent.position.spec.tsx +12 -8
- package/src/modules/pivot/SwipePivotContent.spec.tsx +55 -25
- package/src/modules/pivot/SwipePivotContent.tsx +2 -2
- package/src/modules/pivot/SwipePivotTabBar.spec.tsx +85 -68
- package/src/modules/pivot/SwipePivotTabBar.tsx +75 -15
- package/src/modules/pivot/scaleInputState.spec.ts +11 -2
- package/src/modules/pivot/usePivot.spec.ts +17 -3
- package/src/modules/pivot/usePivotSwipeInput.spec.ts +182 -123
- package/src/modules/stack/SwipeStackContent.spec.tsx +387 -100
- package/src/modules/stack/SwipeStackContent.tsx +43 -33
- package/src/modules/stack/SwipeStackOutlet.spec.tsx +14 -16
- package/src/modules/stack/SwipeStackOutlet.tsx +6 -6
- package/src/modules/stack/computeSwipeStackTransform.spec.ts +5 -5
- package/src/modules/stack/computeSwipeStackTransform.ts +3 -3
- package/src/modules/stack/swipeTransitionContinuity.spec.tsx +1133 -0
- package/src/modules/stack/useStackAnimationState.spec.ts +3 -1
- package/src/modules/stack/useStackAnimationState.ts +18 -13
- package/src/modules/stack/useStackNavigation.spec.ts +198 -3
- package/src/modules/stack/useStackNavigation.tsx +113 -56
- package/src/modules/stack/useStackSwipeInput.spec.ts +65 -32
- package/src/modules/stack/useStackSwipeInput.ts +1 -1
- package/src/sticky-header/StickyArea.tsx +29 -57
- package/src/sticky-header/calculateStickyMetrics.spec.ts +105 -0
- package/src/sticky-header/calculateStickyMetrics.ts +50 -0
- package/src/types.ts +18 -0
- package/src/window/index.ts +2 -0
- package/dist/FloatingWindow-BpdOpg_L.js +0 -400
- package/dist/FloatingWindow-BpdOpg_L.js.map +0 -1
- package/dist/FloatingWindow-TCDNY5gE.cjs +0 -2
- package/dist/FloatingWindow-TCDNY5gE.cjs.map +0 -1
- package/dist/GridLayout-B4VRsC0r.cjs +0 -2
- package/dist/ResizeHandle-CScipO5l.cjs +0 -2
- package/dist/SwipePivotTabBar-BGO9X94m.js +0 -407
- package/dist/SwipePivotTabBar-BGO9X94m.js.map +0 -1
- package/dist/SwipePivotTabBar-BrQismcZ.cjs +0 -2
- package/dist/SwipePivotTabBar-BrQismcZ.cjs.map +0 -1
- package/dist/useDocumentPointerEvents-CKdhGXd0.js +0 -46
- package/dist/useDocumentPointerEvents-CKdhGXd0.js.map +0 -1
- package/dist/useDocumentPointerEvents-ChqrKXDk.cjs +0 -2
- package/dist/useDocumentPointerEvents-ChqrKXDk.cjs.map +0 -1
- package/dist/useEffectEvent-Dp7HLCf0.js +0 -13
- package/dist/useEffectEvent-Dp7HLCf0.js.map +0 -1
- package/dist/useEffectEvent-huSsGUnl.cjs +0 -2
- package/dist/useEffectEvent-huSsGUnl.cjs.map +0 -1
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file useDialog hook for imperative alert/confirm/prompt dialogs
|
|
3
|
+
*/
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import type {
|
|
6
|
+
AlertOptions,
|
|
7
|
+
ConfirmOptions,
|
|
8
|
+
PromptOptions,
|
|
9
|
+
DialogQueueItem,
|
|
10
|
+
UseDialogReturn,
|
|
11
|
+
UseDialogProps,
|
|
12
|
+
} from "./types";
|
|
13
|
+
import { AlertDialog } from "./AlertDialog";
|
|
14
|
+
|
|
15
|
+
type DialogState = {
|
|
16
|
+
queue: DialogQueueItem[];
|
|
17
|
+
current: DialogQueueItem | null;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const normalizeAlertOptions = (options: AlertOptions | string): AlertOptions => {
|
|
21
|
+
if (typeof options === "string") {
|
|
22
|
+
return { message: options };
|
|
23
|
+
}
|
|
24
|
+
return options;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const normalizeConfirmOptions = (options: ConfirmOptions | string): ConfirmOptions => {
|
|
28
|
+
if (typeof options === "string") {
|
|
29
|
+
return { message: options };
|
|
30
|
+
}
|
|
31
|
+
return options;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const normalizePromptOptions = (options: PromptOptions | string): PromptOptions => {
|
|
35
|
+
if (typeof options === "string") {
|
|
36
|
+
return { message: options };
|
|
37
|
+
}
|
|
38
|
+
return options;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Hook for imperative alert/confirm/prompt dialogs.
|
|
43
|
+
*
|
|
44
|
+
* Returns functions to show dialogs and an Outlet component that must be rendered.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```tsx
|
|
48
|
+
* function MyComponent() {
|
|
49
|
+
* const { alert, confirm, prompt, Outlet } = useDialog();
|
|
50
|
+
*
|
|
51
|
+
* const handleClick = async () => {
|
|
52
|
+
* await alert("Hello!");
|
|
53
|
+
*
|
|
54
|
+
* const confirmed = await confirm({
|
|
55
|
+
* message: "Are you sure?",
|
|
56
|
+
* confirmLabel: "Yes",
|
|
57
|
+
* cancelLabel: "No",
|
|
58
|
+
* });
|
|
59
|
+
*
|
|
60
|
+
* if (confirmed) {
|
|
61
|
+
* const name = await prompt({
|
|
62
|
+
* message: "Enter your name:",
|
|
63
|
+
* defaultValue: "Anonymous",
|
|
64
|
+
* });
|
|
65
|
+
* console.log("Name:", name);
|
|
66
|
+
* }
|
|
67
|
+
* };
|
|
68
|
+
*
|
|
69
|
+
* return (
|
|
70
|
+
* <>
|
|
71
|
+
* <button onClick={handleClick}>Show dialogs</button>
|
|
72
|
+
* <Outlet />
|
|
73
|
+
* </>
|
|
74
|
+
* );
|
|
75
|
+
* }
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export const useDialog = (props?: UseDialogProps): UseDialogReturn => {
|
|
79
|
+
const DialogComponent = props?.alertDialogComponent ?? AlertDialog;
|
|
80
|
+
const [state, setState] = React.useState<DialogState>({
|
|
81
|
+
queue: [],
|
|
82
|
+
current: null,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Process queue when current dialog is closed
|
|
86
|
+
const processQueue = React.useCallback(() => {
|
|
87
|
+
setState((prev) => {
|
|
88
|
+
if (prev.queue.length === 0) {
|
|
89
|
+
return { ...prev, current: null };
|
|
90
|
+
}
|
|
91
|
+
const [next, ...rest] = prev.queue;
|
|
92
|
+
return { queue: rest, current: next };
|
|
93
|
+
});
|
|
94
|
+
}, []);
|
|
95
|
+
|
|
96
|
+
// Add to queue or show immediately if no current dialog
|
|
97
|
+
const enqueue = React.useCallback((item: DialogQueueItem) => {
|
|
98
|
+
setState((prev) => {
|
|
99
|
+
if (prev.current === null) {
|
|
100
|
+
return { ...prev, current: item };
|
|
101
|
+
}
|
|
102
|
+
return { ...prev, queue: [...prev.queue, item] };
|
|
103
|
+
});
|
|
104
|
+
}, []);
|
|
105
|
+
|
|
106
|
+
const alert = React.useCallback(
|
|
107
|
+
(options: AlertOptions | string): Promise<void> => {
|
|
108
|
+
return new Promise<void>((resolve) => {
|
|
109
|
+
const normalized = normalizeAlertOptions(options);
|
|
110
|
+
enqueue({
|
|
111
|
+
type: "alert",
|
|
112
|
+
options: normalized,
|
|
113
|
+
resolve,
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
},
|
|
117
|
+
[enqueue],
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
const confirm = React.useCallback(
|
|
121
|
+
(options: ConfirmOptions | string): Promise<boolean> => {
|
|
122
|
+
return new Promise<boolean>((resolve) => {
|
|
123
|
+
const normalized = normalizeConfirmOptions(options);
|
|
124
|
+
enqueue({
|
|
125
|
+
type: "confirm",
|
|
126
|
+
options: normalized,
|
|
127
|
+
resolve,
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
},
|
|
131
|
+
[enqueue],
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
const prompt = React.useCallback(
|
|
135
|
+
(options: PromptOptions | string): Promise<string | null> => {
|
|
136
|
+
return new Promise<string | null>((resolve) => {
|
|
137
|
+
const normalized = normalizePromptOptions(options);
|
|
138
|
+
enqueue({
|
|
139
|
+
type: "prompt",
|
|
140
|
+
options: normalized,
|
|
141
|
+
resolve,
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
},
|
|
145
|
+
[enqueue],
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
const handleConfirm = React.useCallback(
|
|
149
|
+
(value?: string) => {
|
|
150
|
+
const current = state.current;
|
|
151
|
+
if (!current) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (current.type === "alert") {
|
|
156
|
+
current.resolve();
|
|
157
|
+
} else if (current.type === "confirm") {
|
|
158
|
+
current.resolve(true);
|
|
159
|
+
} else if (current.type === "prompt") {
|
|
160
|
+
current.resolve(value ?? "");
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
processQueue();
|
|
164
|
+
},
|
|
165
|
+
[state.current, processQueue],
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
const handleCancel = React.useCallback(() => {
|
|
169
|
+
const current = state.current;
|
|
170
|
+
if (!current) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (current.type === "alert") {
|
|
175
|
+
current.resolve();
|
|
176
|
+
} else if (current.type === "confirm") {
|
|
177
|
+
current.resolve(false);
|
|
178
|
+
} else if (current.type === "prompt") {
|
|
179
|
+
current.resolve(null);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
processQueue();
|
|
183
|
+
}, [state.current, processQueue]);
|
|
184
|
+
|
|
185
|
+
const Outlet: React.FC = React.useCallback(() => {
|
|
186
|
+
const current = state.current;
|
|
187
|
+
if (!current) {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const { type, options } = current;
|
|
192
|
+
|
|
193
|
+
return React.createElement(DialogComponent, {
|
|
194
|
+
type,
|
|
195
|
+
visible: true,
|
|
196
|
+
title: options.title,
|
|
197
|
+
message: options.message,
|
|
198
|
+
confirmLabel: type === "alert" ? (options as AlertOptions).okLabel : (options as ConfirmOptions).confirmLabel,
|
|
199
|
+
cancelLabel: (options as ConfirmOptions).cancelLabel,
|
|
200
|
+
placeholder: (options as PromptOptions).placeholder,
|
|
201
|
+
defaultValue: (options as PromptOptions).defaultValue,
|
|
202
|
+
inputType: (options as PromptOptions).inputType,
|
|
203
|
+
onConfirm: handleConfirm,
|
|
204
|
+
onCancel: handleCancel,
|
|
205
|
+
});
|
|
206
|
+
}, [state.current, handleConfirm, handleCancel, DialogComponent]);
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
alert,
|
|
210
|
+
confirm,
|
|
211
|
+
prompt,
|
|
212
|
+
Outlet,
|
|
213
|
+
};
|
|
214
|
+
};
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Tests for useDialogContainer hook
|
|
3
|
+
*/
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { renderHook, act } from "@testing-library/react";
|
|
6
|
+
import { useDialogContainer } from "./useDialogContainer";
|
|
7
|
+
|
|
8
|
+
type CallTracker = {
|
|
9
|
+
calls: ReadonlyArray<ReadonlyArray<unknown>>;
|
|
10
|
+
fn: (...args: ReadonlyArray<unknown>) => void;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const createCallTracker = (): CallTracker => {
|
|
14
|
+
const calls: Array<ReadonlyArray<unknown>> = [];
|
|
15
|
+
const fn = (...args: ReadonlyArray<unknown>): void => {
|
|
16
|
+
calls.push(args);
|
|
17
|
+
};
|
|
18
|
+
return { calls, fn };
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Mock SyntheticEvent with call tracking.
|
|
23
|
+
*/
|
|
24
|
+
type MockSyntheticEvent = React.SyntheticEvent & {
|
|
25
|
+
preventDefault: (() => void) & { calls: number };
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Creates a mock React.SyntheticEvent with preventDefault tracking.
|
|
30
|
+
*/
|
|
31
|
+
function createMockSyntheticEvent(): MockSyntheticEvent {
|
|
32
|
+
const noop = (): void => {};
|
|
33
|
+
const noopBool = (): boolean => false;
|
|
34
|
+
const element = document.createElement("div");
|
|
35
|
+
|
|
36
|
+
const preventDefaultFn = (): void => {
|
|
37
|
+
preventDefaultFn.calls += 1;
|
|
38
|
+
};
|
|
39
|
+
preventDefaultFn.calls = 0;
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
preventDefault: preventDefaultFn,
|
|
43
|
+
target: element,
|
|
44
|
+
currentTarget: element,
|
|
45
|
+
nativeEvent: new Event("test"),
|
|
46
|
+
bubbles: true,
|
|
47
|
+
cancelable: true,
|
|
48
|
+
defaultPrevented: false,
|
|
49
|
+
eventPhase: 0,
|
|
50
|
+
isTrusted: true,
|
|
51
|
+
isDefaultPrevented: noopBool,
|
|
52
|
+
stopPropagation: noop,
|
|
53
|
+
isPropagationStopped: noopBool,
|
|
54
|
+
persist: noop,
|
|
55
|
+
timeStamp: Date.now(),
|
|
56
|
+
type: "test",
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Creates a mock React.MouseEvent for dialog interactions.
|
|
62
|
+
*/
|
|
63
|
+
function createMockMouseEvent(
|
|
64
|
+
target: EventTarget,
|
|
65
|
+
currentTarget: EventTarget,
|
|
66
|
+
): React.MouseEvent<HTMLDialogElement> {
|
|
67
|
+
const noop = (): void => {};
|
|
68
|
+
const noopBool = (): boolean => false;
|
|
69
|
+
const nativeEvent = new MouseEvent("click");
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
target,
|
|
73
|
+
currentTarget,
|
|
74
|
+
nativeEvent,
|
|
75
|
+
bubbles: true,
|
|
76
|
+
cancelable: true,
|
|
77
|
+
defaultPrevented: false,
|
|
78
|
+
eventPhase: 0,
|
|
79
|
+
isTrusted: true,
|
|
80
|
+
preventDefault: noop,
|
|
81
|
+
isDefaultPrevented: noopBool,
|
|
82
|
+
stopPropagation: noop,
|
|
83
|
+
isPropagationStopped: noopBool,
|
|
84
|
+
persist: noop,
|
|
85
|
+
timeStamp: Date.now(),
|
|
86
|
+
type: "click",
|
|
87
|
+
// MouseEvent properties
|
|
88
|
+
altKey: false,
|
|
89
|
+
button: 0,
|
|
90
|
+
buttons: 1,
|
|
91
|
+
clientX: 0,
|
|
92
|
+
clientY: 0,
|
|
93
|
+
ctrlKey: false,
|
|
94
|
+
metaKey: false,
|
|
95
|
+
shiftKey: false,
|
|
96
|
+
getModifierState: noopBool,
|
|
97
|
+
movementX: 0,
|
|
98
|
+
movementY: 0,
|
|
99
|
+
pageX: 0,
|
|
100
|
+
pageY: 0,
|
|
101
|
+
relatedTarget: null,
|
|
102
|
+
screenX: 0,
|
|
103
|
+
screenY: 0,
|
|
104
|
+
// UIEvent properties
|
|
105
|
+
detail: 0,
|
|
106
|
+
view: window,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
describe("useDialogContainer", () => {
|
|
111
|
+
const dialogState = {
|
|
112
|
+
dialog: document.createElement("dialog") as HTMLDialogElement,
|
|
113
|
+
showModal: createCallTracker(),
|
|
114
|
+
close: createCallTracker(),
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
beforeEach(() => {
|
|
118
|
+
// Create mock dialog element
|
|
119
|
+
dialogState.dialog = document.createElement("dialog");
|
|
120
|
+
dialogState.showModal = createCallTracker();
|
|
121
|
+
dialogState.close = createCallTracker();
|
|
122
|
+
dialogState.dialog.showModal = () => {
|
|
123
|
+
dialogState.showModal.fn();
|
|
124
|
+
};
|
|
125
|
+
dialogState.dialog.close = () => {
|
|
126
|
+
dialogState.close.fn();
|
|
127
|
+
};
|
|
128
|
+
Object.defineProperty(dialogState.dialog, "open", {
|
|
129
|
+
value: false,
|
|
130
|
+
writable: true,
|
|
131
|
+
configurable: true,
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
afterEach(() => {
|
|
136
|
+
document.body.style.overflow = "";
|
|
137
|
+
document.body.style.paddingRight = "";
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("should return dialogRef and dialogProps", () => {
|
|
141
|
+
const onClose = createCallTracker();
|
|
142
|
+
const { result } = renderHook(() =>
|
|
143
|
+
useDialogContainer({
|
|
144
|
+
visible: false,
|
|
145
|
+
onClose: onClose.fn,
|
|
146
|
+
}),
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
expect(result.current.dialogRef).toBeDefined();
|
|
150
|
+
expect(result.current.dialogProps).toBeDefined();
|
|
151
|
+
expect(result.current.dialogProps.onCancel).toBeInstanceOf(Function);
|
|
152
|
+
expect(result.current.dialogProps.onClick).toBeInstanceOf(Function);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it("should call showModal when visible becomes true", () => {
|
|
156
|
+
const onClose = createCallTracker();
|
|
157
|
+
const { result, rerender } = renderHook(
|
|
158
|
+
({ visible }) =>
|
|
159
|
+
useDialogContainer({
|
|
160
|
+
visible,
|
|
161
|
+
onClose: onClose.fn,
|
|
162
|
+
}),
|
|
163
|
+
{ initialProps: { visible: false } },
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
// Assign mock dialog to ref
|
|
167
|
+
act(() => {
|
|
168
|
+
(result.current.dialogRef as React.MutableRefObject<HTMLDialogElement | null>).current = dialogState.dialog;
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Make visible
|
|
172
|
+
rerender({ visible: true });
|
|
173
|
+
|
|
174
|
+
expect(dialogState.showModal.calls).toHaveLength(1);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it("should call close when visible becomes false", () => {
|
|
178
|
+
const onClose = createCallTracker();
|
|
179
|
+
const { result, rerender } = renderHook(
|
|
180
|
+
({ visible }) =>
|
|
181
|
+
useDialogContainer({
|
|
182
|
+
visible,
|
|
183
|
+
onClose: onClose.fn,
|
|
184
|
+
}),
|
|
185
|
+
{ initialProps: { visible: true } },
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
// Assign mock dialog to ref and set as open
|
|
189
|
+
act(() => {
|
|
190
|
+
(result.current.dialogRef as React.MutableRefObject<HTMLDialogElement | null>).current = dialogState.dialog;
|
|
191
|
+
Object.defineProperty(dialogState.dialog, "open", { value: true, configurable: true });
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// Make invisible
|
|
195
|
+
rerender({ visible: false });
|
|
196
|
+
|
|
197
|
+
expect(dialogState.close.calls).toHaveLength(1);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it("should prevent default on cancel event and call onClose when closeOnEscape is true", () => {
|
|
201
|
+
const onClose = createCallTracker();
|
|
202
|
+
const { result } = renderHook(() =>
|
|
203
|
+
useDialogContainer({
|
|
204
|
+
visible: true,
|
|
205
|
+
onClose: onClose.fn,
|
|
206
|
+
closeOnEscape: true,
|
|
207
|
+
}),
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
const mockEvent = createMockSyntheticEvent();
|
|
211
|
+
|
|
212
|
+
act(() => {
|
|
213
|
+
result.current.dialogProps.onCancel(mockEvent);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
expect(mockEvent.preventDefault.calls).toBeGreaterThan(0);
|
|
217
|
+
expect(onClose.calls).toHaveLength(1);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it("should prevent default on cancel event but NOT call onClose when closeOnEscape is false", () => {
|
|
221
|
+
const onClose = createCallTracker();
|
|
222
|
+
const { result } = renderHook(() =>
|
|
223
|
+
useDialogContainer({
|
|
224
|
+
visible: true,
|
|
225
|
+
onClose: onClose.fn,
|
|
226
|
+
closeOnEscape: false,
|
|
227
|
+
}),
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
const mockEvent = createMockSyntheticEvent();
|
|
231
|
+
|
|
232
|
+
act(() => {
|
|
233
|
+
result.current.dialogProps.onCancel(mockEvent);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
expect(mockEvent.preventDefault.calls).toBeGreaterThan(0);
|
|
237
|
+
expect(onClose.calls).toHaveLength(0);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it("should call onClose on backdrop click when dismissible is true", () => {
|
|
241
|
+
const onClose = createCallTracker();
|
|
242
|
+
const { result } = renderHook(() =>
|
|
243
|
+
useDialogContainer({
|
|
244
|
+
visible: true,
|
|
245
|
+
onClose: onClose.fn,
|
|
246
|
+
dismissible: true,
|
|
247
|
+
}),
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
// Simulate click on dialog element itself (backdrop area)
|
|
251
|
+
const mockEvent = createMockMouseEvent(dialogState.dialog, dialogState.dialog);
|
|
252
|
+
|
|
253
|
+
act(() => {
|
|
254
|
+
result.current.dialogProps.onClick(mockEvent);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
expect(onClose.calls).toHaveLength(1);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it("should NOT call onClose on backdrop click when dismissible is false", () => {
|
|
261
|
+
const onClose = createCallTracker();
|
|
262
|
+
const { result } = renderHook(() =>
|
|
263
|
+
useDialogContainer({
|
|
264
|
+
visible: true,
|
|
265
|
+
onClose: onClose.fn,
|
|
266
|
+
dismissible: false,
|
|
267
|
+
}),
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
const mockEvent = createMockMouseEvent(dialogState.dialog, dialogState.dialog);
|
|
271
|
+
|
|
272
|
+
act(() => {
|
|
273
|
+
result.current.dialogProps.onClick(mockEvent);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
expect(onClose.calls).toHaveLength(0);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it("should NOT call onClose when click is on content (not backdrop)", () => {
|
|
280
|
+
const onClose = createCallTracker();
|
|
281
|
+
const { result } = renderHook(() =>
|
|
282
|
+
useDialogContainer({
|
|
283
|
+
visible: true,
|
|
284
|
+
onClose: onClose.fn,
|
|
285
|
+
dismissible: true,
|
|
286
|
+
}),
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
const contentElement = document.createElement("div");
|
|
290
|
+
|
|
291
|
+
// Click on content inside dialog
|
|
292
|
+
const mockEvent = createMockMouseEvent(contentElement, dialogState.dialog);
|
|
293
|
+
|
|
294
|
+
act(() => {
|
|
295
|
+
result.current.dialogProps.onClick(mockEvent);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
expect(onClose.calls).toHaveLength(0);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it("should set body overflow to hidden when visible and preventBodyScroll is true", () => {
|
|
302
|
+
const onClose = createCallTracker();
|
|
303
|
+
const { unmount } = renderHook(() =>
|
|
304
|
+
useDialogContainer({
|
|
305
|
+
visible: true,
|
|
306
|
+
onClose: onClose.fn,
|
|
307
|
+
preventBodyScroll: true,
|
|
308
|
+
}),
|
|
309
|
+
);
|
|
310
|
+
|
|
311
|
+
expect(document.body.style.overflow).toBe("hidden");
|
|
312
|
+
|
|
313
|
+
unmount();
|
|
314
|
+
|
|
315
|
+
// Should restore
|
|
316
|
+
expect(document.body.style.overflow).toBe("");
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
it("should NOT set body overflow when preventBodyScroll is false", () => {
|
|
320
|
+
const onClose = createCallTracker();
|
|
321
|
+
renderHook(() =>
|
|
322
|
+
useDialogContainer({
|
|
323
|
+
visible: true,
|
|
324
|
+
onClose: onClose.fn,
|
|
325
|
+
preventBodyScroll: false,
|
|
326
|
+
}),
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
expect(document.body.style.overflow).toBe("");
|
|
330
|
+
});
|
|
331
|
+
});
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Hook for managing dialog element lifecycle
|
|
3
|
+
*/
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { useEffectEvent } from "../../hooks/useEffectEvent";
|
|
6
|
+
import { useIsomorphicLayoutEffect } from "../../hooks/useIsomorphicLayoutEffect";
|
|
7
|
+
|
|
8
|
+
export type UseDialogContainerOptions = {
|
|
9
|
+
/** Whether the dialog is visible */
|
|
10
|
+
visible: boolean;
|
|
11
|
+
/** Callback when dialog should close */
|
|
12
|
+
onClose: () => void;
|
|
13
|
+
/** Whether clicking backdrop closes the dialog (default: true) */
|
|
14
|
+
dismissible?: boolean;
|
|
15
|
+
/** Whether pressing Escape closes the dialog (default: true) */
|
|
16
|
+
closeOnEscape?: boolean;
|
|
17
|
+
/** Whether to return focus to previous element on close (default: true) */
|
|
18
|
+
returnFocus?: boolean;
|
|
19
|
+
/** Whether to prevent body scroll when open (default: true) */
|
|
20
|
+
preventBodyScroll?: boolean;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type UseDialogContainerReturn = {
|
|
24
|
+
/** Ref to attach to the dialog element */
|
|
25
|
+
dialogRef: React.RefObject<HTMLDialogElement | null>;
|
|
26
|
+
/** Props to spread onto the dialog element */
|
|
27
|
+
dialogProps: {
|
|
28
|
+
onCancel: (event: React.SyntheticEvent) => void;
|
|
29
|
+
onClick: (event: React.MouseEvent<HTMLDialogElement>) => void;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const isBrowser = typeof window !== "undefined" && typeof document !== "undefined";
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Hook for managing native dialog element lifecycle
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```tsx
|
|
40
|
+
* function MyDialog({ visible, onClose }) {
|
|
41
|
+
* const { dialogRef, dialogProps } = useDialogContainer({
|
|
42
|
+
* visible,
|
|
43
|
+
* onClose,
|
|
44
|
+
* });
|
|
45
|
+
*
|
|
46
|
+
* return (
|
|
47
|
+
* <dialog ref={dialogRef} {...dialogProps}>
|
|
48
|
+
* <div>Dialog content</div>
|
|
49
|
+
* </dialog>
|
|
50
|
+
* );
|
|
51
|
+
* }
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export const useDialogContainer = (options: UseDialogContainerOptions): UseDialogContainerReturn => {
|
|
55
|
+
const {
|
|
56
|
+
visible,
|
|
57
|
+
onClose,
|
|
58
|
+
dismissible = true,
|
|
59
|
+
closeOnEscape = true,
|
|
60
|
+
returnFocus = true,
|
|
61
|
+
preventBodyScroll = true,
|
|
62
|
+
} = options;
|
|
63
|
+
|
|
64
|
+
const dialogRef = React.useRef<HTMLDialogElement | null>(null);
|
|
65
|
+
const previousActiveElementRef = React.useRef<Element | null>(null);
|
|
66
|
+
|
|
67
|
+
const handleClose = useEffectEvent(onClose);
|
|
68
|
+
|
|
69
|
+
// Open/close dialog based on visibility
|
|
70
|
+
useIsomorphicLayoutEffect(() => {
|
|
71
|
+
const dialog = dialogRef.current;
|
|
72
|
+
if (!dialog || !isBrowser) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (visible) {
|
|
77
|
+
// Store currently focused element before opening
|
|
78
|
+
if (returnFocus) {
|
|
79
|
+
previousActiveElementRef.current = document.activeElement;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Open as modal (this puts it in the top layer, above all other content)
|
|
83
|
+
if (!dialog.open) {
|
|
84
|
+
dialog.showModal();
|
|
85
|
+
}
|
|
86
|
+
} else if (dialog.open) {
|
|
87
|
+
dialog.close();
|
|
88
|
+
|
|
89
|
+
// Return focus to previously focused element
|
|
90
|
+
if (returnFocus && previousActiveElementRef.current instanceof HTMLElement) {
|
|
91
|
+
previousActiveElementRef.current.focus();
|
|
92
|
+
previousActiveElementRef.current = null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}, [visible, returnFocus]);
|
|
96
|
+
|
|
97
|
+
// Prevent body scroll when dialog is open
|
|
98
|
+
React.useEffect(() => {
|
|
99
|
+
if (!isBrowser || !preventBodyScroll || !visible) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const originalOverflow = document.body.style.overflow;
|
|
104
|
+
const originalPaddingRight = document.body.style.paddingRight;
|
|
105
|
+
|
|
106
|
+
// Calculate scrollbar width to prevent layout shift
|
|
107
|
+
const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
|
|
108
|
+
|
|
109
|
+
document.body.style.overflow = "hidden";
|
|
110
|
+
if (scrollbarWidth > 0) {
|
|
111
|
+
document.body.style.paddingRight = `${scrollbarWidth}px`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return () => {
|
|
115
|
+
document.body.style.overflow = originalOverflow;
|
|
116
|
+
document.body.style.paddingRight = originalPaddingRight;
|
|
117
|
+
};
|
|
118
|
+
}, [visible, preventBodyScroll]);
|
|
119
|
+
|
|
120
|
+
// Handle cancel event (Escape key)
|
|
121
|
+
const handleCancel = React.useCallback(
|
|
122
|
+
(event: React.SyntheticEvent) => {
|
|
123
|
+
event.preventDefault();
|
|
124
|
+
if (closeOnEscape) {
|
|
125
|
+
handleClose();
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
[closeOnEscape, handleClose],
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
// Handle click on dialog (for backdrop click detection)
|
|
132
|
+
const handleClick = React.useCallback(
|
|
133
|
+
(event: React.MouseEvent<HTMLDialogElement>) => {
|
|
134
|
+
// Check if click was on the dialog backdrop (::backdrop pseudo-element area)
|
|
135
|
+
// The dialog element itself is the backdrop; clicking on it directly means backdrop click
|
|
136
|
+
if (dismissible && event.target === event.currentTarget) {
|
|
137
|
+
handleClose();
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
[dismissible, handleClose],
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
dialogRef,
|
|
145
|
+
dialogProps: {
|
|
146
|
+
onCancel: handleCancel,
|
|
147
|
+
onClick: handleClick,
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
};
|