@lodev09/react-native-true-sheet 4.0.0-beta.24 → 4.0.0-beta.26
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/README.md +2 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetModule.kt +13 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetOverlayView.kt +12 -1
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +120 -19
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +103 -27
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +18 -10
- package/android/src/main/java/com/lodev09/truesheet/core/RNScreensEventObserver.kt +31 -14
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetBehavior.kt +9 -0
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetView.kt +3 -16
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetCoordinatorLayout.kt +14 -1
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDimView.kt +11 -17
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetGrabberView.kt +2 -4
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetStackManager.kt +29 -38
- package/android/src/main/java/com/lodev09/truesheet/utils/ColorUtils.kt +19 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.cpp +6 -2
- package/ios/TrueSheetContainerView.h +1 -0
- package/ios/TrueSheetContainerView.mm +6 -0
- package/ios/TrueSheetContentView.h +1 -0
- package/ios/TrueSheetContentView.mm +2 -0
- package/ios/TrueSheetFooterView.mm +5 -0
- package/ios/TrueSheetModule.mm +11 -2
- package/ios/TrueSheetView.h +2 -0
- package/ios/TrueSheetView.mm +62 -9
- package/ios/TrueSheetViewController.h +14 -0
- package/ios/TrueSheetViewController.mm +490 -33
- package/ios/core/RNScreensEventObserver.mm +18 -1
- package/ios/core/TrueSheetDetentCalculator.h +11 -0
- package/ios/core/TrueSheetDetentCalculator.mm +17 -5
- package/ios/core/TrueSheetDimView.h +27 -0
- package/ios/core/TrueSheetDimView.mm +41 -0
- package/ios/core/TrueSheetKeyboardObserver.mm +98 -15
- package/lib/module/TrueSheet.js +88 -17
- package/lib/module/TrueSheet.js.map +1 -1
- package/lib/module/TrueSheet.web.js +150 -37
- package/lib/module/TrueSheet.web.js.map +1 -1
- package/lib/module/TrueSheetProvider.web.js +13 -9
- package/lib/module/TrueSheetProvider.web.js.map +1 -1
- package/lib/module/fabric/TrueSheetViewNativeComponent.ts +8 -0
- package/lib/module/scrollable.js +28 -0
- package/lib/module/scrollable.js.map +1 -0
- package/lib/module/web/keyboard.js +69 -0
- package/lib/module/web/keyboard.js.map +1 -0
- package/lib/module/web/layout.js +1 -1
- package/lib/module/web/layout.js.map +1 -1
- package/lib/module/web/vaul/context.js.map +1 -1
- package/lib/module/web/vaul/index.js +18 -8
- package/lib/module/web/vaul/index.js.map +1 -1
- package/lib/module/web/vaul/use-snap-points.js +15 -10
- package/lib/module/web/vaul/use-snap-points.js.map +1 -1
- package/lib/typescript/src/TrueSheet.d.ts +14 -1
- package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheet.types.d.ts +53 -2
- package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheet.web.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheetProvider.web.d.ts +5 -1
- package/lib/typescript/src/TrueSheetProvider.web.d.ts.map +1 -1
- package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +7 -0
- package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/navigation/types.d.ts +1 -1
- package/lib/typescript/src/navigation/types.d.ts.map +1 -1
- package/lib/typescript/src/scrollable.d.ts +2 -0
- package/lib/typescript/src/scrollable.d.ts.map +1 -0
- package/lib/typescript/src/web/keyboard.d.ts +15 -0
- package/lib/typescript/src/web/keyboard.d.ts.map +1 -0
- package/lib/typescript/src/web/layout.d.ts +1 -0
- package/lib/typescript/src/web/layout.d.ts.map +1 -1
- package/lib/typescript/src/web/vaul/context.d.ts +2 -1
- package/lib/typescript/src/web/vaul/context.d.ts.map +1 -1
- package/lib/typescript/src/web/vaul/index.d.ts +8 -1
- package/lib/typescript/src/web/vaul/index.d.ts.map +1 -1
- package/lib/typescript/src/web/vaul/types.d.ts +9 -0
- package/lib/typescript/src/web/vaul/types.d.ts.map +1 -1
- package/lib/typescript/src/web/vaul/use-snap-points.d.ts +3 -2
- package/lib/typescript/src/web/vaul/use-snap-points.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/TrueSheet.tsx +91 -14
- package/src/TrueSheet.types.ts +60 -2
- package/src/TrueSheet.web.tsx +170 -41
- package/src/TrueSheetProvider.web.tsx +22 -13
- package/src/fabric/TrueSheetViewNativeComponent.ts +8 -0
- package/src/navigation/types.ts +3 -0
- package/src/scrollable.ts +25 -0
- package/src/web/keyboard.ts +79 -0
- package/src/web/layout.ts +1 -1
- package/src/web/vaul/context.ts +2 -1
- package/src/web/vaul/index.tsx +20 -5
- package/src/web/vaul/types.ts +10 -0
- package/src/web/vaul/use-snap-points.ts +19 -9
package/src/web/vaul/index.tsx
CHANGED
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
reset,
|
|
29
29
|
set,
|
|
30
30
|
} from './helpers';
|
|
31
|
-
import type { DrawerDirection } from './types';
|
|
31
|
+
import type { DrawerDirection, KeyboardViewport } from './types';
|
|
32
32
|
import { useComposedRefs } from './use-composed-refs';
|
|
33
33
|
import { useControllableState } from './use-controllable-state';
|
|
34
34
|
import { usePositionFixed } from './use-position-fixed';
|
|
@@ -224,6 +224,12 @@ export type DialogProps = {
|
|
|
224
224
|
* from natural flow.
|
|
225
225
|
*/
|
|
226
226
|
contentHeight?: number;
|
|
227
|
+
/**
|
|
228
|
+
* Lays the drawer out in the visual viewport above a soft keyboard. The
|
|
229
|
+
* wrapper and snap offsets fit the visible area, while fractional snap
|
|
230
|
+
* points keep scaling against the full layout height.
|
|
231
|
+
*/
|
|
232
|
+
keyboardViewport?: KeyboardViewport;
|
|
227
233
|
} & (WithFadeFromProps | WithoutFadeFromProps);
|
|
228
234
|
|
|
229
235
|
export function Root({
|
|
@@ -269,6 +275,7 @@ export function Root({
|
|
|
269
275
|
initialAnimated = true,
|
|
270
276
|
onContentHeightChange,
|
|
271
277
|
contentHeight: contentHeightProp,
|
|
278
|
+
keyboardViewport,
|
|
272
279
|
}: DialogProps) {
|
|
273
280
|
const [isOpen = false, setIsOpen] = useControllableState({
|
|
274
281
|
defaultProp: defaultOpen,
|
|
@@ -352,6 +359,7 @@ export function Root({
|
|
|
352
359
|
maxContentHeight,
|
|
353
360
|
peekHeight,
|
|
354
361
|
initialAnimated,
|
|
362
|
+
keyboardViewport,
|
|
355
363
|
});
|
|
356
364
|
|
|
357
365
|
usePreventScroll({
|
|
@@ -1049,6 +1057,7 @@ export function Root({
|
|
|
1049
1057
|
detachedOffset: detached ? detachedOffset : 0,
|
|
1050
1058
|
detachedRadius: detached ? detachedRadius : 0,
|
|
1051
1059
|
detachedWrapperStyle,
|
|
1060
|
+
keyboardViewport,
|
|
1052
1061
|
}}
|
|
1053
1062
|
>
|
|
1054
1063
|
{children}
|
|
@@ -1191,6 +1200,7 @@ export const Content = React.forwardRef<HTMLDivElement, ContentProps>(
|
|
|
1191
1200
|
detachedOffset,
|
|
1192
1201
|
detachedRadius,
|
|
1193
1202
|
detachedWrapperStyle: detachedWrapperStyleProp,
|
|
1203
|
+
keyboardViewport,
|
|
1194
1204
|
} = useDrawerContext();
|
|
1195
1205
|
// Always measure the inner wrapper's natural height. The drawer itself may
|
|
1196
1206
|
// be styled to a fixed viewport height, so we measure an inner wrapper
|
|
@@ -1393,14 +1403,19 @@ export const Content = React.forwardRef<HTMLDivElement, ContentProps>(
|
|
|
1393
1403
|
// with a bottom gap and rounded bottom corners; otherwise it sits flush.
|
|
1394
1404
|
// Transform/transition are managed imperatively (via drag overshoot and the
|
|
1395
1405
|
// dismiss effect) so React doesn't skip DOM writes for values it thinks it
|
|
1396
|
-
// already owns.
|
|
1406
|
+
// already owns. Above a soft keyboard the wrapper fits the visual viewport,
|
|
1407
|
+
// which the full-height layout viewport extends behind.
|
|
1397
1408
|
const wrapperStyle = React.useMemo<React.CSSProperties>(
|
|
1398
1409
|
() => ({
|
|
1399
1410
|
position: 'fixed',
|
|
1400
|
-
top: 0,
|
|
1401
1411
|
left: 0,
|
|
1402
1412
|
right: 0,
|
|
1403
|
-
|
|
1413
|
+
...(keyboardViewport
|
|
1414
|
+
? {
|
|
1415
|
+
top: keyboardViewport.top,
|
|
1416
|
+
height: Math.max(0, keyboardViewport.height - (detached ? detachedOffset : 0)),
|
|
1417
|
+
}
|
|
1418
|
+
: { top: 0, bottom: detached ? detachedOffset : 0 }),
|
|
1404
1419
|
overflow: 'hidden',
|
|
1405
1420
|
contain: 'paint',
|
|
1406
1421
|
pointerEvents: 'none',
|
|
@@ -1408,7 +1423,7 @@ export const Content = React.forwardRef<HTMLDivElement, ContentProps>(
|
|
|
1408
1423
|
borderBottomRightRadius: detached ? detachedRadius : 0,
|
|
1409
1424
|
...detachedWrapperStyleProp,
|
|
1410
1425
|
}),
|
|
1411
|
-
[detached, detachedOffset, detachedRadius, detachedWrapperStyleProp]
|
|
1426
|
+
[detached, detachedOffset, detachedRadius, detachedWrapperStyleProp, keyboardViewport]
|
|
1412
1427
|
);
|
|
1413
1428
|
|
|
1414
1429
|
// Translate the wrapper off-screen on dismiss so the whole card slides out
|
package/src/web/vaul/types.ts
CHANGED
|
@@ -5,3 +5,13 @@ export interface SnapPoint {
|
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export type AnyFunction = (...args: any) => any;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The visual viewport while a soft keyboard shrinks it, in layout-viewport px.
|
|
11
|
+
* `layoutHeight` is the full (keyboard-free) height.
|
|
12
|
+
*/
|
|
13
|
+
export interface KeyboardViewport {
|
|
14
|
+
top: number;
|
|
15
|
+
height: number;
|
|
16
|
+
layoutHeight: number;
|
|
17
|
+
}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
VELOCITY_THRESHOLD,
|
|
10
10
|
} from './constants';
|
|
11
11
|
import { useControllableState } from './use-controllable-state';
|
|
12
|
-
import type { DrawerDirection } from './types';
|
|
12
|
+
import type { DrawerDirection, KeyboardViewport } from './types';
|
|
13
13
|
|
|
14
14
|
export function useSnapPoints({
|
|
15
15
|
activeSnapPointProp,
|
|
@@ -28,6 +28,7 @@ export function useSnapPoints({
|
|
|
28
28
|
maxContentHeight,
|
|
29
29
|
peekHeight,
|
|
30
30
|
initialAnimated = true,
|
|
31
|
+
keyboardViewport,
|
|
31
32
|
}: {
|
|
32
33
|
activeSnapPointProp?: number | string | null;
|
|
33
34
|
setActiveSnapPointProp?(snapPoint: number | null | string): void;
|
|
@@ -45,6 +46,7 @@ export function useSnapPoints({
|
|
|
45
46
|
maxContentHeight?: number;
|
|
46
47
|
peekHeight?: number;
|
|
47
48
|
initialAnimated?: boolean;
|
|
49
|
+
keyboardViewport?: KeyboardViewport;
|
|
48
50
|
}) {
|
|
49
51
|
const [activeSnapPoint, setActiveSnapPoint] = useControllableState<string | number | null>({
|
|
50
52
|
prop: activeSnapPointProp,
|
|
@@ -98,13 +100,18 @@ export function useSnapPoints({
|
|
|
98
100
|
height: container.getBoundingClientRect().height,
|
|
99
101
|
}
|
|
100
102
|
: typeof window !== 'undefined'
|
|
101
|
-
? { width: window.innerWidth, height: window.innerHeight }
|
|
103
|
+
? { width: window.innerWidth, height: keyboardViewport?.height ?? window.innerHeight }
|
|
102
104
|
: { width: 0, height: 0 };
|
|
103
105
|
|
|
104
106
|
// Shrink the effective vertical area by detachedOffset so snap math
|
|
105
107
|
// reserves a fixed gap at the bottom — the floating card stays offset
|
|
106
108
|
// from the viewport edge through drag, snap and resize.
|
|
107
109
|
const effectiveHeight = Math.max(0, containerSize.height - (detachedOffset || 0));
|
|
110
|
+
// Above a keyboard, fractional snap points keep their full-height size and
|
|
111
|
+
// only cap at the visible area — mirrors native, where the sheet rises.
|
|
112
|
+
const fractionHeight = keyboardViewport
|
|
113
|
+
? Math.max(0, keyboardViewport.layoutHeight - (detachedOffset || 0))
|
|
114
|
+
: effectiveHeight;
|
|
108
115
|
|
|
109
116
|
return (
|
|
110
117
|
snapPoints?.map((snapPoint) => {
|
|
@@ -129,11 +136,11 @@ export function useSnapPoints({
|
|
|
129
136
|
const rawHeight = isPx
|
|
130
137
|
? snapPointAsNumber
|
|
131
138
|
: windowDimensions
|
|
132
|
-
? resolved *
|
|
139
|
+
? resolved * fractionHeight
|
|
133
140
|
: 0;
|
|
134
|
-
// Cap
|
|
135
|
-
// doesn't push the drawer past the top
|
|
136
|
-
//
|
|
141
|
+
// Cap snap points so content taller than the viewport (or a
|
|
142
|
+
// fraction above a keyboard) doesn't push the drawer past the top
|
|
143
|
+
// edge (offset would go negative).
|
|
137
144
|
// `maxContentHeight`, when set, caps the visible sheet further so
|
|
138
145
|
// full/'auto' detents respect the user's ceiling.
|
|
139
146
|
const ceiling =
|
|
@@ -170,8 +177,11 @@ export function useSnapPoints({
|
|
|
170
177
|
detachedOffset,
|
|
171
178
|
maxContentHeight,
|
|
172
179
|
peekHeight,
|
|
180
|
+
keyboardViewport,
|
|
173
181
|
]);
|
|
174
182
|
|
|
183
|
+
const getViewportHeight = () => keyboardViewport?.height ?? window.innerHeight;
|
|
184
|
+
|
|
175
185
|
const activeSnapPointOffset = React.useMemo(
|
|
176
186
|
() => (activeSnapPointIndex !== null ? snapPointsOffset?.[activeSnapPointIndex] : null),
|
|
177
187
|
[snapPointsOffset, activeSnapPointIndex]
|
|
@@ -334,7 +344,7 @@ export function useSnapPoints({
|
|
|
334
344
|
(direction === 'bottom' || direction === 'right') &&
|
|
335
345
|
currentPosition > snapPointsOffset[0]
|
|
336
346
|
) {
|
|
337
|
-
const viewportDim = isVertical(direction) ?
|
|
347
|
+
const viewportDim = isVertical(direction) ? getViewportHeight() : window.innerWidth;
|
|
338
348
|
const effectiveDim = Math.max(0, viewportDim - (detachedOffset || 0));
|
|
339
349
|
const visibleAtLowest = Math.max(0, effectiveDim - snapPointsOffset[0]);
|
|
340
350
|
const overshoot = currentPosition - snapPointsOffset[0];
|
|
@@ -362,7 +372,7 @@ export function useSnapPoints({
|
|
|
362
372
|
return Math.abs(curr - currentPosition) < Math.abs(prev - currentPosition) ? curr : prev;
|
|
363
373
|
});
|
|
364
374
|
|
|
365
|
-
const dim = isVertical(direction) ?
|
|
375
|
+
const dim = isVertical(direction) ? getViewportHeight() : window.innerWidth;
|
|
366
376
|
if (velocity > VELOCITY_THRESHOLD && Math.abs(draggedDistance) < dim * 0.4) {
|
|
367
377
|
const dragDirection = hasDraggedUp ? 1 : -1; // 1 = up, -1 = down
|
|
368
378
|
|
|
@@ -444,7 +454,7 @@ export function useSnapPoints({
|
|
|
444
454
|
if (activeSnapPointIndex === 0 && !isDraggingDown) {
|
|
445
455
|
const activeOffset = snapPointsOffset[activeSnapPointIndex];
|
|
446
456
|
if (activeOffset === undefined) return 0;
|
|
447
|
-
const windowDim = isVertical(direction) ?
|
|
457
|
+
const windowDim = isVertical(direction) ? getViewportHeight() : window.innerWidth;
|
|
448
458
|
const dismissOffset =
|
|
449
459
|
direction === 'bottom' || direction === 'right' ? windowDim : -windowDim;
|
|
450
460
|
const dismissRange = Math.abs(dismissOffset - activeOffset);
|