1import { useId, useState, type ReactNode } from "react";
2import { Platform, View } from "react-native";
3import { FormSheet, Screen, ScreenStack, ScreenStackHeaderConfig } from "react-native-screens";
4import { useResolveClassNames, withUniwind } from "uniwind";
5
6import { AndroidSheetHeader } from "./AndroidScreenHeader";
7import { nativeHeaderScrollEdgeEffects } from "../native/StackHeader";
8
9const HEADER_SCROLL_EDGE_EFFECTS = nativeHeaderScrollEdgeEffects(Platform.OS, Platform.Version);
10const NativeScreen = withUniwind(Screen);
11const NativeHeader = withUniwind(ScreenStackHeaderConfig, {
12 color: { fromClassName: "tintColorClassName", styleProperty: "accentColor" },
13 titleColor: { fromClassName: "titleColorClassName", styleProperty: "accentColor" },
14});
15
16/** Native presentation for local context whose owner supplies its dismissal callback. */
17export function AppSheet(props: {
18 readonly title: string;
19 readonly children: ReactNode;
20 readonly onClose: () => void;
21}) {
22 const containerStyle = useResolveClassNames("bg-sheet");
23 const screenId = useId();
24 const [isOpen, setIsOpen] = useState(true);
25 const close = () => setIsOpen(false);
26
27 return (
28 <FormSheet
29 isOpen={isOpen}
30 detents={[0.5, 0.9]}
31 prefersGrabberVisible
32 nativeContainerStyle={containerStyle}
33 onDismiss={props.onClose}
34 onNativeDismiss={props.onClose}
35 >
36 <View collapsable={false} className="flex-1 bg-sheet">
37 {Platform.OS === "ios" ? (
38 <ScreenStack style={{ flex: 1 }}>
39 <NativeScreen
40 activityState={2}
41 enabled
42 isNativeStack
43 screenId={`app-sheet-${screenId}`}
44 scrollEdgeEffects={HEADER_SCROLL_EDGE_EFFECTS}
45 className="flex-1 bg-sheet"
46 >
47 {props.children}
48 <NativeHeader
49 backgroundColor="rgba(0,0,0,0)"
50 tintColorClassName="accent-foreground"
51 hideBackButton
52 hideShadow={false}
53 title={props.title}
54 titleColorClassName="accent-foreground"
55 titleFontSize={18}
56 titleFontWeight="800"
57 translucent
58 headerRightBarButtonItems={[
59 {
60 type: "button",
61 title: "Done",
62 variant: "done",
63 accessibilityLabel: `Close ${props.title}`,
64 identifier: `app-sheet-done-${screenId}`,
65 onPress: close,
66 },
67 ]}
68 />
69 </NativeScreen>
70 </ScreenStack>
71 ) : (
72 <>
73 <AndroidSheetHeader title={props.title} onBack={close} />
74 {props.children}
75 </>
76 )}
77 </View>
78 </FormSheet>
79 );
80}