@oxyhq/bloom 0.16.1 → 0.16.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/lib/commonjs/dialog/Dialog.js +7 -7
- package/lib/commonjs/dialog/Dialog.js.map +1 -1
- package/lib/commonjs/dialog/Dialog.web.js +9 -5
- package/lib/commonjs/dialog/Dialog.web.js.map +1 -1
- package/lib/commonjs/dialog/DialogBottomSheet.js +18 -7
- package/lib/commonjs/dialog/DialogBottomSheet.js.map +1 -1
- package/lib/commonjs/dialog/placement.js +12 -1
- package/lib/commonjs/dialog/placement.js.map +1 -1
- package/lib/module/dialog/Dialog.js +8 -8
- package/lib/module/dialog/Dialog.js.map +1 -1
- package/lib/module/dialog/Dialog.web.js +10 -6
- package/lib/module/dialog/Dialog.web.js.map +1 -1
- package/lib/module/dialog/DialogBottomSheet.js +19 -8
- package/lib/module/dialog/DialogBottomSheet.js.map +1 -1
- package/lib/module/dialog/placement.js +11 -0
- package/lib/module/dialog/placement.js.map +1 -1
- package/lib/typescript/commonjs/dialog/Dialog.d.ts.map +1 -1
- package/lib/typescript/commonjs/dialog/Dialog.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/dialog/DialogBottomSheet.d.ts +2 -2
- package/lib/typescript/commonjs/dialog/DialogBottomSheet.d.ts.map +1 -1
- package/lib/typescript/commonjs/dialog/placement.d.ts +10 -0
- package/lib/typescript/commonjs/dialog/placement.d.ts.map +1 -1
- package/lib/typescript/commonjs/dialog/types.d.ts +12 -0
- package/lib/typescript/commonjs/dialog/types.d.ts.map +1 -1
- package/lib/typescript/module/dialog/Dialog.d.ts.map +1 -1
- package/lib/typescript/module/dialog/Dialog.web.d.ts.map +1 -1
- package/lib/typescript/module/dialog/DialogBottomSheet.d.ts +2 -2
- package/lib/typescript/module/dialog/DialogBottomSheet.d.ts.map +1 -1
- package/lib/typescript/module/dialog/placement.d.ts +10 -0
- package/lib/typescript/module/dialog/placement.d.ts.map +1 -1
- package/lib/typescript/module/dialog/types.d.ts +12 -0
- package/lib/typescript/module/dialog/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/DialogBottomSheet.test.tsx +129 -0
- package/src/dialog/Dialog.tsx +7 -5
- package/src/dialog/Dialog.web.tsx +10 -5
- package/src/dialog/DialogBottomSheet.tsx +22 -7
- package/src/dialog/placement.ts +11 -0
- package/src/dialog/types.ts +12 -0
|
@@ -5,6 +5,34 @@ import { act, fireEvent, render } from '@testing-library/react-native';
|
|
|
5
5
|
import { Dialog, useDialogControl } from '../dialog';
|
|
6
6
|
import { BloomThemeProvider } from '../theme/BloomThemeProvider';
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Minimal shape of a `react-test-renderer` JSON node — enough to walk the tree
|
|
10
|
+
* by host `type` string without depending on `@types/react-test-renderer`.
|
|
11
|
+
*/
|
|
12
|
+
type RenderedNode = {
|
|
13
|
+
type: string;
|
|
14
|
+
children: Array<RenderedNode | string> | null;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/** Count host nodes of a given `type` in a rendered `toJSON()` tree. */
|
|
18
|
+
function countNodesByType(
|
|
19
|
+
tree: RenderedNode | RenderedNode[] | null,
|
|
20
|
+
type: string,
|
|
21
|
+
): number {
|
|
22
|
+
if (tree === null) return 0;
|
|
23
|
+
const roots = Array.isArray(tree) ? tree : [tree];
|
|
24
|
+
let count = 0;
|
|
25
|
+
for (const node of roots) {
|
|
26
|
+
if (node.type === type) count += 1;
|
|
27
|
+
if (node.children) {
|
|
28
|
+
for (const child of node.children) {
|
|
29
|
+
if (typeof child !== 'string') count += countNodesByType(child, type);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return count;
|
|
34
|
+
}
|
|
35
|
+
|
|
8
36
|
/**
|
|
9
37
|
* The Dialog `bottom` placement must delegate to the shared cross-platform
|
|
10
38
|
* `BottomSheet` (via `DialogBottomSheet`) — the SAME surface native and web use
|
|
@@ -127,4 +155,105 @@ describe('Dialog bottom placement delegates to BottomSheet', () => {
|
|
|
127
155
|
expect(flattened.backgroundColor).toBe('rebeccapurple');
|
|
128
156
|
expect(flattened.paddingTop).toBe(7);
|
|
129
157
|
});
|
|
158
|
+
|
|
159
|
+
it('applies the default 20px content padding when contentPadding is omitted', () => {
|
|
160
|
+
let control: ReturnType<typeof useDialogControl> | undefined;
|
|
161
|
+
const { getByTestId } = renderWithTheme(
|
|
162
|
+
<Harness>
|
|
163
|
+
{(c) => {
|
|
164
|
+
control = c;
|
|
165
|
+
return (
|
|
166
|
+
<Dialog control={c} placement="bottom" testID="default-pad">
|
|
167
|
+
<Text>Body</Text>
|
|
168
|
+
</Dialog>
|
|
169
|
+
);
|
|
170
|
+
}}
|
|
171
|
+
</Harness>,
|
|
172
|
+
);
|
|
173
|
+
act(() => {
|
|
174
|
+
control?.open();
|
|
175
|
+
});
|
|
176
|
+
const content = getByTestId('default-pad');
|
|
177
|
+
const flattened = Array.isArray(content.props.style)
|
|
178
|
+
? Object.assign({}, ...content.props.style.filter(Boolean))
|
|
179
|
+
: content.props.style;
|
|
180
|
+
// Omitting `contentPadding` keeps the legacy 20px chrome padding.
|
|
181
|
+
expect(flattened.padding).toBe(20);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('removes the body padding when contentPadding={0} (host owns its insets)', () => {
|
|
185
|
+
let control: ReturnType<typeof useDialogControl> | undefined;
|
|
186
|
+
const { getByTestId } = renderWithTheme(
|
|
187
|
+
<Harness>
|
|
188
|
+
{(c) => {
|
|
189
|
+
control = c;
|
|
190
|
+
return (
|
|
191
|
+
<Dialog control={c} placement="bottom" testID="flush-pad" contentPadding={0}>
|
|
192
|
+
<Text>Flush body</Text>
|
|
193
|
+
</Dialog>
|
|
194
|
+
);
|
|
195
|
+
}}
|
|
196
|
+
</Harness>,
|
|
197
|
+
);
|
|
198
|
+
act(() => {
|
|
199
|
+
control?.open();
|
|
200
|
+
});
|
|
201
|
+
const content = getByTestId('flush-pad');
|
|
202
|
+
const flattened = Array.isArray(content.props.style)
|
|
203
|
+
? Object.assign({}, ...content.props.style.filter(Boolean))
|
|
204
|
+
: content.props.style;
|
|
205
|
+
// `contentPadding={0}` yields flush content the host pads itself.
|
|
206
|
+
expect(flattened.padding).toBe(0);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('does NOT wrap pure custom children in a second scroll container (no scroll-in-scroll)', () => {
|
|
210
|
+
let control: ReturnType<typeof useDialogControl> | undefined;
|
|
211
|
+
const result = renderWithTheme(
|
|
212
|
+
<Harness>
|
|
213
|
+
{(c) => {
|
|
214
|
+
control = c;
|
|
215
|
+
return (
|
|
216
|
+
<Dialog control={c} placement="bottom">
|
|
217
|
+
<Text>Custom children own their own scrolling</Text>
|
|
218
|
+
</Dialog>
|
|
219
|
+
);
|
|
220
|
+
}}
|
|
221
|
+
</Harness>,
|
|
222
|
+
);
|
|
223
|
+
act(() => {
|
|
224
|
+
control?.open();
|
|
225
|
+
});
|
|
226
|
+
// Pure custom children → DialogBottomSheet passes `scrollable={false}` to
|
|
227
|
+
// BottomSheet, so the sheet does NOT add its internal ScrollView. A child
|
|
228
|
+
// that contains its own scroller is then the ONLY scroll container.
|
|
229
|
+
const tree: RenderedNode | RenderedNode[] | null = result.toJSON();
|
|
230
|
+
expect(countNodesByType(tree, 'Animated.ScrollView')).toBe(0);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('keeps the internal scrollable body for declarative dialogs (title/description/actions)', () => {
|
|
234
|
+
let control: ReturnType<typeof useDialogControl> | undefined;
|
|
235
|
+
const result = renderWithTheme(
|
|
236
|
+
<Harness>
|
|
237
|
+
{(c) => {
|
|
238
|
+
control = c;
|
|
239
|
+
return (
|
|
240
|
+
<Dialog
|
|
241
|
+
control={c}
|
|
242
|
+
placement="bottom"
|
|
243
|
+
title="Confirm"
|
|
244
|
+
description="Short declarative body."
|
|
245
|
+
actions={[{ label: 'OK' }]}
|
|
246
|
+
/>
|
|
247
|
+
);
|
|
248
|
+
}}
|
|
249
|
+
</Harness>,
|
|
250
|
+
);
|
|
251
|
+
act(() => {
|
|
252
|
+
control?.open();
|
|
253
|
+
});
|
|
254
|
+
// Declarative chrome → the default scrollable body is retained, so a long
|
|
255
|
+
// title/description list still scrolls gracefully on a small viewport.
|
|
256
|
+
const tree: RenderedNode | RenderedNode[] | null = result.toJSON();
|
|
257
|
+
expect(countNodesByType(tree, 'Animated.ScrollView')).toBe(1);
|
|
258
|
+
});
|
|
130
259
|
});
|
package/src/dialog/Dialog.tsx
CHANGED
|
@@ -32,6 +32,7 @@ import { DialogBody } from './DialogContent';
|
|
|
32
32
|
import { DialogBottomSheet } from './DialogBottomSheet';
|
|
33
33
|
import {
|
|
34
34
|
ANIMATION_DURATION,
|
|
35
|
+
DEFAULT_DIALOG_CONTENT_PADDING,
|
|
35
36
|
DEFAULT_SIDE_WIDTH,
|
|
36
37
|
DIALOG_SHEET_BACKDROP_TESTID,
|
|
37
38
|
PANEL_RADIUS,
|
|
@@ -106,6 +107,7 @@ function CenteredOrSideDialog({
|
|
|
106
107
|
width = DEFAULT_SIDE_WIDTH,
|
|
107
108
|
inset,
|
|
108
109
|
dismissOnBackdrop = true,
|
|
110
|
+
contentPadding = DEFAULT_DIALOG_CONTENT_PADDING,
|
|
109
111
|
style,
|
|
110
112
|
panelStyle,
|
|
111
113
|
panelClassName,
|
|
@@ -242,6 +244,7 @@ function CenteredOrSideDialog({
|
|
|
242
244
|
width={width}
|
|
243
245
|
inset={inset}
|
|
244
246
|
dismissOnBackdrop={dismissOnBackdrop}
|
|
247
|
+
contentPadding={contentPadding}
|
|
245
248
|
testID={testID}
|
|
246
249
|
label={label}
|
|
247
250
|
title={title}
|
|
@@ -283,7 +286,7 @@ function CenteredOrSideDialog({
|
|
|
283
286
|
// Detached BottomSheet already adds `marginBottom: insets.bottom + 16`
|
|
284
287
|
// to the sheet container — the floating card sits ABOVE the
|
|
285
288
|
// system gesture bar, so we don't add `insets.bottom` here.
|
|
286
|
-
{
|
|
289
|
+
{ padding: contentPadding },
|
|
287
290
|
{ backgroundColor: theme.colors.background },
|
|
288
291
|
style,
|
|
289
292
|
panelStyle,
|
|
@@ -311,6 +314,7 @@ function SideSheet({
|
|
|
311
314
|
width,
|
|
312
315
|
inset,
|
|
313
316
|
dismissOnBackdrop,
|
|
317
|
+
contentPadding,
|
|
314
318
|
testID,
|
|
315
319
|
label,
|
|
316
320
|
title,
|
|
@@ -330,6 +334,7 @@ function SideSheet({
|
|
|
330
334
|
width: number;
|
|
331
335
|
inset?: DialogInset;
|
|
332
336
|
dismissOnBackdrop: boolean;
|
|
337
|
+
contentPadding: number;
|
|
333
338
|
testID?: string;
|
|
334
339
|
label?: string;
|
|
335
340
|
title?: string;
|
|
@@ -461,7 +466,7 @@ function SideSheet({
|
|
|
461
466
|
]}
|
|
462
467
|
pointerEvents="auto"
|
|
463
468
|
>
|
|
464
|
-
<View style={
|
|
469
|
+
<View style={{ padding: contentPadding }}>{children}</View>
|
|
465
470
|
</Animated.View>
|
|
466
471
|
</View>
|
|
467
472
|
);
|
|
@@ -484,9 +489,6 @@ const sideStyles = StyleSheet.create({
|
|
|
484
489
|
shadowOffset: { width: 0, height: 8 },
|
|
485
490
|
elevation: 12,
|
|
486
491
|
},
|
|
487
|
-
body: {
|
|
488
|
-
padding: 20,
|
|
489
|
-
},
|
|
490
492
|
});
|
|
491
493
|
|
|
492
494
|
/**
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
ANIMATION_DURATION,
|
|
28
28
|
CENTER_FADE_OUT_DURATION,
|
|
29
29
|
DEFAULT_CENTER_MAX_WIDTH,
|
|
30
|
+
DEFAULT_DIALOG_CONTENT_PADDING,
|
|
30
31
|
DEFAULT_SIDE_WIDTH,
|
|
31
32
|
DIALOG_SHEET_BACKDROP_TESTID,
|
|
32
33
|
EASE_OUT,
|
|
@@ -106,6 +107,7 @@ function CenterOrSideDialog({
|
|
|
106
107
|
maxWidth = DEFAULT_CENTER_MAX_WIDTH,
|
|
107
108
|
inset,
|
|
108
109
|
dismissOnBackdrop = true,
|
|
110
|
+
contentPadding = DEFAULT_DIALOG_CONTENT_PADDING,
|
|
109
111
|
style,
|
|
110
112
|
panelStyle,
|
|
111
113
|
panelClassName,
|
|
@@ -260,6 +262,7 @@ function CenterOrSideDialog({
|
|
|
260
262
|
actions={actions}
|
|
261
263
|
style={style}
|
|
262
264
|
maxWidth={maxWidth}
|
|
265
|
+
contentPadding={contentPadding}
|
|
263
266
|
isClosing={isClosing}
|
|
264
267
|
>
|
|
265
268
|
{children}
|
|
@@ -287,6 +290,7 @@ function CenterOrSideDialog({
|
|
|
287
290
|
width={width}
|
|
288
291
|
inset={inset}
|
|
289
292
|
dismissOnBackdrop={dismissOnBackdrop}
|
|
293
|
+
contentPadding={contentPadding}
|
|
290
294
|
onDismiss={close}
|
|
291
295
|
panelStyle={panelStyle}
|
|
292
296
|
panelClassName={panelClassName}
|
|
@@ -310,6 +314,7 @@ function DialogPanel({
|
|
|
310
314
|
actions,
|
|
311
315
|
style,
|
|
312
316
|
maxWidth,
|
|
317
|
+
contentPadding,
|
|
313
318
|
isClosing,
|
|
314
319
|
children,
|
|
315
320
|
}: {
|
|
@@ -320,6 +325,7 @@ function DialogPanel({
|
|
|
320
325
|
actions?: DialogAction[];
|
|
321
326
|
style?: DialogProps['style'];
|
|
322
327
|
maxWidth: number;
|
|
328
|
+
contentPadding: number;
|
|
323
329
|
isClosing: boolean;
|
|
324
330
|
children?: React.ReactNode;
|
|
325
331
|
}) {
|
|
@@ -350,7 +356,7 @@ function DialogPanel({
|
|
|
350
356
|
shadowOpacity: theme.isDark ? 0.4 : 0.1,
|
|
351
357
|
shadowRadius: 30,
|
|
352
358
|
shadowOffset: { width: 0, height: 4 },
|
|
353
|
-
padding:
|
|
359
|
+
padding: contentPadding,
|
|
354
360
|
zIndex: dialogZIndex.surface,
|
|
355
361
|
},
|
|
356
362
|
isClosing
|
|
@@ -394,6 +400,7 @@ function SheetSurface({
|
|
|
394
400
|
width,
|
|
395
401
|
inset,
|
|
396
402
|
dismissOnBackdrop,
|
|
403
|
+
contentPadding,
|
|
397
404
|
onDismiss,
|
|
398
405
|
panelStyle,
|
|
399
406
|
panelClassName,
|
|
@@ -412,6 +419,7 @@ function SheetSurface({
|
|
|
412
419
|
width: number;
|
|
413
420
|
inset?: DialogInset;
|
|
414
421
|
dismissOnBackdrop: boolean;
|
|
422
|
+
contentPadding: number;
|
|
415
423
|
onDismiss: () => void;
|
|
416
424
|
panelStyle?: StyleProp<ViewStyle>;
|
|
417
425
|
panelClassName?: string;
|
|
@@ -528,7 +536,7 @@ function SheetSurface({
|
|
|
528
536
|
]}
|
|
529
537
|
pointerEvents="auto"
|
|
530
538
|
>
|
|
531
|
-
<View style={
|
|
539
|
+
<View style={{ padding: contentPadding }}>
|
|
532
540
|
<DialogBody
|
|
533
541
|
titleId={titleId}
|
|
534
542
|
descriptionId={descriptionId}
|
|
@@ -641,9 +649,6 @@ const sheetStyles = {
|
|
|
641
649
|
shadowOffset: { width: 0, height: 8 },
|
|
642
650
|
zIndex: dialogZIndex.surface,
|
|
643
651
|
} as ViewStyle,
|
|
644
|
-
body: {
|
|
645
|
-
padding: 20,
|
|
646
|
-
} as ViewStyle,
|
|
647
652
|
};
|
|
648
653
|
|
|
649
654
|
/**
|
|
@@ -13,18 +13,13 @@ import { useTheme } from '../theme/use-theme';
|
|
|
13
13
|
import { Context } from './context';
|
|
14
14
|
import { DialogBody } from './DialogContent';
|
|
15
15
|
import {
|
|
16
|
+
DEFAULT_DIALOG_CONTENT_PADDING,
|
|
16
17
|
DEFAULT_MAX_HEIGHT_RATIO,
|
|
17
18
|
PANEL_RADIUS,
|
|
18
19
|
SHEET_BACKDROP_OPACITY,
|
|
19
20
|
} from './placement';
|
|
20
21
|
import type { DialogControlProps, DialogProps } from './types';
|
|
21
22
|
|
|
22
|
-
/**
|
|
23
|
-
* Padding of the bottom-sheet content container (px). Matches the side-sheet
|
|
24
|
-
* and centered-panel body padding so every placement reads identically.
|
|
25
|
-
*/
|
|
26
|
-
const SHEET_CONTENT_PADDING = 20;
|
|
27
|
-
|
|
28
23
|
/**
|
|
29
24
|
* Shared `BottomSheet`-backed surface for the `bottom` placement, used by BOTH
|
|
30
25
|
* `Dialog.tsx` (native) and `Dialog.web.tsx` (web). `BottomSheet` is itself a
|
|
@@ -56,6 +51,7 @@ export function DialogBottomSheet({
|
|
|
56
51
|
maxHeightRatio = DEFAULT_MAX_HEIGHT_RATIO,
|
|
57
52
|
showHandle = true,
|
|
58
53
|
dismissOnBackdrop = true,
|
|
54
|
+
contentPadding = DEFAULT_DIALOG_CONTENT_PADDING,
|
|
59
55
|
style,
|
|
60
56
|
panelStyle,
|
|
61
57
|
panelClassName,
|
|
@@ -164,6 +160,21 @@ export function DialogBottomSheet({
|
|
|
164
160
|
];
|
|
165
161
|
}, [theme.colors.background, maxHeightRatio, panelStyle]);
|
|
166
162
|
|
|
163
|
+
// Does this dialog render bloom's declarative chrome (title / description /
|
|
164
|
+
// actions), or is it pure custom `children`? Pure custom children own their
|
|
165
|
+
// own layout and scrolling, so we render them through a NON-scrollable
|
|
166
|
+
// BottomSheet body — otherwise the sheet's internal ScrollView would wrap a
|
|
167
|
+
// child that already contains its own scroller, producing a scroll-in-scroll
|
|
168
|
+
// (double scroll container). Declarative dialogs are short and keep the
|
|
169
|
+
// sheet's default scrollable body so they degrade gracefully on small
|
|
170
|
+
// viewports. This only changes what `DialogBottomSheet` passes to
|
|
171
|
+
// `BottomSheet`; the standalone `BottomSheet` API and its `scrollable` default
|
|
172
|
+
// are unchanged for direct consumers.
|
|
173
|
+
const hasDeclarativeChrome =
|
|
174
|
+
title !== undefined ||
|
|
175
|
+
description !== undefined ||
|
|
176
|
+
(actions !== undefined && actions.length > 0);
|
|
177
|
+
|
|
167
178
|
return (
|
|
168
179
|
<BottomSheet
|
|
169
180
|
ref={ref}
|
|
@@ -171,6 +182,9 @@ export function DialogBottomSheet({
|
|
|
171
182
|
onDismissAttempt={onDismissAttempt}
|
|
172
183
|
enablePanDownToClose
|
|
173
184
|
showHandle={showHandle}
|
|
185
|
+
// Pure custom children own scrolling → opt OUT of BottomSheet's internal
|
|
186
|
+
// ScrollView so there is exactly ONE scroll container (no scroll-in-scroll).
|
|
187
|
+
scrollable={hasDeclarativeChrome}
|
|
174
188
|
// Stronger dim than a lone sheet so an underlying sheet's handle/content
|
|
175
189
|
// doesn't bleed through when a Dialog is stacked over one.
|
|
176
190
|
backdropOpacity={SHEET_BACKDROP_OPACITY + 0.3}
|
|
@@ -185,7 +199,7 @@ export function DialogBottomSheet({
|
|
|
185
199
|
{...(containerClassName ? ({ className: containerClassName } as Record<string, string>) : {})}
|
|
186
200
|
{...(panelClassName ? ({ className: panelClassName } as Record<string, string>) : {})}
|
|
187
201
|
style={[
|
|
188
|
-
{ padding:
|
|
202
|
+
{ padding: contentPadding },
|
|
189
203
|
// `containerStyle` carries the host's CSS-var theme scope; it wraps
|
|
190
204
|
// the content subtree so descendants read the scoped palette.
|
|
191
205
|
containerStyle,
|
|
@@ -225,6 +239,7 @@ export type DialogBottomSheetProps = Pick<
|
|
|
225
239
|
| 'maxHeightRatio'
|
|
226
240
|
| 'showHandle'
|
|
227
241
|
| 'dismissOnBackdrop'
|
|
242
|
+
| 'contentPadding'
|
|
228
243
|
| 'style'
|
|
229
244
|
| 'panelStyle'
|
|
230
245
|
| 'panelClassName'
|
package/src/dialog/placement.ts
CHANGED
|
@@ -60,6 +60,17 @@ export const DEFAULT_MAX_HEIGHT_RATIO = 0.9;
|
|
|
60
60
|
/** Corner radius shared by the side-sheet panel and the bottom-sheet top. */
|
|
61
61
|
export const PANEL_RADIUS = 20;
|
|
62
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Default inner padding (px) of the dialog content container, applied uniformly
|
|
65
|
+
* across every placement (centered panel, side-sheet body, bottom-sheet body)
|
|
66
|
+
* so the chrome reads identically regardless of which surface resolves. This is
|
|
67
|
+
* the legacy value — omitting the `contentPadding` prop keeps 20px everywhere,
|
|
68
|
+
* byte-for-byte unchanged. A host that owns its own insets (e.g. custom
|
|
69
|
+
* `children` that already manage padding) can override it via
|
|
70
|
+
* `Dialog`'s `contentPadding` prop (e.g. `contentPadding={0}`).
|
|
71
|
+
*/
|
|
72
|
+
export const DEFAULT_DIALOG_CONTENT_PADDING = 20;
|
|
73
|
+
|
|
63
74
|
/** Open/close transition duration (ms). ~280ms ease-out reads smooth. */
|
|
64
75
|
export const ANIMATION_DURATION = 280;
|
|
65
76
|
|
package/src/dialog/types.ts
CHANGED
|
@@ -134,6 +134,18 @@ export type DialogProps = React.PropsWithChildren<{
|
|
|
134
134
|
inset?: DialogInset;
|
|
135
135
|
/** Whether to render the drag handle in bottom-sheet mode. Defaults to `true`. */
|
|
136
136
|
showHandle?: boolean;
|
|
137
|
+
/**
|
|
138
|
+
* Inner padding (px) of the dialog content container, applied uniformly across
|
|
139
|
+
* every placement (centered panel, side-sheet body, bottom-sheet body).
|
|
140
|
+
* Defaults to `20`.
|
|
141
|
+
*
|
|
142
|
+
* The default chrome padding is correct for the declarative
|
|
143
|
+
* `title`/`description`/`actions` layout, but a host passing pure custom
|
|
144
|
+
* `children` that already own their insets can set `contentPadding={0}` to
|
|
145
|
+
* render flush content and manage padding itself. Omitting the prop keeps the
|
|
146
|
+
* 20px default on every surface.
|
|
147
|
+
*/
|
|
148
|
+
contentPadding?: number;
|
|
137
149
|
/** Whether tapping the backdrop dismisses the dialog. Defaults to `true`. */
|
|
138
150
|
dismissOnBackdrop?: boolean;
|
|
139
151
|
/**
|