@atlaskit/modal-dialog 15.0.0 → 15.0.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.
- package/CHANGELOG.md +200 -0
- package/dist/cjs/internal/components/modal-dialog.js +3 -3
- package/dist/cjs/internal/components/modal-wrapper.compiled.css +18 -1
- package/dist/cjs/internal/components/modal-wrapper.js +240 -12
- package/dist/es2019/internal/components/modal-dialog.js +2 -2
- package/dist/es2019/internal/components/modal-wrapper.compiled.css +18 -1
- package/dist/es2019/internal/components/modal-wrapper.js +241 -13
- package/dist/esm/internal/components/modal-dialog.js +2 -2
- package/dist/esm/internal/components/modal-wrapper.compiled.css +18 -1
- package/dist/esm/internal/components/modal-wrapper.js +241 -13
- package/dist/types/internal/components/modal-dialog.d.ts +3 -0
- package/dist/types/types.d.ts +3 -5
- package/dist/types-ts4.5/internal/components/modal-dialog.d.ts +3 -0
- package/dist/types-ts4.5/types.d.ts +3 -5
- package/package.json +11 -7
|
@@ -3,30 +3,62 @@ import _extends from "@babel/runtime/helpers/extends";
|
|
|
3
3
|
import "./modal-wrapper.compiled.css";
|
|
4
4
|
import * as React from 'react';
|
|
5
5
|
import { ax, ix } from "@compiled/react/runtime";
|
|
6
|
-
import { useCallback } from 'react';
|
|
6
|
+
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
7
7
|
import FocusLock from 'react-focus-lock';
|
|
8
8
|
import ScrollLock, { TouchScrollable } from 'react-scrolllock';
|
|
9
9
|
import { usePlatformLeafEventHandler } from '@atlaskit/analytics-next';
|
|
10
10
|
import Blanket from '@atlaskit/blanket';
|
|
11
11
|
import noop from '@atlaskit/ds-lib/noop';
|
|
12
|
+
import useAutoFocus from '@atlaskit/ds-lib/use-auto-focus';
|
|
13
|
+
import { useId } from '@atlaskit/ds-lib/use-id';
|
|
12
14
|
import { Layering } from '@atlaskit/layering';
|
|
13
15
|
import { useNotifyOpenLayerObserver } from '@atlaskit/layering/experimental/open-layer-observer';
|
|
14
16
|
import { Motion } from '@atlaskit/motion';
|
|
17
|
+
import { useExitingPersistence } from '@atlaskit/motion/exiting-persistence';
|
|
15
18
|
import FadeIn from '@atlaskit/motion/fade-in';
|
|
16
19
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
17
20
|
import Portal from '@atlaskit/portal';
|
|
21
|
+
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
|
|
18
22
|
import { layers } from '@atlaskit/theme/constants';
|
|
23
|
+
import { dialogSlideUpAndFade } from '@atlaskit/top-layer/animations';
|
|
24
|
+
import { createCloseEvent } from '@atlaskit/top-layer/create-close-event';
|
|
25
|
+
import { Dialog } from '@atlaskit/top-layer/dialog';
|
|
26
|
+
import { DialogScrollLock } from '@atlaskit/top-layer/dialog-scroll-lock';
|
|
27
|
+
import { ModalContext, ScrollContext } from '../context';
|
|
19
28
|
import useModalStack from '../hooks/use-modal-stack';
|
|
20
29
|
import usePreventProgrammaticScroll from '../hooks/use-prevent-programmatic-scroll';
|
|
21
|
-
import
|
|
30
|
+
import { disableDraggingToCrossOriginIFramesForElement } from '../pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/element';
|
|
31
|
+
import { disableDraggingToCrossOriginIFramesForExternal } from '../pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/external';
|
|
32
|
+
import { disableDraggingToCrossOriginIFramesForTextSelection } from '../pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/text-selection';
|
|
33
|
+
import ModalDialog, { dialogHeight, dialogWidth as getDialogWidth } from './modal-dialog';
|
|
34
|
+
const modalAnimation = dialogSlideUpAndFade();
|
|
22
35
|
const fillScreenStyles = null;
|
|
36
|
+
|
|
37
|
+
// Visual styles for modal content inside native <dialog>.
|
|
38
|
+
// Uses cssMap (not css) to avoid triggering no-nested-styles lint rule.
|
|
39
|
+
|
|
40
|
+
const LOCAL_CURRENT_SURFACE_CSS_VAR = '--ds-elevation-surface-current';
|
|
41
|
+
const topLayerStyles = {
|
|
42
|
+
content: "_1e0c1txw _4t3i1osq _2lx21bp4 _bfhk1bhr _syazi7uo _1q1l1bhr _lcxv1wug _1mq81kw7 _m01u1kw7 _1dg11kw7 _mizu1v1w _1ah3dkaa _ra3xnqa1 _128mdkaa _zg7p130s",
|
|
43
|
+
borderRadius: "_epkxfajl",
|
|
44
|
+
borderRadiusT26: "_epkxpb1k"
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Scroll-mode styles for the content div.
|
|
48
|
+
// Height overrides use ID-scoped <style> (see dialogPositionStyles) because
|
|
49
|
+
// Compiled atomic classes have specificity (0,1,0) (increaseSpecificity is disabled).
|
|
50
|
+
// The doubled-ID selector (#id#id > div) at (2,0,1) reliably wins.
|
|
51
|
+
// Only non-height properties needing the && boost remain here.
|
|
52
|
+
|
|
53
|
+
const topLayerBodyScrollStyles = null;
|
|
54
|
+
const topLayerViewportScrollStyles = null;
|
|
23
55
|
const allowlistElements = (element, callback) => {
|
|
24
|
-
// Allow focus
|
|
25
|
-
//
|
|
26
|
-
if (document.querySelector('.aui-blanket:not([hidden])')) {
|
|
56
|
+
// Allow focus outside modal when AUI dialog is visible
|
|
57
|
+
// eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- legacy FocusLock allowlist
|
|
58
|
+
if (Boolean(document.querySelector('.aui-blanket:not([hidden])'))) {
|
|
27
59
|
return false;
|
|
28
60
|
}
|
|
29
|
-
//
|
|
61
|
+
// Optional callback to let consumers exclude elements from focus lock
|
|
30
62
|
if (typeof callback === 'function') {
|
|
31
63
|
return callback(element);
|
|
32
64
|
}
|
|
@@ -78,7 +110,7 @@ const InternalModalWrapper = props => {
|
|
|
78
110
|
action: 'closed',
|
|
79
111
|
componentName: 'modalDialog',
|
|
80
112
|
packageName: "@atlaskit/modal-dialog",
|
|
81
|
-
packageVersion: "
|
|
113
|
+
packageVersion: "15.0.1"
|
|
82
114
|
});
|
|
83
115
|
const onBlanketClicked = useCallback(e => {
|
|
84
116
|
if (shouldCloseOnOverlayClick) {
|
|
@@ -86,18 +118,214 @@ const InternalModalWrapper = props => {
|
|
|
86
118
|
}
|
|
87
119
|
}, [shouldCloseOnOverlayClick, onCloseHandler]);
|
|
88
120
|
|
|
89
|
-
//
|
|
121
|
+
// Stable callback to avoid re-renders when focusLockAllowlist is not provided.
|
|
90
122
|
const allowListCallback = useCallback(element => allowlistElements(element, focusLockAllowlist), [focusLockAllowlist]);
|
|
91
|
-
|
|
123
|
+
|
|
124
|
+
// Called outside the feature-flag branch to keep hook order stable.
|
|
125
|
+
// Legacy path: FadeIn calls onFinish. Top-layer path: called directly.
|
|
126
|
+
const {
|
|
127
|
+
isExiting,
|
|
128
|
+
onFinish: onExitFinish
|
|
129
|
+
} = useExitingPersistence();
|
|
130
|
+
|
|
131
|
+
// Prevent background scroll (top-layer path uses DialogScrollLock instead).
|
|
132
|
+
// Safe conditional hook: feature flags are resolved once at startup.
|
|
133
|
+
if (!fg('platform-dst-top-layer')) {
|
|
134
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
135
|
+
usePreventProgrammaticScroll();
|
|
136
|
+
}
|
|
92
137
|
useNotifyOpenLayerObserver({
|
|
93
138
|
type: 'modal',
|
|
94
|
-
//
|
|
139
|
+
// Always open — modal is conditionally rendered when visible.
|
|
95
140
|
isOpen: true,
|
|
96
|
-
//
|
|
97
|
-
// by the OpenLayerObserver. The only current use case is closing layers when resizing the nav layout,
|
|
98
|
-
// which cannot happen while a modal dialog is open.
|
|
141
|
+
// No-op: no current use case for programmatic close via OpenLayerObserver.
|
|
99
142
|
onClose: noop
|
|
100
143
|
});
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Top-layer path (platform-dst-top-layer).
|
|
147
|
+
*
|
|
148
|
+
* Replaces Portal, FocusLock, ScrollLock, Blanket, Positioner, and z-index
|
|
149
|
+
* management with native <dialog> via @atlaskit/top-layer/dialog.
|
|
150
|
+
*
|
|
151
|
+
* Key decisions:
|
|
152
|
+
* - Animation: CSS transitions via @starting-style / allow-discrete.
|
|
153
|
+
* - Close gating: onDialogClose only forwards allowed reasons
|
|
154
|
+
* (see notes/guides/dialog-close-flow.md).
|
|
155
|
+
* - onClose event param: undefined - consumers should use close reason.
|
|
156
|
+
* - Focus restoration: native <dialog> behavior replaces react-focus-lock's
|
|
157
|
+
* returnFocus (see accessibility-criteria.md).
|
|
158
|
+
*/
|
|
159
|
+
if (fg('platform-dst-top-layer')) {
|
|
160
|
+
// Native <dialog> always restores focus on close - no opt-out via shouldReturnFocus.
|
|
161
|
+
const defaultTestId = testId || 'modal-dialog';
|
|
162
|
+
|
|
163
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
164
|
+
const id = useId();
|
|
165
|
+
const titleId = `modal-dialog-title-${id}`;
|
|
166
|
+
|
|
167
|
+
// Content container ref - used for onOpenComplete/onCloseComplete callbacks.
|
|
168
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
169
|
+
const contentRef = useRef(null);
|
|
170
|
+
|
|
171
|
+
// Cache last content element for onCloseComplete after children unmount
|
|
172
|
+
// (with reduced motion, contentRef clears before onExitFinish fires).
|
|
173
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
174
|
+
const lastContentElRef = useRef(null);
|
|
175
|
+
if (contentRef.current) {
|
|
176
|
+
lastContentElRef.current = contentRef.current;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Native <dialog> ref - needed for ExitingPersistence to call dialog.close().
|
|
180
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
181
|
+
const dialogRef = useRef(null);
|
|
182
|
+
|
|
183
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
184
|
+
const modalDialogContext = useMemo(() => ({
|
|
185
|
+
testId: defaultTestId,
|
|
186
|
+
titleId,
|
|
187
|
+
onClose: onCloseHandler,
|
|
188
|
+
hasProvidedOnClose: Boolean(providedOnClose),
|
|
189
|
+
isFullScreen: isFullScreen !== null && isFullScreen !== void 0 ? isFullScreen : false
|
|
190
|
+
}), [defaultTestId, titleId, onCloseHandler, providedOnClose, isFullScreen]);
|
|
191
|
+
|
|
192
|
+
// Only forward close when the reason is allowed by props.
|
|
193
|
+
// Passes a synthetic event to satisfy the KeyboardOrMouseEvent contract.
|
|
194
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
195
|
+
const onDialogClose = useCallback(({
|
|
196
|
+
reason
|
|
197
|
+
}) => {
|
|
198
|
+
if (reason === 'escape' && shouldCloseOnEscapePress) {
|
|
199
|
+
onCloseHandler(createCloseEvent({
|
|
200
|
+
reason
|
|
201
|
+
}));
|
|
202
|
+
}
|
|
203
|
+
if (reason === 'overlay-click' && shouldCloseOnOverlayClick) {
|
|
204
|
+
onCloseHandler(createCloseEvent({
|
|
205
|
+
reason
|
|
206
|
+
}));
|
|
207
|
+
}
|
|
208
|
+
}, [onCloseHandler, shouldCloseOnEscapePress, shouldCloseOnOverlayClick]);
|
|
209
|
+
|
|
210
|
+
// ExitingPersistence: isExiting → isOpen={false} → Dialog exit animation →
|
|
211
|
+
// onExitFinish → onCloseComplete + unmount.
|
|
212
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
213
|
+
const handleDialogExitFinish = useCallback(() => {
|
|
214
|
+
var _contentRef$current;
|
|
215
|
+
const el = (_contentRef$current = contentRef.current) !== null && _contentRef$current !== void 0 ? _contentRef$current : lastContentElRef.current;
|
|
216
|
+
if (onCloseComplete && el) {
|
|
217
|
+
onCloseComplete(el);
|
|
218
|
+
}
|
|
219
|
+
lastContentElRef.current = null;
|
|
220
|
+
onExitFinish === null || onExitFinish === void 0 ? void 0 : onExitFinish();
|
|
221
|
+
}, [onExitFinish, onCloseComplete]);
|
|
222
|
+
|
|
223
|
+
// Fire onOpenComplete after mount.
|
|
224
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
225
|
+
useEffect(() => {
|
|
226
|
+
if (onOpenComplete && contentRef.current) {
|
|
227
|
+
onOpenComplete(contentRef.current, true);
|
|
228
|
+
}
|
|
229
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
230
|
+
}, []);
|
|
231
|
+
|
|
232
|
+
// Honor `shouldReturnFocus={ref}` on unmount.
|
|
233
|
+
// Native <dialog>.close() restores focus to the trigger that opened it,
|
|
234
|
+
// but the consumer asked for focus to go to a specific element instead.
|
|
235
|
+
// Run this in an unmount cleanup so it fires after dialog.close()
|
|
236
|
+
// (which fires in the Dialog's effect cleanup).
|
|
237
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
238
|
+
const shouldReturnFocusRef = useRef(shouldReturnFocus);
|
|
239
|
+
shouldReturnFocusRef.current = shouldReturnFocus;
|
|
240
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
241
|
+
useEffect(() => {
|
|
242
|
+
return () => {
|
|
243
|
+
const target = shouldReturnFocusRef.current;
|
|
244
|
+
if (typeof target === 'object' && target.current) {
|
|
245
|
+
target.current.focus();
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
}, []);
|
|
249
|
+
|
|
250
|
+
// Focus a ref-targeted element after mount (when autoFocus is a ref).
|
|
251
|
+
// When true, native <dialog>.showModal() handles focus automatically.
|
|
252
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
253
|
+
useAutoFocus(typeof autoFocus === 'object' ? autoFocus : undefined, typeof autoFocus === 'object');
|
|
254
|
+
|
|
255
|
+
// Chrome cross-origin iframe DnD workaround (crbug.com/362301053)
|
|
256
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
257
|
+
useEffect(() => {
|
|
258
|
+
return combine(disableDraggingToCrossOriginIFramesForElement(), disableDraggingToCrossOriginIFramesForTextSelection(), disableDraggingToCrossOriginIFramesForExternal());
|
|
259
|
+
}, []);
|
|
260
|
+
|
|
261
|
+
// Responsive layout via ID-scoped <style> (same pattern as Dialog's hideBackdrop).
|
|
262
|
+
// ID selector beats Compiled atomic classes without !important and supports @media.
|
|
263
|
+
const namedWidth = getDialogWidth(width !== null && width !== void 0 ? width : 'medium');
|
|
264
|
+
const dialogId = `modal-dialog-${id}`;
|
|
265
|
+
const escapedDialogId = CSS.escape(dialogId);
|
|
266
|
+
|
|
267
|
+
// Percentage widths need special handling in the top layer.
|
|
268
|
+
// In legacy, the percentage resolved against the Positioner's max-width
|
|
269
|
+
// (100vw - 120px). In the top layer, the <dialog>'s containing block is the
|
|
270
|
+
// viewport (100vw), so a raw percentage would produce a wider modal.
|
|
271
|
+
// Transform e.g. '42%' → 'calc(42 * (100vw - 120px) / 100)' to match legacy.
|
|
272
|
+
const resolvedWidth = namedWidth.endsWith('%') ? `calc(${parseFloat(namedWidth)} * (100vw - 120px) / 100)` : namedWidth;
|
|
273
|
+
const dialogStyle = isFullScreen ? {
|
|
274
|
+
width: '100vw',
|
|
275
|
+
height: '100vh',
|
|
276
|
+
margin: '0'
|
|
277
|
+
} : {
|
|
278
|
+
width: `min(${resolvedWidth}, 100vw)`
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
// Shift stacked background modals down by space.100 (8px) per level.
|
|
282
|
+
if (stackIndex > 0) {
|
|
283
|
+
dialogStyle['transform'] = `translateY(calc(${stackIndex}px * ${"var(--ds-space-100, 8px)"}))`;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Mobile: viewport fill. Desktop (≥ 30rem): gutter margins, auto height.
|
|
287
|
+
// Content-div height set via #id > div to beat Compiled's atomic specificity.
|
|
288
|
+
const desktopMargin = shouldScrollInViewport ? '60px auto' : '60px auto auto';
|
|
289
|
+
const resolvedHeight = dialogHeight(height);
|
|
290
|
+
// Body-scroll: specified height or auto. Viewport-scroll: uses min-height.
|
|
291
|
+
const desktopContentHeight = shouldScrollInViewport ? 'auto' : resolvedHeight;
|
|
292
|
+
const desktopContentMinHeight = shouldScrollInViewport ? resolvedHeight : 'auto';
|
|
293
|
+
// Viewport-scroll: the legacy Positioner was a fixed 100vh container that
|
|
294
|
+
// scrolled internally, so the modal section could fill (100vh - 60px top gutter).
|
|
295
|
+
// In the top layer the <dialog> sizes to content with height:auto, so we need
|
|
296
|
+
// an explicit min-height to ensure the dialog stretches to the same visible area.
|
|
297
|
+
const desktopDialogMinHeight = shouldScrollInViewport ? 'min-height:calc(100vh - 60px);' : '';
|
|
298
|
+
// Doubled-ID selector (#id#id > div) at specificity (2,0,1) beats
|
|
299
|
+
// Compiled atomic classes at (0,1,0) (increaseSpecificity is disabled).
|
|
300
|
+
const dialogPositionStyles = isFullScreen ? ''
|
|
301
|
+
// Mobile: edge-to-edge. Desktop (≥ 30rem): 60px gutters, max-width.
|
|
302
|
+
: `#${escapedDialogId}#${escapedDialogId}{margin:0;height:100vh}#${escapedDialogId}#${escapedDialogId}>div{height:100%}@media(min-width:30rem){#${escapedDialogId}#${escapedDialogId}{margin:${desktopMargin};height:auto;${desktopDialogMinHeight}max-width:calc(100vw - 120px)}#${escapedDialogId}#${escapedDialogId}>div{height:${desktopContentHeight};min-height:${desktopContentMinHeight}}}`;
|
|
303
|
+
return /*#__PURE__*/React.createElement(Dialog, {
|
|
304
|
+
ref: dialogRef,
|
|
305
|
+
id: dialogId,
|
|
306
|
+
onClose: onDialogClose,
|
|
307
|
+
onExitFinish: handleDialogExitFinish,
|
|
308
|
+
animate: isFullScreen ? false : modalAnimation,
|
|
309
|
+
isOpen: !isExiting,
|
|
310
|
+
shouldHideBackdrop: stackIndex > 0 || Boolean(isBlanketHidden),
|
|
311
|
+
label: label,
|
|
312
|
+
labelledBy: label ? undefined : titleId,
|
|
313
|
+
testId: defaultTestId
|
|
314
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
|
|
315
|
+
,
|
|
316
|
+
style: dialogStyle
|
|
317
|
+
}, /*#__PURE__*/React.createElement(DialogScrollLock, null), dialogPositionStyles &&
|
|
318
|
+
/*#__PURE__*/
|
|
319
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-global-styles
|
|
320
|
+
React.createElement("style", null, dialogPositionStyles), /*#__PURE__*/React.createElement("div", {
|
|
321
|
+
ref: contentRef,
|
|
322
|
+
className: ax([topLayerStyles.content, !isFullScreen && topLayerStyles.borderRadius, !isFullScreen && fg('platform-dst-shape-theme-default') && topLayerStyles.borderRadiusT26, !isFullScreen && !shouldScrollInViewport && "_bolhzwhf", !isFullScreen && shouldScrollInViewport && "_1tke1kxc _c71lglyw"])
|
|
323
|
+
}, /*#__PURE__*/React.createElement(ModalContext.Provider, {
|
|
324
|
+
value: modalDialogContext
|
|
325
|
+
}, /*#__PURE__*/React.createElement(ScrollContext.Provider, {
|
|
326
|
+
value: shouldScrollInViewport
|
|
327
|
+
}, children))));
|
|
328
|
+
}
|
|
101
329
|
const modalDialogWithBlanket = /*#__PURE__*/React.createElement(Blanket, {
|
|
102
330
|
isTinted: !isBlanketHidden,
|
|
103
331
|
onBlanketClicked: onBlanketClicked,
|
|
@@ -23,7 +23,7 @@ import { disableDraggingToCrossOriginIFramesForTextSelection } from '../pragmati
|
|
|
23
23
|
import { ScrollContext } from '../scroll-context';
|
|
24
24
|
import { width } from '../width';
|
|
25
25
|
import Positioner from './positioner';
|
|
26
|
-
var dialogWidth = function dialogWidth(input) {
|
|
26
|
+
export var dialogWidth = function dialogWidth(input) {
|
|
27
27
|
if (!input) {
|
|
28
28
|
return 'auto';
|
|
29
29
|
}
|
|
@@ -34,7 +34,7 @@ var dialogWidth = function dialogWidth(input) {
|
|
|
34
34
|
}
|
|
35
35
|
return typeof input === 'number' ? "".concat(input, "px") : input;
|
|
36
36
|
};
|
|
37
|
-
var dialogHeight = function dialogHeight(input) {
|
|
37
|
+
export var dialogHeight = function dialogHeight(input) {
|
|
38
38
|
if (!input) {
|
|
39
39
|
return 'auto';
|
|
40
40
|
}
|
|
@@ -1,7 +1,24 @@
|
|
|
1
|
+
|
|
1
2
|
._152tze3t{inset-block-start:var(--ds-space-0,0)}
|
|
2
3
|
._18m91wug{overflow-y:auto}
|
|
3
4
|
._1bsbauwl{width:100vw}
|
|
5
|
+
._1dg11kw7>form:only-child{flex-direction:inherit}
|
|
4
6
|
._1e02ze3t{inset-inline-start:var(--ds-space-0,0)}
|
|
7
|
+
._1e0c1txw{display:flex}
|
|
8
|
+
._1mq81kw7>form:only-child{display:inherit}
|
|
9
|
+
._1q1l1bhr{--ds-elevation-surface-current:var(--ds-surface-overlay,#fff)}
|
|
10
|
+
._1tke1kxc{min-height:100vh}
|
|
11
|
+
._2lx21bp4{flex-direction:column}
|
|
5
12
|
._4t3i1kxc{height:100vh}
|
|
13
|
+
._4t3i1osq{height:100%}
|
|
6
14
|
._8am5i4x0{-webkit-overflow-scrolling:touch}
|
|
7
|
-
.
|
|
15
|
+
._bfhk1bhr{background-color:var(--ds-surface-overlay,#fff)}
|
|
16
|
+
._c71lglyw{max-height:none}
|
|
17
|
+
._kqsw1n9t{position:fixed}
|
|
18
|
+
._lcxv1wug{pointer-events:auto}
|
|
19
|
+
._m01u1kw7>form:only-child{max-height:inherit}
|
|
20
|
+
._syazi7uo{color:var(--ds-text,#292a2e)}._128mdkaa:focus-visible{outline-width:var(--ds-border-width-focused,2px)}
|
|
21
|
+
._1ah3dkaa:focus-visible{outline-offset:var(--ds-border-width-focused,2px)}
|
|
22
|
+
._mizu1v1w:focus-visible{outline-color:var(--ds-border-focused,#4688ec)}
|
|
23
|
+
._ra3xnqa1:focus-visible{outline-style:solid}
|
|
24
|
+
@media (min-width:30rem){._bolhzwhf._bolhzwhf{max-height:calc(100vh - 119px)}._epkxfajl{border-radius:var(--ds-radius-small,3px)}._epkxpb1k{border-radius:var(--ds-radius-xlarge,9pt)}._zg7p130s{box-shadow:var(--ds-shadow-overlay,0 8px 9pt #1e1f2126,0 0 1px #1e1f214f)}}
|
|
@@ -4,30 +4,62 @@ import _typeof from "@babel/runtime/helpers/typeof";
|
|
|
4
4
|
import "./modal-wrapper.compiled.css";
|
|
5
5
|
import * as React from 'react';
|
|
6
6
|
import { ax, ix } from "@compiled/react/runtime";
|
|
7
|
-
import { useCallback } from 'react';
|
|
7
|
+
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
8
8
|
import FocusLock from 'react-focus-lock';
|
|
9
9
|
import ScrollLock, { TouchScrollable } from 'react-scrolllock';
|
|
10
10
|
import { usePlatformLeafEventHandler } from '@atlaskit/analytics-next';
|
|
11
11
|
import Blanket from '@atlaskit/blanket';
|
|
12
12
|
import noop from '@atlaskit/ds-lib/noop';
|
|
13
|
+
import useAutoFocus from '@atlaskit/ds-lib/use-auto-focus';
|
|
14
|
+
import { useId } from '@atlaskit/ds-lib/use-id';
|
|
13
15
|
import { Layering } from '@atlaskit/layering';
|
|
14
16
|
import { useNotifyOpenLayerObserver } from '@atlaskit/layering/experimental/open-layer-observer';
|
|
15
17
|
import { Motion } from '@atlaskit/motion';
|
|
18
|
+
import { useExitingPersistence } from '@atlaskit/motion/exiting-persistence';
|
|
16
19
|
import FadeIn from '@atlaskit/motion/fade-in';
|
|
17
20
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
18
21
|
import Portal from '@atlaskit/portal';
|
|
22
|
+
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
|
|
19
23
|
import { layers } from '@atlaskit/theme/constants';
|
|
24
|
+
import { dialogSlideUpAndFade } from '@atlaskit/top-layer/animations';
|
|
25
|
+
import { createCloseEvent } from '@atlaskit/top-layer/create-close-event';
|
|
26
|
+
import { Dialog } from '@atlaskit/top-layer/dialog';
|
|
27
|
+
import { DialogScrollLock } from '@atlaskit/top-layer/dialog-scroll-lock';
|
|
28
|
+
import { ModalContext, ScrollContext } from '../context';
|
|
20
29
|
import useModalStack from '../hooks/use-modal-stack';
|
|
21
30
|
import usePreventProgrammaticScroll from '../hooks/use-prevent-programmatic-scroll';
|
|
22
|
-
import
|
|
31
|
+
import { disableDraggingToCrossOriginIFramesForElement } from '../pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/element';
|
|
32
|
+
import { disableDraggingToCrossOriginIFramesForExternal } from '../pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/external';
|
|
33
|
+
import { disableDraggingToCrossOriginIFramesForTextSelection } from '../pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/text-selection';
|
|
34
|
+
import ModalDialog, { dialogHeight, dialogWidth as getDialogWidth } from './modal-dialog';
|
|
35
|
+
var modalAnimation = dialogSlideUpAndFade();
|
|
23
36
|
var fillScreenStyles = null;
|
|
37
|
+
|
|
38
|
+
// Visual styles for modal content inside native <dialog>.
|
|
39
|
+
// Uses cssMap (not css) to avoid triggering no-nested-styles lint rule.
|
|
40
|
+
|
|
41
|
+
var LOCAL_CURRENT_SURFACE_CSS_VAR = '--ds-elevation-surface-current';
|
|
42
|
+
var topLayerStyles = {
|
|
43
|
+
content: "_1e0c1txw _4t3i1osq _2lx21bp4 _bfhk1bhr _syazi7uo _1q1l1bhr _lcxv1wug _1mq81kw7 _m01u1kw7 _1dg11kw7 _mizu1v1w _1ah3dkaa _ra3xnqa1 _128mdkaa _zg7p130s",
|
|
44
|
+
borderRadius: "_epkxfajl",
|
|
45
|
+
borderRadiusT26: "_epkxpb1k"
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// Scroll-mode styles for the content div.
|
|
49
|
+
// Height overrides use ID-scoped <style> (see dialogPositionStyles) because
|
|
50
|
+
// Compiled atomic classes have specificity (0,1,0) (increaseSpecificity is disabled).
|
|
51
|
+
// The doubled-ID selector (#id#id > div) at (2,0,1) reliably wins.
|
|
52
|
+
// Only non-height properties needing the && boost remain here.
|
|
53
|
+
|
|
54
|
+
var topLayerBodyScrollStyles = null;
|
|
55
|
+
var topLayerViewportScrollStyles = null;
|
|
24
56
|
var allowlistElements = function allowlistElements(element, callback) {
|
|
25
|
-
// Allow focus
|
|
26
|
-
//
|
|
27
|
-
if (document.querySelector('.aui-blanket:not([hidden])')) {
|
|
57
|
+
// Allow focus outside modal when AUI dialog is visible
|
|
58
|
+
// eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- legacy FocusLock allowlist
|
|
59
|
+
if (Boolean(document.querySelector('.aui-blanket:not([hidden])'))) {
|
|
28
60
|
return false;
|
|
29
61
|
}
|
|
30
|
-
//
|
|
62
|
+
// Optional callback to let consumers exclude elements from focus lock
|
|
31
63
|
if (typeof callback === 'function') {
|
|
32
64
|
return callback(element);
|
|
33
65
|
}
|
|
@@ -83,7 +115,7 @@ var InternalModalWrapper = function InternalModalWrapper(props) {
|
|
|
83
115
|
action: 'closed',
|
|
84
116
|
componentName: 'modalDialog',
|
|
85
117
|
packageName: "@atlaskit/modal-dialog",
|
|
86
|
-
packageVersion: "
|
|
118
|
+
packageVersion: "15.0.1"
|
|
87
119
|
});
|
|
88
120
|
var onBlanketClicked = useCallback(function (e) {
|
|
89
121
|
if (shouldCloseOnOverlayClick) {
|
|
@@ -91,20 +123,216 @@ var InternalModalWrapper = function InternalModalWrapper(props) {
|
|
|
91
123
|
}
|
|
92
124
|
}, [shouldCloseOnOverlayClick, onCloseHandler]);
|
|
93
125
|
|
|
94
|
-
//
|
|
126
|
+
// Stable callback to avoid re-renders when focusLockAllowlist is not provided.
|
|
95
127
|
var allowListCallback = useCallback(function (element) {
|
|
96
128
|
return allowlistElements(element, focusLockAllowlist);
|
|
97
129
|
}, [focusLockAllowlist]);
|
|
98
|
-
|
|
130
|
+
|
|
131
|
+
// Called outside the feature-flag branch to keep hook order stable.
|
|
132
|
+
// Legacy path: FadeIn calls onFinish. Top-layer path: called directly.
|
|
133
|
+
var _useExitingPersistenc = useExitingPersistence(),
|
|
134
|
+
isExiting = _useExitingPersistenc.isExiting,
|
|
135
|
+
onExitFinish = _useExitingPersistenc.onFinish;
|
|
136
|
+
|
|
137
|
+
// Prevent background scroll (top-layer path uses DialogScrollLock instead).
|
|
138
|
+
// Safe conditional hook: feature flags are resolved once at startup.
|
|
139
|
+
if (!fg('platform-dst-top-layer')) {
|
|
140
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
141
|
+
usePreventProgrammaticScroll();
|
|
142
|
+
}
|
|
99
143
|
useNotifyOpenLayerObserver({
|
|
100
144
|
type: 'modal',
|
|
101
|
-
//
|
|
145
|
+
// Always open — modal is conditionally rendered when visible.
|
|
102
146
|
isOpen: true,
|
|
103
|
-
//
|
|
104
|
-
// by the OpenLayerObserver. The only current use case is closing layers when resizing the nav layout,
|
|
105
|
-
// which cannot happen while a modal dialog is open.
|
|
147
|
+
// No-op: no current use case for programmatic close via OpenLayerObserver.
|
|
106
148
|
onClose: noop
|
|
107
149
|
});
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Top-layer path (platform-dst-top-layer).
|
|
153
|
+
*
|
|
154
|
+
* Replaces Portal, FocusLock, ScrollLock, Blanket, Positioner, and z-index
|
|
155
|
+
* management with native <dialog> via @atlaskit/top-layer/dialog.
|
|
156
|
+
*
|
|
157
|
+
* Key decisions:
|
|
158
|
+
* - Animation: CSS transitions via @starting-style / allow-discrete.
|
|
159
|
+
* - Close gating: onDialogClose only forwards allowed reasons
|
|
160
|
+
* (see notes/guides/dialog-close-flow.md).
|
|
161
|
+
* - onClose event param: undefined - consumers should use close reason.
|
|
162
|
+
* - Focus restoration: native <dialog> behavior replaces react-focus-lock's
|
|
163
|
+
* returnFocus (see accessibility-criteria.md).
|
|
164
|
+
*/
|
|
165
|
+
if (fg('platform-dst-top-layer')) {
|
|
166
|
+
// Native <dialog> always restores focus on close - no opt-out via shouldReturnFocus.
|
|
167
|
+
var defaultTestId = testId || 'modal-dialog';
|
|
168
|
+
|
|
169
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
170
|
+
var id = useId();
|
|
171
|
+
var titleId = "modal-dialog-title-".concat(id);
|
|
172
|
+
|
|
173
|
+
// Content container ref - used for onOpenComplete/onCloseComplete callbacks.
|
|
174
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
175
|
+
var contentRef = useRef(null);
|
|
176
|
+
|
|
177
|
+
// Cache last content element for onCloseComplete after children unmount
|
|
178
|
+
// (with reduced motion, contentRef clears before onExitFinish fires).
|
|
179
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
180
|
+
var lastContentElRef = useRef(null);
|
|
181
|
+
if (contentRef.current) {
|
|
182
|
+
lastContentElRef.current = contentRef.current;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Native <dialog> ref - needed for ExitingPersistence to call dialog.close().
|
|
186
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
187
|
+
var dialogRef = useRef(null);
|
|
188
|
+
|
|
189
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
190
|
+
var modalDialogContext = useMemo(function () {
|
|
191
|
+
return {
|
|
192
|
+
testId: defaultTestId,
|
|
193
|
+
titleId: titleId,
|
|
194
|
+
onClose: onCloseHandler,
|
|
195
|
+
hasProvidedOnClose: Boolean(providedOnClose),
|
|
196
|
+
isFullScreen: isFullScreen !== null && isFullScreen !== void 0 ? isFullScreen : false
|
|
197
|
+
};
|
|
198
|
+
}, [defaultTestId, titleId, onCloseHandler, providedOnClose, isFullScreen]);
|
|
199
|
+
|
|
200
|
+
// Only forward close when the reason is allowed by props.
|
|
201
|
+
// Passes a synthetic event to satisfy the KeyboardOrMouseEvent contract.
|
|
202
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
203
|
+
var onDialogClose = useCallback(function (_ref) {
|
|
204
|
+
var reason = _ref.reason;
|
|
205
|
+
if (reason === 'escape' && shouldCloseOnEscapePress) {
|
|
206
|
+
onCloseHandler(createCloseEvent({
|
|
207
|
+
reason: reason
|
|
208
|
+
}));
|
|
209
|
+
}
|
|
210
|
+
if (reason === 'overlay-click' && shouldCloseOnOverlayClick) {
|
|
211
|
+
onCloseHandler(createCloseEvent({
|
|
212
|
+
reason: reason
|
|
213
|
+
}));
|
|
214
|
+
}
|
|
215
|
+
}, [onCloseHandler, shouldCloseOnEscapePress, shouldCloseOnOverlayClick]);
|
|
216
|
+
|
|
217
|
+
// ExitingPersistence: isExiting → isOpen={false} → Dialog exit animation →
|
|
218
|
+
// onExitFinish → onCloseComplete + unmount.
|
|
219
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
220
|
+
var handleDialogExitFinish = useCallback(function () {
|
|
221
|
+
var _contentRef$current;
|
|
222
|
+
var el = (_contentRef$current = contentRef.current) !== null && _contentRef$current !== void 0 ? _contentRef$current : lastContentElRef.current;
|
|
223
|
+
if (onCloseComplete && el) {
|
|
224
|
+
onCloseComplete(el);
|
|
225
|
+
}
|
|
226
|
+
lastContentElRef.current = null;
|
|
227
|
+
onExitFinish === null || onExitFinish === void 0 || onExitFinish();
|
|
228
|
+
}, [onExitFinish, onCloseComplete]);
|
|
229
|
+
|
|
230
|
+
// Fire onOpenComplete after mount.
|
|
231
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
232
|
+
useEffect(function () {
|
|
233
|
+
if (onOpenComplete && contentRef.current) {
|
|
234
|
+
onOpenComplete(contentRef.current, true);
|
|
235
|
+
}
|
|
236
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
237
|
+
}, []);
|
|
238
|
+
|
|
239
|
+
// Honor `shouldReturnFocus={ref}` on unmount.
|
|
240
|
+
// Native <dialog>.close() restores focus to the trigger that opened it,
|
|
241
|
+
// but the consumer asked for focus to go to a specific element instead.
|
|
242
|
+
// Run this in an unmount cleanup so it fires after dialog.close()
|
|
243
|
+
// (which fires in the Dialog's effect cleanup).
|
|
244
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
245
|
+
var shouldReturnFocusRef = useRef(shouldReturnFocus);
|
|
246
|
+
shouldReturnFocusRef.current = shouldReturnFocus;
|
|
247
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
248
|
+
useEffect(function () {
|
|
249
|
+
return function () {
|
|
250
|
+
var target = shouldReturnFocusRef.current;
|
|
251
|
+
if (_typeof(target) === 'object' && target.current) {
|
|
252
|
+
target.current.focus();
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
}, []);
|
|
256
|
+
|
|
257
|
+
// Focus a ref-targeted element after mount (when autoFocus is a ref).
|
|
258
|
+
// When true, native <dialog>.showModal() handles focus automatically.
|
|
259
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
260
|
+
useAutoFocus(_typeof(autoFocus) === 'object' ? autoFocus : undefined, _typeof(autoFocus) === 'object');
|
|
261
|
+
|
|
262
|
+
// Chrome cross-origin iframe DnD workaround (crbug.com/362301053)
|
|
263
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
264
|
+
useEffect(function () {
|
|
265
|
+
return combine(disableDraggingToCrossOriginIFramesForElement(), disableDraggingToCrossOriginIFramesForTextSelection(), disableDraggingToCrossOriginIFramesForExternal());
|
|
266
|
+
}, []);
|
|
267
|
+
|
|
268
|
+
// Responsive layout via ID-scoped <style> (same pattern as Dialog's hideBackdrop).
|
|
269
|
+
// ID selector beats Compiled atomic classes without !important and supports @media.
|
|
270
|
+
var namedWidth = getDialogWidth(width !== null && width !== void 0 ? width : 'medium');
|
|
271
|
+
var dialogId = "modal-dialog-".concat(id);
|
|
272
|
+
var escapedDialogId = CSS.escape(dialogId);
|
|
273
|
+
|
|
274
|
+
// Percentage widths need special handling in the top layer.
|
|
275
|
+
// In legacy, the percentage resolved against the Positioner's max-width
|
|
276
|
+
// (100vw - 120px). In the top layer, the <dialog>'s containing block is the
|
|
277
|
+
// viewport (100vw), so a raw percentage would produce a wider modal.
|
|
278
|
+
// Transform e.g. '42%' → 'calc(42 * (100vw - 120px) / 100)' to match legacy.
|
|
279
|
+
var resolvedWidth = namedWidth.endsWith('%') ? "calc(".concat(parseFloat(namedWidth), " * (100vw - 120px) / 100)") : namedWidth;
|
|
280
|
+
var dialogStyle = isFullScreen ? {
|
|
281
|
+
width: '100vw',
|
|
282
|
+
height: '100vh',
|
|
283
|
+
margin: '0'
|
|
284
|
+
} : {
|
|
285
|
+
width: "min(".concat(resolvedWidth, ", 100vw)")
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
// Shift stacked background modals down by space.100 (8px) per level.
|
|
289
|
+
if (stackIndex > 0) {
|
|
290
|
+
dialogStyle['transform'] = "translateY(calc(".concat(stackIndex, "px * ", "var(--ds-space-100, 8px)", "))");
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Mobile: viewport fill. Desktop (≥ 30rem): gutter margins, auto height.
|
|
294
|
+
// Content-div height set via #id > div to beat Compiled's atomic specificity.
|
|
295
|
+
var desktopMargin = shouldScrollInViewport ? '60px auto' : '60px auto auto';
|
|
296
|
+
var resolvedHeight = dialogHeight(height);
|
|
297
|
+
// Body-scroll: specified height or auto. Viewport-scroll: uses min-height.
|
|
298
|
+
var desktopContentHeight = shouldScrollInViewport ? 'auto' : resolvedHeight;
|
|
299
|
+
var desktopContentMinHeight = shouldScrollInViewport ? resolvedHeight : 'auto';
|
|
300
|
+
// Viewport-scroll: the legacy Positioner was a fixed 100vh container that
|
|
301
|
+
// scrolled internally, so the modal section could fill (100vh - 60px top gutter).
|
|
302
|
+
// In the top layer the <dialog> sizes to content with height:auto, so we need
|
|
303
|
+
// an explicit min-height to ensure the dialog stretches to the same visible area.
|
|
304
|
+
var desktopDialogMinHeight = shouldScrollInViewport ? 'min-height:calc(100vh - 60px);' : '';
|
|
305
|
+
// Doubled-ID selector (#id#id > div) at specificity (2,0,1) beats
|
|
306
|
+
// Compiled atomic classes at (0,1,0) (increaseSpecificity is disabled).
|
|
307
|
+
var dialogPositionStyles = isFullScreen ? ''
|
|
308
|
+
// Mobile: edge-to-edge. Desktop (≥ 30rem): 60px gutters, max-width.
|
|
309
|
+
: "#".concat(escapedDialogId, "#").concat(escapedDialogId, "{margin:0;height:100vh}#").concat(escapedDialogId, "#").concat(escapedDialogId, ">div{height:100%}@media(min-width:30rem){#").concat(escapedDialogId, "#").concat(escapedDialogId, "{margin:").concat(desktopMargin, ";height:auto;").concat(desktopDialogMinHeight, "max-width:calc(100vw - 120px)}#").concat(escapedDialogId, "#").concat(escapedDialogId, ">div{height:").concat(desktopContentHeight, ";min-height:").concat(desktopContentMinHeight, "}}");
|
|
310
|
+
return /*#__PURE__*/React.createElement(Dialog, {
|
|
311
|
+
ref: dialogRef,
|
|
312
|
+
id: dialogId,
|
|
313
|
+
onClose: onDialogClose,
|
|
314
|
+
onExitFinish: handleDialogExitFinish,
|
|
315
|
+
animate: isFullScreen ? false : modalAnimation,
|
|
316
|
+
isOpen: !isExiting,
|
|
317
|
+
shouldHideBackdrop: stackIndex > 0 || Boolean(isBlanketHidden),
|
|
318
|
+
label: label,
|
|
319
|
+
labelledBy: label ? undefined : titleId,
|
|
320
|
+
testId: defaultTestId
|
|
321
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
|
|
322
|
+
,
|
|
323
|
+
style: dialogStyle
|
|
324
|
+
}, /*#__PURE__*/React.createElement(DialogScrollLock, null), dialogPositionStyles &&
|
|
325
|
+
/*#__PURE__*/
|
|
326
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-global-styles
|
|
327
|
+
React.createElement("style", null, dialogPositionStyles), /*#__PURE__*/React.createElement("div", {
|
|
328
|
+
ref: contentRef,
|
|
329
|
+
className: ax([topLayerStyles.content, !isFullScreen && topLayerStyles.borderRadius, !isFullScreen && fg('platform-dst-shape-theme-default') && topLayerStyles.borderRadiusT26, !isFullScreen && !shouldScrollInViewport && "_bolhzwhf", !isFullScreen && shouldScrollInViewport && "_1tke1kxc _c71lglyw"])
|
|
330
|
+
}, /*#__PURE__*/React.createElement(ModalContext.Provider, {
|
|
331
|
+
value: modalDialogContext
|
|
332
|
+
}, /*#__PURE__*/React.createElement(ScrollContext.Provider, {
|
|
333
|
+
value: shouldScrollInViewport
|
|
334
|
+
}, children))));
|
|
335
|
+
}
|
|
108
336
|
var modalDialogWithBlanket = /*#__PURE__*/React.createElement(Blanket, {
|
|
109
337
|
isTinted: !isBlanketHidden,
|
|
110
338
|
onBlanketClicked: onBlanketClicked,
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
* @jsxRuntime classic
|
|
3
3
|
* @jsx jsx
|
|
4
4
|
*/
|
|
5
|
+
import type { ModalDialogProps } from '../../types';
|
|
5
6
|
import type { InternalModalDialogProps } from '../types';
|
|
7
|
+
export declare const dialogWidth: (input?: ModalDialogProps["width"]) => string;
|
|
8
|
+
export declare const dialogHeight: (input?: ModalDialogProps["height"]) => string;
|
|
6
9
|
declare const ModalDialog: (props: InternalModalDialogProps) => JSX.Element;
|
|
7
10
|
export default ModalDialog;
|