@oxyhq/bloom 0.48.0 → 0.49.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/lib/commonjs/bottom-sheet/BottomSheetBase.js +3 -1
- package/lib/commonjs/bottom-sheet/BottomSheetBase.js.map +1 -1
- package/lib/commonjs/dialog/Dialog.js +35 -4
- package/lib/commonjs/dialog/Dialog.js.map +1 -1
- package/lib/commonjs/dialog/Dialog.web.js +48 -14
- package/lib/commonjs/dialog/Dialog.web.js.map +1 -1
- package/lib/commonjs/dialog/DialogBottomSheet.js +30 -5
- package/lib/commonjs/dialog/DialogBottomSheet.js.map +1 -1
- package/lib/commonjs/dialog/DialogHeader.js +12 -6
- package/lib/commonjs/dialog/DialogHeader.js.map +1 -1
- package/lib/commonjs/dialog/DialogMorph.js +458 -0
- package/lib/commonjs/dialog/DialogMorph.js.map +1 -0
- package/lib/commonjs/dialog/index.js +7 -0
- package/lib/commonjs/dialog/index.js.map +1 -1
- package/lib/commonjs/dialog/index.web.js +7 -0
- package/lib/commonjs/dialog/index.web.js.map +1 -1
- package/lib/commonjs/settings-list/SettingsList.js +1 -1
- package/lib/commonjs/surfaces/SurfaceHost.js +1 -0
- package/lib/commonjs/surfaces/SurfaceHost.js.map +1 -1
- package/lib/module/bottom-sheet/BottomSheetBase.js +3 -1
- package/lib/module/bottom-sheet/BottomSheetBase.js.map +1 -1
- package/lib/module/dialog/Dialog.js +35 -4
- package/lib/module/dialog/Dialog.js.map +1 -1
- package/lib/module/dialog/Dialog.web.js +48 -15
- package/lib/module/dialog/Dialog.web.js.map +1 -1
- package/lib/module/dialog/DialogBottomSheet.js +31 -6
- package/lib/module/dialog/DialogBottomSheet.js.map +1 -1
- package/lib/module/dialog/DialogHeader.js +12 -6
- package/lib/module/dialog/DialogHeader.js.map +1 -1
- package/lib/module/dialog/DialogMorph.js +451 -0
- package/lib/module/dialog/DialogMorph.js.map +1 -0
- package/lib/module/dialog/index.js +1 -0
- package/lib/module/dialog/index.js.map +1 -1
- package/lib/module/dialog/index.web.js +1 -0
- package/lib/module/dialog/index.web.js.map +1 -1
- package/lib/module/settings-list/SettingsList.js +1 -1
- package/lib/module/surfaces/SurfaceHost.js +1 -0
- package/lib/module/surfaces/SurfaceHost.js.map +1 -1
- package/lib/typescript/commonjs/bottom-sheet/BottomSheetBase.d.ts +10 -3
- package/lib/typescript/commonjs/bottom-sheet/BottomSheetBase.d.ts.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/DialogHeader.d.ts.map +1 -1
- package/lib/typescript/commonjs/dialog/DialogMorph.d.ts +150 -0
- package/lib/typescript/commonjs/dialog/DialogMorph.d.ts.map +1 -0
- package/lib/typescript/commonjs/dialog/index.d.ts +2 -0
- package/lib/typescript/commonjs/dialog/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/dialog/index.web.d.ts +2 -0
- package/lib/typescript/commonjs/dialog/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/dialog/types.d.ts +30 -0
- package/lib/typescript/commonjs/dialog/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/surfaces/SurfaceHost.d.ts.map +1 -1
- package/lib/typescript/commonjs/surfaces/types.d.ts +9 -0
- package/lib/typescript/commonjs/surfaces/types.d.ts.map +1 -1
- package/lib/typescript/module/bottom-sheet/BottomSheetBase.d.ts +10 -3
- package/lib/typescript/module/bottom-sheet/BottomSheetBase.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/DialogHeader.d.ts.map +1 -1
- package/lib/typescript/module/dialog/DialogMorph.d.ts +150 -0
- package/lib/typescript/module/dialog/DialogMorph.d.ts.map +1 -0
- package/lib/typescript/module/dialog/index.d.ts +2 -0
- package/lib/typescript/module/dialog/index.d.ts.map +1 -1
- package/lib/typescript/module/dialog/index.web.d.ts +2 -0
- package/lib/typescript/module/dialog/index.web.d.ts.map +1 -1
- package/lib/typescript/module/dialog/types.d.ts +30 -0
- package/lib/typescript/module/dialog/types.d.ts.map +1 -1
- package/lib/typescript/module/surfaces/SurfaceHost.d.ts.map +1 -1
- package/lib/typescript/module/surfaces/types.d.ts +9 -0
- package/lib/typescript/module/surfaces/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/DialogMorph.test.tsx +230 -0
- package/src/bottom-sheet/BottomSheetBase.tsx +15 -2
- package/src/dialog/Dialog.tsx +43 -11
- package/src/dialog/Dialog.web.tsx +40 -10
- package/src/dialog/DialogBottomSheet.tsx +37 -6
- package/src/dialog/DialogHeader.tsx +14 -5
- package/src/dialog/DialogMorph.tsx +576 -0
- package/src/dialog/index.ts +2 -0
- package/src/dialog/index.web.ts +2 -0
- package/src/dialog/types.ts +30 -0
- package/src/settings-list/SettingsList.tsx +1 -1
- package/src/surfaces/SurfaceHost.tsx +1 -0
- package/src/surfaces/types.ts +9 -0
|
@@ -6,7 +6,13 @@ import React, {
|
|
|
6
6
|
useMemo,
|
|
7
7
|
useRef,
|
|
8
8
|
} from 'react';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
useWindowDimensions,
|
|
11
|
+
View,
|
|
12
|
+
type StyleProp,
|
|
13
|
+
type ViewStyle,
|
|
14
|
+
} from 'react-native';
|
|
15
|
+
import { type AnimatedStyle } from 'react-native-reanimated';
|
|
10
16
|
|
|
11
17
|
import { BottomSheet, type BottomSheetRef } from '../bottom-sheet';
|
|
12
18
|
import { useTheme } from '../theme/use-theme';
|
|
@@ -19,6 +25,7 @@ import {
|
|
|
19
25
|
DialogNavHeader,
|
|
20
26
|
useDialogHeaderController,
|
|
21
27
|
} from './DialogHeader';
|
|
28
|
+
import { DialogMorphContent, useDialogMorph } from './DialogMorph';
|
|
22
29
|
import {
|
|
23
30
|
DEFAULT_DIALOG_CONTENT_PADDING,
|
|
24
31
|
DEFAULT_MAX_HEIGHT_RATIO,
|
|
@@ -62,6 +69,7 @@ export function DialogBottomSheet({
|
|
|
62
69
|
dismissOnBackdrop = true,
|
|
63
70
|
contentPadding = DEFAULT_DIALOG_CONTENT_PADDING,
|
|
64
71
|
scrollable,
|
|
72
|
+
morph,
|
|
65
73
|
style,
|
|
66
74
|
panelStyle,
|
|
67
75
|
panelClassName,
|
|
@@ -72,6 +80,7 @@ export function DialogBottomSheet({
|
|
|
72
80
|
}: DialogBottomSheetProps) {
|
|
73
81
|
const isControlled = controlledOpen !== undefined;
|
|
74
82
|
const theme = useTheme();
|
|
83
|
+
const { height: viewportHeight } = useWindowDimensions();
|
|
75
84
|
const ref = useRef<BottomSheetRef>(null);
|
|
76
85
|
const closeCallbacks = useRef<(() => void)[]>([]);
|
|
77
86
|
const titleId = useId();
|
|
@@ -155,10 +164,23 @@ export function DialogBottomSheet({
|
|
|
155
164
|
[dismissOnBackdrop],
|
|
156
165
|
);
|
|
157
166
|
|
|
167
|
+
const scrollableResolved = scrollable ?? true;
|
|
168
|
+
|
|
169
|
+
// Size morphing across an in-place content swap. The sheet is anchored at the
|
|
170
|
+
// bottom, so animating its height makes it grow/shrink from that edge; its
|
|
171
|
+
// width is fixed by the placement. The sheet's own `maxHeight` (the ratio
|
|
172
|
+
// percentage + the safe-area clamp inside `BottomSheet`) does the exact
|
|
173
|
+
// capping — the viewport is just the bound the reshape may not exceed.
|
|
174
|
+
const morphState = useDialogMorph({
|
|
175
|
+
enabled: morph !== false,
|
|
176
|
+
measurable: scrollableResolved,
|
|
177
|
+
maxHeight: viewportHeight,
|
|
178
|
+
});
|
|
179
|
+
|
|
158
180
|
// `panelStyle` paints the sheet surface (e.g. a brand background). It composes
|
|
159
181
|
// AFTER the BottomSheet's internal background so a host palette wins; the
|
|
160
182
|
// shape (radius, max height) is supplied here and remains overridable.
|
|
161
|
-
const sheetStyle = useMemo<StyleProp<ViewStyle
|
|
183
|
+
const sheetStyle = useMemo<StyleProp<AnimatedStyle<ViewStyle>>>(() => {
|
|
162
184
|
const maxHeightPercent: `${number}%` = `${Math.round(maxHeightRatio * 100)}%`;
|
|
163
185
|
return [
|
|
164
186
|
{
|
|
@@ -168,8 +190,11 @@ export function DialogBottomSheet({
|
|
|
168
190
|
maxHeight: maxHeightPercent,
|
|
169
191
|
},
|
|
170
192
|
panelStyle,
|
|
193
|
+
// Drives the card's `height` only while a morph is in flight; at rest it
|
|
194
|
+
// resolves to `height: 'auto'` — the sheet's normal content sizing.
|
|
195
|
+
morphState.panelStyle,
|
|
171
196
|
];
|
|
172
|
-
}, [theme.colors.background, maxHeightRatio, panelStyle]);
|
|
197
|
+
}, [theme.colors.background, maxHeightRatio, panelStyle, morphState.panelStyle]);
|
|
173
198
|
|
|
174
199
|
// Does this dialog render bloom's declarative chrome (title / description /
|
|
175
200
|
// actions)? This no longer gates the SCROLL decision (that is now the explicit
|
|
@@ -183,8 +208,6 @@ export function DialogBottomSheet({
|
|
|
183
208
|
description !== undefined ||
|
|
184
209
|
(actions !== undefined && actions.length > 0);
|
|
185
210
|
|
|
186
|
-
const scrollableResolved = scrollable ?? true;
|
|
187
|
-
|
|
188
211
|
const dialogBody = (
|
|
189
212
|
<DialogBody
|
|
190
213
|
titleId={titleId}
|
|
@@ -264,6 +287,8 @@ export function DialogBottomSheet({
|
|
|
264
287
|
// Stronger dim than a lone sheet so an underlying sheet's handle/content
|
|
265
288
|
// doesn't bleed through when a Dialog is stacked over one.
|
|
266
289
|
backdropOpacity={SHEET_BACKDROP_OPACITY + 0.3}
|
|
290
|
+
// Measures the sheet card — the size a morph starts from.
|
|
291
|
+
onLayout={morphState.onPanelLayout}
|
|
267
292
|
style={sheetStyle}
|
|
268
293
|
>
|
|
269
294
|
<Context.Provider value={context}>
|
|
@@ -285,7 +310,12 @@ export function DialogBottomSheet({
|
|
|
285
310
|
panelStyle,
|
|
286
311
|
]}
|
|
287
312
|
>
|
|
288
|
-
{
|
|
313
|
+
{/* The morph layer is its own node INSIDE the class-name'd container:
|
|
314
|
+
a className'd component's `onLayout` never fires on web, and this
|
|
315
|
+
one has to measure the incoming frame. */}
|
|
316
|
+
<DialogMorphContent morph={morphState}>
|
|
317
|
+
{header ? headerBody : dialogBody}
|
|
318
|
+
</DialogMorphContent>
|
|
289
319
|
</View>
|
|
290
320
|
</Context.Provider>
|
|
291
321
|
</BottomSheet>
|
|
@@ -313,6 +343,7 @@ export type DialogBottomSheetProps = Pick<
|
|
|
313
343
|
| 'dismissOnBackdrop'
|
|
314
344
|
| 'contentPadding'
|
|
315
345
|
| 'scrollable'
|
|
346
|
+
| 'morph'
|
|
316
347
|
| 'style'
|
|
317
348
|
| 'panelStyle'
|
|
318
349
|
| 'panelClassName'
|
|
@@ -89,6 +89,7 @@ function configsEqual(a: DialogHeaderConfig | null, b: DialogHeaderConfig | null
|
|
|
89
89
|
if (!a || !b) return false;
|
|
90
90
|
return (
|
|
91
91
|
a.title === b.title &&
|
|
92
|
+
a.titleContent === b.titleContent &&
|
|
92
93
|
a.subtitle === b.subtitle &&
|
|
93
94
|
a.largeTitle === b.largeTitle &&
|
|
94
95
|
a.left === b.left &&
|
|
@@ -181,6 +182,7 @@ export function useDialogHeader(config: DialogHeaderConfig | null | undefined):
|
|
|
181
182
|
}, [
|
|
182
183
|
store,
|
|
183
184
|
config?.title,
|
|
185
|
+
config?.titleContent,
|
|
184
186
|
config?.subtitle,
|
|
185
187
|
config?.largeTitle,
|
|
186
188
|
config?.left,
|
|
@@ -235,7 +237,10 @@ export const DialogNavHeader = memo(function DialogNavHeader({
|
|
|
235
237
|
const config = useMergedHeaderConfig(header, controller.store);
|
|
236
238
|
const { scrollY, largeTitleHeight } = controller;
|
|
237
239
|
|
|
238
|
-
|
|
240
|
+
// A branded `titleContent` owns the bar centre outright: it is always visible,
|
|
241
|
+
// so there is nothing to collapse and no large in-content title to collapse under.
|
|
242
|
+
const hasLargeTitle =
|
|
243
|
+
collapse && !config.titleContent && (config.largeTitle ?? true) && !!config.title;
|
|
239
244
|
|
|
240
245
|
const titleStyle = useAnimatedStyle(() => {
|
|
241
246
|
// When there is no large title to collapse under, the bar title is always
|
|
@@ -294,15 +299,17 @@ export const DialogNavHeader = memo(function DialogNavHeader({
|
|
|
294
299
|
testID="dialog-nav-title"
|
|
295
300
|
style={[styles.centerTitle, titleStyle]}
|
|
296
301
|
>
|
|
297
|
-
{config.
|
|
302
|
+
{config.titleContent ?? null}
|
|
303
|
+
{!config.titleContent && config.title ? (
|
|
298
304
|
<Text numberOfLines={1} style={[styles.smallTitle, { color: theme.colors.text }]}>
|
|
299
305
|
{config.title}
|
|
300
306
|
</Text>
|
|
301
307
|
) : null}
|
|
302
308
|
{/* The subtitle rides along ONLY in the static (non-collapsing) bar —
|
|
303
309
|
own-scroller screens whose subtitle is a short count. A large-title
|
|
304
|
-
screen keeps a clean single-line collapsed title
|
|
305
|
-
|
|
310
|
+
screen keeps a clean single-line collapsed title, and a branded
|
|
311
|
+
`titleContent` bar carries no supporting copy at all. */}
|
|
312
|
+
{!hasLargeTitle && !config.titleContent && config.subtitle ? (
|
|
306
313
|
<Text
|
|
307
314
|
numberOfLines={1}
|
|
308
315
|
style={[styles.smallSubtitle, { color: theme.colors.textSecondary }]}
|
|
@@ -336,7 +343,9 @@ export const DialogLargeTitle = memo(function DialogLargeTitle({
|
|
|
336
343
|
const config = useMergedHeaderConfig(header, controller.store);
|
|
337
344
|
const { largeTitleHeight } = controller;
|
|
338
345
|
|
|
339
|
-
|
|
346
|
+
// A branded `titleContent` lives in the bar and never collapses, so the
|
|
347
|
+
// surface starts flush under the bar with no large title above it.
|
|
348
|
+
const hasLargeTitle = !config.titleContent && (config.largeTitle ?? true) && !!config.title;
|
|
340
349
|
|
|
341
350
|
const onLayout = (e: LayoutChangeEvent) => {
|
|
342
351
|
largeTitleHeight.value = e.nativeEvent.layout.height;
|