@lodev09/react-native-true-sheet 4.0.0-beta.3 → 4.0.0-beta.5
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 +21 -2
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerView.kt +24 -7
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentView.kt +195 -174
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentViewManager.kt +5 -1
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetFooterView.kt +6 -17
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +50 -8
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +101 -18
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +24 -1
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetCoordinatorLayout.kt +3 -3
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDetentCalculator.kt +14 -24
- package/android/src/main/java/com/lodev09/truesheet/utils/ViewUtils.kt +0 -7
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewComponentDescriptor.h +0 -8
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.cpp +54 -29
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.h +6 -1
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.cpp +1 -1
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.h +6 -4
- package/ios/TrueSheetContainerView.h +9 -7
- package/ios/TrueSheetContainerView.mm +6 -7
- package/ios/TrueSheetContentView.h +28 -14
- package/ios/TrueSheetContentView.mm +122 -179
- package/ios/TrueSheetFooterView.mm +17 -0
- package/ios/TrueSheetView.mm +13 -10
- package/ios/TrueSheetViewController.mm +35 -27
- package/ios/utils/UIView+ScrollEdgeInteraction.h +1 -0
- package/ios/utils/UIView+ScrollEdgeInteraction.mm +24 -2
- package/lib/module/TrueSheet.js +47 -14
- package/lib/module/TrueSheet.js.map +1 -1
- package/lib/module/TrueSheet.web.js +26 -24
- package/lib/module/TrueSheet.web.js.map +1 -1
- package/lib/module/fabric/TrueSheetContentViewNativeComponent.ts +1 -1
- package/lib/module/fabric/TrueSheetViewNativeComponent.ts +4 -0
- package/lib/typescript/src/TrueSheet.d.ts +2 -0
- package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheet.types.d.ts +64 -1
- 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/fabric/TrueSheetViewNativeComponent.d.ts +3 -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/package.json +1 -1
- package/src/TrueSheet.tsx +48 -13
- package/src/TrueSheet.types.ts +68 -1
- package/src/TrueSheet.web.tsx +39 -24
- package/src/fabric/TrueSheetContentViewNativeComponent.ts +1 -1
- package/src/fabric/TrueSheetViewNativeComponent.ts +4 -0
- package/src/navigation/types.ts +1 -0
package/src/TrueSheet.tsx
CHANGED
|
@@ -59,16 +59,26 @@ if (!TrueSheetModule) {
|
|
|
59
59
|
|
|
60
60
|
type NativeRef = ComponentRef<typeof TrueSheetViewNativeComponent>;
|
|
61
61
|
|
|
62
|
-
// Claim touches that no descendant claimed so the responder negotiation
|
|
63
|
-
// doesn't bubble up to touchables outside the sheet
|
|
64
|
-
const absorbUnclaimedTouches = () => true;
|
|
65
|
-
|
|
66
62
|
// Stop raw touch events from bubbling past the sheet to outside ancestors
|
|
67
63
|
const stopTouchPropagation = (event: GestureResponderEvent) => event.stopPropagation();
|
|
68
64
|
|
|
65
|
+
// Stop the responder negotiation at the sheet boundary without claiming the
|
|
66
|
+
// responder. Views inside the sheet are asked before this one, so in-sheet
|
|
67
|
+
// touchables work normally; views outside are asked after, so stopping here
|
|
68
|
+
// keeps unclaimed touches from leaking to touchables behind the sheet.
|
|
69
|
+
// Claiming instead (returning true) would steal the responder from a pressed
|
|
70
|
+
// touchable whenever the negotiation re-runs mid-gesture — e.g. a second
|
|
71
|
+
// finger, or the duplicate touch stream from a nested react-native-screens
|
|
72
|
+
// screen that attaches its own touch handler inside the sheet.
|
|
73
|
+
const stopResponderNegotiation = (event: GestureResponderEvent) => {
|
|
74
|
+
event.stopPropagation();
|
|
75
|
+
return false;
|
|
76
|
+
};
|
|
77
|
+
|
|
69
78
|
interface TrueSheetState {
|
|
70
79
|
shouldRenderNativeView: boolean;
|
|
71
80
|
initialPresentReady: boolean;
|
|
81
|
+
scrollableHandle: number | null;
|
|
72
82
|
}
|
|
73
83
|
|
|
74
84
|
// Gates auto-present (initialDetentIndex) by one commit. Rendered last in the
|
|
@@ -120,13 +130,15 @@ export class TrueSheet
|
|
|
120
130
|
|
|
121
131
|
this.validateDetents();
|
|
122
132
|
|
|
123
|
-
// Lazy load by default, except when
|
|
133
|
+
// Lazy load by default, except when auto-presenting or when lazy is disabled
|
|
124
134
|
const shouldRenderImmediately =
|
|
125
|
-
props.initialDetentIndex !== undefined && props.initialDetentIndex >= 0
|
|
135
|
+
(props.initialDetentIndex !== undefined && props.initialDetentIndex >= 0) ||
|
|
136
|
+
props.lazy === false;
|
|
126
137
|
|
|
127
138
|
this.state = {
|
|
128
139
|
shouldRenderNativeView: shouldRenderImmediately,
|
|
129
140
|
initialPresentReady: false,
|
|
141
|
+
scrollableHandle: null,
|
|
130
142
|
};
|
|
131
143
|
|
|
132
144
|
this.onMount = this.onMount.bind(this);
|
|
@@ -152,6 +164,17 @@ export class TrueSheet
|
|
|
152
164
|
this.setState({ initialPresentReady: true });
|
|
153
165
|
}
|
|
154
166
|
|
|
167
|
+
// Resolves after commit (didMount/didUpdate) — the scrollable mounts with the
|
|
168
|
+
// sheet content, so its ref is only populated once the native tree renders.
|
|
169
|
+
private updateScrollableHandle(): void {
|
|
170
|
+
const { scrollableRef } = this.props;
|
|
171
|
+
const scrollableHandle = scrollableRef?.current ? findNodeHandle(scrollableRef.current) : null;
|
|
172
|
+
|
|
173
|
+
if (scrollableHandle !== this.state.scrollableHandle) {
|
|
174
|
+
this.setState({ scrollableHandle });
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
155
178
|
private validateDetents(): void {
|
|
156
179
|
const { detents, initialDetentIndex } = this.props;
|
|
157
180
|
|
|
@@ -328,9 +351,8 @@ export class TrueSheet
|
|
|
328
351
|
this.backHandlerSubscription?.remove();
|
|
329
352
|
this.backHandlerSubscription = null;
|
|
330
353
|
|
|
331
|
-
//
|
|
332
|
-
|
|
333
|
-
if (!this.isPresenting) {
|
|
354
|
+
// Non-lazy content stays mounted; otherwise clean it up unless another presentation is active.
|
|
355
|
+
if (!this.isPresenting && this.props.lazy !== false) {
|
|
334
356
|
this.setState({ shouldRenderNativeView: false });
|
|
335
357
|
}
|
|
336
358
|
|
|
@@ -455,10 +477,20 @@ export class TrueSheet
|
|
|
455
477
|
|
|
456
478
|
componentDidMount(): void {
|
|
457
479
|
this.registerInstance();
|
|
480
|
+
this.updateScrollableHandle();
|
|
458
481
|
}
|
|
459
482
|
|
|
460
483
|
componentDidUpdate(prevProps: TrueSheetProps): void {
|
|
461
484
|
this.registerInstance();
|
|
485
|
+
this.updateScrollableHandle();
|
|
486
|
+
|
|
487
|
+
if (
|
|
488
|
+
prevProps.lazy !== false &&
|
|
489
|
+
this.props.lazy === false &&
|
|
490
|
+
!this.state.shouldRenderNativeView
|
|
491
|
+
) {
|
|
492
|
+
this.setState({ shouldRenderNativeView: true });
|
|
493
|
+
}
|
|
462
494
|
|
|
463
495
|
// Validate when detents prop changes
|
|
464
496
|
if (prevProps.detents !== this.props.detents) {
|
|
@@ -519,6 +551,7 @@ export class TrueSheet
|
|
|
519
551
|
insetAdjustment = 'automatic',
|
|
520
552
|
...rest
|
|
521
553
|
} = this.props;
|
|
554
|
+
delete rest.lazy;
|
|
522
555
|
|
|
523
556
|
// Trim to max 3 detents and clamp fractions
|
|
524
557
|
const resolvedDetents: number[] = detents.slice(0, 3).map((detent) => {
|
|
@@ -570,6 +603,7 @@ export class TrueSheet
|
|
|
570
603
|
maxContentWidth={maxContentWidth}
|
|
571
604
|
anchor={anchor}
|
|
572
605
|
anchorOffset={anchorOffset}
|
|
606
|
+
scrollableHandle={this.state.scrollableHandle ?? -1}
|
|
573
607
|
scrollableOptions={scrollableOptions}
|
|
574
608
|
headerOptions={headerOptions}
|
|
575
609
|
footerOptions={{
|
|
@@ -595,10 +629,11 @@ export class TrueSheet
|
|
|
595
629
|
onVisibilityChange={this.onVisibilityChange}
|
|
596
630
|
// These must stay on this host view, not on the container. The container is
|
|
597
631
|
// reparented into the native sheet, so this view is never a native ancestor of
|
|
598
|
-
// the sheet content
|
|
599
|
-
//
|
|
600
|
-
//
|
|
601
|
-
onStartShouldSetResponder={
|
|
632
|
+
// the sheet content — this is the React-tree boundary between the sheet and
|
|
633
|
+
// the presenting screen, where both the responder negotiation and raw touch
|
|
634
|
+
// bubbling must stop.
|
|
635
|
+
onStartShouldSetResponder={stopResponderNegotiation}
|
|
636
|
+
onMoveShouldSetResponder={stopResponderNegotiation}
|
|
602
637
|
onTouchStart={stopTouchPropagation}
|
|
603
638
|
onTouchMove={stopTouchPropagation}
|
|
604
639
|
onTouchEnd={stopTouchPropagation}
|
package/src/TrueSheet.types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ComponentType, ReactElement } from 'react';
|
|
1
|
+
import type { Component, ComponentType, ReactElement, RefObject } from 'react';
|
|
2
2
|
import type {
|
|
3
3
|
ColorValue,
|
|
4
4
|
NativeSyntheticEvent,
|
|
@@ -165,6 +165,28 @@ export type ScrollEdgeEffect = 'automatic' | 'hard' | 'soft' | 'hidden';
|
|
|
165
165
|
* Options for scrollable behavior.
|
|
166
166
|
*/
|
|
167
167
|
export interface ScrollableOptions {
|
|
168
|
+
/**
|
|
169
|
+
* Applies the bottom safe-area inset to the scroll content automatically
|
|
170
|
+
* while the content can scroll, so the last item clears the home indicator
|
|
171
|
+
* (iOS) and navigation bar (Android).
|
|
172
|
+
*
|
|
173
|
+
* - **iOS**: Sets the scroll view's native
|
|
174
|
+
* [`contentInsetAdjustmentBehavior`](https://developer.apple.com/documentation/uikit/uiscrollview/contentinsetadjustmentbehavior)
|
|
175
|
+
* to `automatic` while it's plugged into the sheet — no need to set React
|
|
176
|
+
* Native's iOS-only prop yourself.
|
|
177
|
+
* - **Android**: Pads the scroll content with the bottom window inset,
|
|
178
|
+
* mirroring iOS's `automatic` behavior — parity React Native's iOS-only
|
|
179
|
+
* prop can't provide.
|
|
180
|
+
* - **Web**: Lifts the content above the safe area
|
|
181
|
+
* (`env(safe-area-inset-bottom)`).
|
|
182
|
+
*
|
|
183
|
+
* Only applies while the sheet's `insetAdjustment` is `'automatic'`. When
|
|
184
|
+
* the sheet has a relative footer, the footer absorbs the inset instead.
|
|
185
|
+
*
|
|
186
|
+
* @default true
|
|
187
|
+
*/
|
|
188
|
+
contentInsetAdjustmentBehavior?: boolean;
|
|
189
|
+
|
|
168
190
|
/**
|
|
169
191
|
* Extra offset when scrolling to the focused input when keyboard appears.
|
|
170
192
|
*
|
|
@@ -172,6 +194,18 @@ export interface ScrollableOptions {
|
|
|
172
194
|
*/
|
|
173
195
|
keyboardScrollOffset?: number;
|
|
174
196
|
|
|
197
|
+
/**
|
|
198
|
+
* Adjusts the bottom inset applied to the scrollable when the keyboard is shown.
|
|
199
|
+
* Positive values increase the inset; negative values reduce it.
|
|
200
|
+
* Pass `-insets.bottom` to cancel out safe-area padding already included in
|
|
201
|
+
* the content's `paddingBottom`.
|
|
202
|
+
* Does not affect the auto scroll of the focused input — it always targets
|
|
203
|
+
* the keyboard edge.
|
|
204
|
+
*
|
|
205
|
+
* @default 0
|
|
206
|
+
*/
|
|
207
|
+
keyboardOffset?: number;
|
|
208
|
+
|
|
175
209
|
/**
|
|
176
210
|
* Whether scrolling the content expands the sheet to the next detent.
|
|
177
211
|
* When `false`, only the grabber can expand the sheet.
|
|
@@ -397,6 +431,21 @@ export interface TrueSheetProps extends ViewProps {
|
|
|
397
431
|
*/
|
|
398
432
|
initialDetentAnimated?: boolean;
|
|
399
433
|
|
|
434
|
+
/**
|
|
435
|
+
* Specify whether the sheet content should mount lazily, on first presentation.
|
|
436
|
+
* Set to `false` to mount the content before presentation without presenting the sheet.
|
|
437
|
+
* Use this when content is not ready on the first render, then call `present()`
|
|
438
|
+
* after your readiness signal so auto detents measure the settled content.
|
|
439
|
+
*
|
|
440
|
+
* Content that requires window attachment to measure, such as SwiftUI-hosted views,
|
|
441
|
+
* still only measures during presentation.
|
|
442
|
+
*
|
|
443
|
+
* @platform android
|
|
444
|
+
* @platform ios
|
|
445
|
+
* @default true
|
|
446
|
+
*/
|
|
447
|
+
lazy?: boolean;
|
|
448
|
+
|
|
400
449
|
/**
|
|
401
450
|
* The detent index that the sheet should start to dim the background.
|
|
402
451
|
* This is ignored if `dimmed` is set to `false`.
|
|
@@ -568,8 +617,26 @@ export interface TrueSheetProps extends ViewProps {
|
|
|
568
617
|
*/
|
|
569
618
|
footerStyle?: StyleProp<ViewStyle>;
|
|
570
619
|
|
|
620
|
+
/**
|
|
621
|
+
* A ref to the scrollable component (e.g. `ScrollView`, `FlatList`)
|
|
622
|
+
* rendered within the sheet content.
|
|
623
|
+
* Required for scrollable handling — nested scrolling, keyboard insets,
|
|
624
|
+
* and `auto` detent sizing are wired to this scrollable.
|
|
625
|
+
*
|
|
626
|
+
* Example:
|
|
627
|
+
* ```tsx
|
|
628
|
+
* const scrollableRef = useRef<ScrollView>(null)
|
|
629
|
+
*
|
|
630
|
+
* <TrueSheet scrollableRef={scrollableRef}>
|
|
631
|
+
* <ScrollView ref={scrollableRef} />
|
|
632
|
+
* </TrueSheet>
|
|
633
|
+
* ```
|
|
634
|
+
*/
|
|
635
|
+
scrollableRef?: RefObject<Component<unknown> | null>;
|
|
636
|
+
|
|
571
637
|
/**
|
|
572
638
|
* Options for scrollable behavior.
|
|
639
|
+
* Applies to the scrollable provided via `scrollableRef`.
|
|
573
640
|
*/
|
|
574
641
|
scrollableOptions?: ScrollableOptions;
|
|
575
642
|
|
package/src/TrueSheet.web.tsx
CHANGED
|
@@ -55,15 +55,15 @@ import { getDOMElement } from './web/dom';
|
|
|
55
55
|
import { Drawer } from './web/vaul';
|
|
56
56
|
import { DEFAULT_PEEK_HEIGHT, TRANSITIONS } from './web/vaul/constants';
|
|
57
57
|
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
return null;
|
|
58
|
+
// Resolves the user's `scrollableRef` to its scrollable DOM element — RN-web
|
|
59
|
+
// ScrollView refs expose the scroll node directly (with helpers attached);
|
|
60
|
+
// list refs (e.g. FlatList) expose it via getScrollableNode(). The node's
|
|
61
|
+
// first child is the content container.
|
|
62
|
+
const getScrollableElement = (scrollable: unknown): HTMLElement | null => {
|
|
63
|
+
if (!scrollable) return null;
|
|
64
|
+
if (scrollable instanceof HTMLElement) return scrollable;
|
|
65
|
+
const node = (scrollable as { getScrollableNode?: () => unknown }).getScrollableNode?.();
|
|
66
|
+
return node instanceof HTMLElement ? node : null;
|
|
67
67
|
};
|
|
68
68
|
|
|
69
69
|
const TrueSheetComponent = forwardRef<TrueSheetMethods, TrueSheetProps>((props, ref) => {
|
|
@@ -79,6 +79,8 @@ const TrueSheetComponent = forwardRef<TrueSheetMethods, TrueSheetProps>((props,
|
|
|
79
79
|
maxContentWidth,
|
|
80
80
|
anchor = 'center',
|
|
81
81
|
anchorOffset = DEFAULT_ANCHOR_OFFSET,
|
|
82
|
+
scrollableRef,
|
|
83
|
+
scrollableOptions,
|
|
82
84
|
grabber = true,
|
|
83
85
|
grabberOptions,
|
|
84
86
|
accessibilityOptions,
|
|
@@ -323,9 +325,9 @@ const TrueSheetComponent = forwardRef<TrueSheetMethods, TrueSheetProps>((props,
|
|
|
323
325
|
// `naturalHeight`.
|
|
324
326
|
const [hasBoundedScrollable, setHasBoundedScrollable] = useState(false);
|
|
325
327
|
const [scrollableAutoHeight, setScrollableAutoHeight] = useState(0);
|
|
326
|
-
const
|
|
328
|
+
const detectedScrollerRef = useRef<HTMLElement | null>(null);
|
|
327
329
|
|
|
328
|
-
// Natural content height (header + content + footer, with a
|
|
330
|
+
// Natural content height (header + content + footer, with a detected
|
|
329
331
|
// scrollable's viewport replaced by its content size) — the height the
|
|
330
332
|
// content wants regardless of the sheet's bounds.
|
|
331
333
|
const measureNaturalHeight = useCallback(() => {
|
|
@@ -335,7 +337,7 @@ const TrueSheetComponent = forwardRef<TrueSheetMethods, TrueSheetProps>((props,
|
|
|
335
337
|
const footerEl = absoluteFooterRef.current ? null : getDOMElement(footerElRef.current);
|
|
336
338
|
let height =
|
|
337
339
|
(headerEl?.offsetHeight ?? 0) + (footerEl?.offsetHeight ?? 0) + contentEl.offsetHeight;
|
|
338
|
-
const scroller =
|
|
340
|
+
const scroller = detectedScrollerRef.current;
|
|
339
341
|
const scrollContent = scroller?.firstElementChild;
|
|
340
342
|
if (scroller?.isConnected && scrollContent instanceof HTMLElement) {
|
|
341
343
|
height += scrollContent.offsetHeight - scroller.clientHeight;
|
|
@@ -369,7 +371,7 @@ const TrueSheetComponent = forwardRef<TrueSheetMethods, TrueSheetProps>((props,
|
|
|
369
371
|
scrollContent: Element | null;
|
|
370
372
|
} | null = null;
|
|
371
373
|
|
|
372
|
-
// (Re)
|
|
374
|
+
// (Re)resolve the plugged scrollable and observe the nodes whose size
|
|
373
375
|
// feeds the natural height — content growth inside a bounded scroller is
|
|
374
376
|
// invisible to the sheet's own layout (mirrors native's contentSize
|
|
375
377
|
// observation). Resolves the content node live: the layout-branch swap
|
|
@@ -379,10 +381,8 @@ const TrueSheetComponent = forwardRef<TrueSheetMethods, TrueSheetProps>((props,
|
|
|
379
381
|
const headerEl = getDOMElement(headerElRef.current);
|
|
380
382
|
|
|
381
383
|
// Skip mutations that don't change the observed topology — e.g. a
|
|
382
|
-
// virtualized list mounting rows inside the
|
|
383
|
-
//
|
|
384
|
-
// resolves computed styles) on every scroll frame. Size changes are
|
|
385
|
-
// already covered by the ResizeObserver.
|
|
384
|
+
// virtualized list mounting rows inside the plugged scroller. Size
|
|
385
|
+
// changes are already covered by the ResizeObserver.
|
|
386
386
|
if (
|
|
387
387
|
observed &&
|
|
388
388
|
observed.contentEl === contentEl &&
|
|
@@ -394,9 +394,10 @@ const TrueSheetComponent = forwardRef<TrueSheetMethods, TrueSheetProps>((props,
|
|
|
394
394
|
return;
|
|
395
395
|
}
|
|
396
396
|
|
|
397
|
-
const
|
|
398
|
-
contentEl && contentEl.isConnected ?
|
|
399
|
-
|
|
397
|
+
const resolved =
|
|
398
|
+
contentEl && contentEl.isConnected ? getScrollableElement(scrollableRef?.current) : null;
|
|
399
|
+
const scroller = resolved?.isConnected ? resolved : null;
|
|
400
|
+
detectedScrollerRef.current = scroller;
|
|
400
401
|
setHasBoundedScrollable(scroller != null);
|
|
401
402
|
observed = scroller
|
|
402
403
|
? { contentEl, headerEl, scroller, scrollContent: scroller.firstElementChild }
|
|
@@ -429,7 +430,7 @@ const TrueSheetComponent = forwardRef<TrueSheetMethods, TrueSheetProps>((props,
|
|
|
429
430
|
mutationObserver?.disconnect();
|
|
430
431
|
resizeObserver?.disconnect();
|
|
431
432
|
};
|
|
432
|
-
}, [isOpen, hasAutoDetent, measureNaturalHeight]);
|
|
433
|
+
}, [isOpen, hasAutoDetent, measureNaturalHeight, scrollableRef]);
|
|
433
434
|
|
|
434
435
|
// Below the last detent a vertical touch pan moves the sheet, not the
|
|
435
436
|
// content — `[data-vaul-scroll-locked]` disables vertical touch panning on
|
|
@@ -1069,12 +1070,25 @@ const TrueSheetComponent = forwardRef<TrueSheetMethods, TrueSheetProps>((props,
|
|
|
1069
1070
|
// Lift content above iOS home indicator / bottom safe area when enabled.
|
|
1070
1071
|
// A relative footer owns the inset instead (see resolvedFooterStyle); an
|
|
1071
1072
|
// absolute footer floats over the content, so the content keeps its lift.
|
|
1073
|
+
// A plugged scrollable keeps the lift too (contentInsetAdjustmentBehavior,
|
|
1074
|
+
// default on) — disable it to scroll edge-to-edge behind the indicator
|
|
1075
|
+
// with user-applied content padding.
|
|
1072
1076
|
paddingBottom:
|
|
1073
|
-
insetAdjustment === 'automatic' &&
|
|
1077
|
+
insetAdjustment === 'automatic' &&
|
|
1078
|
+
!(footerOwnsInset && !absoluteFooter) &&
|
|
1079
|
+
(!scrollableRef || (scrollableOptions?.contentInsetAdjustmentBehavior ?? true))
|
|
1074
1080
|
? 'env(safe-area-inset-bottom, 0px)'
|
|
1075
1081
|
: 0,
|
|
1076
1082
|
}),
|
|
1077
|
-
[
|
|
1083
|
+
[
|
|
1084
|
+
backgroundColor,
|
|
1085
|
+
effectiveCornerRadius,
|
|
1086
|
+
insetAdjustment,
|
|
1087
|
+
footerOwnsInset,
|
|
1088
|
+
absoluteFooter,
|
|
1089
|
+
scrollableRef,
|
|
1090
|
+
scrollableOptions,
|
|
1091
|
+
]
|
|
1078
1092
|
);
|
|
1079
1093
|
|
|
1080
1094
|
const defaultGrabberColor =
|
|
@@ -1254,7 +1268,8 @@ const TrueSheetComponent = forwardRef<TrueSheetMethods, TrueSheetProps>((props,
|
|
|
1254
1268
|
{/* Content lays out naturally like native — fill only for auto
|
|
1255
1269
|
detents with a plugged scrollable, where natural layout is
|
|
1256
1270
|
circular (sheet height derives from the scroll content size).
|
|
1257
|
-
|
|
1271
|
+
Unlike native, CSS won't cap the content to the container
|
|
1272
|
+
(no fit-content flex basis), so the fill is still needed here. */}
|
|
1258
1273
|
<View
|
|
1259
1274
|
ref={contentRef}
|
|
1260
1275
|
style={hasAutoDetent && hasBoundedScrollable ? [contentFillStyle, style] : style}
|
|
@@ -6,7 +6,7 @@ export interface NativeProps extends ViewProps {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
// interfaceOnly: shadow node/state/descriptor are custom (common/cpp) so the
|
|
9
|
-
// content can be bounded to the container when a ScrollView is
|
|
9
|
+
// content can be bounded to the container when a ScrollView is detected
|
|
10
10
|
export default codegenNativeComponent<NativeProps>('TrueSheetContentView', {
|
|
11
11
|
interfaceOnly: true,
|
|
12
12
|
});
|
|
@@ -35,7 +35,9 @@ type BlurOptionsType = Readonly<{
|
|
|
35
35
|
type ScrollEdgeEffect = 'automatic' | 'hard' | 'soft' | 'hidden';
|
|
36
36
|
|
|
37
37
|
type ScrollableOptionsType = Readonly<{
|
|
38
|
+
contentInsetAdjustmentBehavior?: WithDefault<boolean, true>;
|
|
38
39
|
keyboardScrollOffset?: WithDefault<Double, 0>;
|
|
40
|
+
keyboardOffset?: WithDefault<Double, 0>;
|
|
39
41
|
scrollingExpandsSheet?: WithDefault<boolean, true>;
|
|
40
42
|
topScrollEdgeEffect?: WithDefault<ScrollEdgeEffect, 'hidden'>;
|
|
41
43
|
bottomScrollEdgeEffect?: WithDefault<ScrollEdgeEffect, 'hidden'>;
|
|
@@ -122,6 +124,8 @@ export interface NativeProps extends ViewProps {
|
|
|
122
124
|
draggable?: WithDefault<boolean, true>;
|
|
123
125
|
dimmed?: WithDefault<boolean, true>;
|
|
124
126
|
initialDetentAnimated?: WithDefault<boolean, true>;
|
|
127
|
+
// React tag of the scrollable component within the content (see scrollableRef)
|
|
128
|
+
scrollableHandle?: WithDefault<Int32, -1>;
|
|
125
129
|
scrollableOptions?: ScrollableOptionsType;
|
|
126
130
|
headerOptions?: HeaderOptionsType;
|
|
127
131
|
footerOptions?: FooterOptionsType;
|