Scrollable dialogs

This commit is contained in:
Eric Bailey
2024-01-15 15:58:57 -06:00
parent 94d31d4cc5
commit 048ce0244f
8 changed files with 67 additions and 52 deletions
+1 -5
View File
@@ -41,10 +41,7 @@ import {
import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unread' import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unread'
import * as persisted from '#/state/persisted' import * as persisted from '#/state/persisted'
import {Splash} from '#/Splash' import {Splash} from '#/Splash'
import { import {Provider as PortalProvider} from '#/components/Portal'
Provider as PortalProvider,
Outlet as PortalOutlet,
} from '#/components/Portal'
SplashScreen.preventAutoHideAsync() SplashScreen.preventAutoHideAsync()
@@ -80,7 +77,6 @@ function InnerApp() {
<GestureHandlerRootView style={s.h100pct}> <GestureHandlerRootView style={s.h100pct}>
<TestCtrls /> <TestCtrls />
<Shell /> <Shell />
<PortalOutlet />
</GestureHandlerRootView> </GestureHandlerRootView>
</RootSiblingParent> </RootSiblingParent>
</ThemeProvider> </ThemeProvider>
+1 -5
View File
@@ -30,10 +30,7 @@ import {
} from 'state/session' } from 'state/session'
import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unread' import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unread'
import * as persisted from '#/state/persisted' import * as persisted from '#/state/persisted'
import { import {Provider as PortalProvider} from '#/components/Portal'
Provider as PortalProvider,
Outlet as PortalOutlet,
} from '#/components/Portal'
function InnerApp() { function InnerApp() {
const {isInitialLoad, currentAccount} = useSession() const {isInitialLoad, currentAccount} = useSession()
@@ -62,7 +59,6 @@ function InnerApp() {
<RootSiblingParent> <RootSiblingParent>
<SafeAreaProvider> <SafeAreaProvider>
<Shell /> <Shell />
<PortalOutlet />
</SafeAreaProvider> </SafeAreaProvider>
</RootSiblingParent> </RootSiblingParent>
<ToastContainer /> <ToastContainer />
+32 -18
View File
@@ -2,6 +2,7 @@ import React, {useImperativeHandle} from 'react'
import {View, Dimensions} from 'react-native' import {View, Dimensions} from 'react-native'
import BottomSheet, { import BottomSheet, {
BottomSheetBackdrop, BottomSheetBackdrop,
BottomSheetScrollView,
BottomSheetView, BottomSheetView,
} from '@gorhom/bottom-sheet' } from '@gorhom/bottom-sheet'
import {useSafeAreaInsets} from 'react-native-safe-area-context' import {useSafeAreaInsets} from 'react-native-safe-area-context'
@@ -16,13 +17,6 @@ import {
} from '#/components/Dialog/types' } from '#/components/Dialog/types'
import {Context} from '#/components/Dialog/context' import {Context} from '#/components/Dialog/context'
/**
* Exports
*/
export {
BottomSheetScrollView as ScrollView,
BottomSheetTextInput as TextInput,
} from '@gorhom/bottom-sheet'
export {useDialogControl, useDialogContext} from '#/components/Dialog/context' export {useDialogControl, useDialogContext} from '#/components/Dialog/context'
export * from '#/components/Dialog/types' export * from '#/components/Dialog/types'
@@ -34,6 +28,8 @@ export function Outer({
}: React.PropsWithChildren<DialogOuterProps>) { }: React.PropsWithChildren<DialogOuterProps>) {
const t = useTheme() const t = useTheme()
const sheet = React.useRef<BottomSheet>(null) const sheet = React.useRef<BottomSheet>(null)
const sheetOptions = nativeOptions?.sheet || {}
const hasSnapPoints = !!sheetOptions.snapPoints
const open = React.useCallback<DialogControlProps['open']>((i = 0) => { const open = React.useCallback<DialogControlProps['open']>((i = 0) => {
sheet.current?.snapToIndex(i) sheet.current?.snapToIndex(i)
@@ -58,15 +54,15 @@ export function Outer({
return ( return (
<Portal> <Portal>
<BottomSheet <BottomSheet
enableDynamicSizing enableDynamicSizing={!hasSnapPoints}
enablePanDownToClose enablePanDownToClose
keyboardBehavior="interactive" keyboardBehavior="interactive"
android_keyboardInputMode="adjustResize" android_keyboardInputMode="adjustResize"
keyboardBlurBehavior="restore" keyboardBlurBehavior="restore"
{...(nativeOptions?.sheet || {})} {...sheetOptions}
ref={sheet} ref={sheet}
index={-1} index={-1}
backgroundStyle={{backgroundColor: 'transparent'}} backgroundStyle={{backgroundColor: t.atoms.bg.backgroundColor}}
backdropComponent={props => ( backdropComponent={props => (
<BottomSheetBackdrop <BottomSheetBackdrop
appearsOnIndex={0} appearsOnIndex={0}
@@ -77,7 +73,6 @@ export function Outer({
handleIndicatorStyle={{backgroundColor: t.palette.primary_500}} handleIndicatorStyle={{backgroundColor: t.palette.primary_500}}
handleStyle={{display: 'none'}} handleStyle={{display: 'none'}}
onClose={onClose}> onClose={onClose}>
<BottomSheetView>
<Context.Provider value={context}> <Context.Provider value={context}>
<View <View
style={[ style={[
@@ -93,7 +88,6 @@ export function Outer({
/> />
{children} {children}
</Context.Provider> </Context.Provider>
</BottomSheetView>
</BottomSheet> </BottomSheet>
</Portal> </Portal>
) )
@@ -103,7 +97,7 @@ export function Outer({
export function Inner(props: DialogInnerProps) { export function Inner(props: DialogInnerProps) {
const insets = useSafeAreaInsets() const insets = useSafeAreaInsets()
return ( return (
<View <BottomSheetView
style={[ style={[
a.p_lg, a.p_lg,
a.pt_3xl, a.pt_3xl,
@@ -114,7 +108,26 @@ export function Inner(props: DialogInnerProps) {
}, },
]}> ]}>
{props.children} {props.children}
</View> </BottomSheetView>
)
}
export function ScrollableInner(props: DialogInnerProps) {
const insets = useSafeAreaInsets()
return (
<BottomSheetScrollView
style={[
a.flex_1, // main diff is this
a.p_lg,
a.pt_3xl,
{
borderTopLeftRadius: 40,
borderTopRightRadius: 40,
paddingBottom: insets.bottom + a.pb_5xl.paddingBottom,
},
]}>
{props.children}
</BottomSheetScrollView>
) )
} }
@@ -126,12 +139,13 @@ export function Handle() {
a.absolute, a.absolute,
a.rounded_sm, a.rounded_sm,
a.z_10, a.z_10,
t.atoms.bg_contrast_200,
{ {
top: 12, top: a.pt_lg.paddingTop,
width: 50, width: 35,
height: 6, height: 4,
alignSelf: 'center', alignSelf: 'center',
backgroundColor: t.palette.contrast_900,
opacity: 0.5,
}, },
]} ]}
/> />
+4 -3
View File
@@ -11,7 +11,6 @@ import {Button} from '#/components/Button'
import {DialogOuterProps, DialogInnerProps} from '#/components/Dialog/types' import {DialogOuterProps, DialogInnerProps} from '#/components/Dialog/types'
import {Context, useDialogContext} from '#/components/Dialog/context' import {Context, useDialogContext} from '#/components/Dialog/context'
export {ScrollView, TextInput} from 'react-native'
export {useDialogControl, useDialogContext} from '#/components/Dialog/context' export {useDialogControl, useDialogContext} from '#/components/Dialog/context'
export * from '#/components/Dialog/types' export * from '#/components/Dialog/types'
@@ -91,7 +90,7 @@ export function Outer({
style={[ style={[
web(a.fixed), web(a.fixed),
a.inset_0, a.inset_0,
t.atoms.bg_contrast_300, t.atoms.bg_contrast_100,
{opacity: 0.8}, {opacity: 0.8},
]} ]}
/> />
@@ -145,7 +144,7 @@ export function Inner({
a.border, a.border,
gtMobile ? a.p_xl : a.p_lg, gtMobile ? a.p_xl : a.p_lg,
t.atoms.bg, t.atoms.bg,
{maxWidth: 600, borderColor: t.palette.contrast_300}, {maxWidth: 600, borderColor: t.palette.contrast_200},
...(Array.isArray(style) ? style : [style || {}]), ...(Array.isArray(style) ? style : [style || {}]),
]}> ]}>
{children} {children}
@@ -154,6 +153,8 @@ export function Inner({
) )
} }
export const ScrollableInner = Inner
export function Handle() { export function Handle() {
return null return null
} }
+2 -1
View File
@@ -34,11 +34,12 @@ export function Outer({
return ( return (
<Dialog.Outer control={control}> <Dialog.Outer control={control}>
<Context.Provider value={context}> <Context.Provider value={context}>
<Dialog.Handle />
<Dialog.Inner <Dialog.Inner
accessibilityLabelledBy={titleId} accessibilityLabelledBy={titleId}
accessibilityDescribedBy={descriptionId} accessibilityDescribedBy={descriptionId}
style={{width: 'auto', maxWidth: 400}}> style={{width: 'auto', maxWidth: 400}}>
<Dialog.Handle />
{children} {children}
</Dialog.Inner> </Dialog.Inner>
</Context.Provider> </Context.Provider>
+8 -5
View File
@@ -45,15 +45,18 @@ export function Dialogs() {
</Prompt.Actions> </Prompt.Actions>
</Prompt.Outer> </Prompt.Outer>
<Dialog.Outer control={control}> <Dialog.Outer
<Dialog.Inner control={control}
accessibilityLabelledBy="dialog-title" nativeOptions={{sheet: {snapPoints: ['90%']}}}>
accessibilityDescribedBy="dialog-description">
<Dialog.Handle /> <Dialog.Handle />
<Dialog.ScrollableInner
accessibilityLabelledBy="dialog-title"
accessibilityDescribedBy="dialog-description">
<View style={[a.relative, a.gap_md, a.w_full]}> <View style={[a.relative, a.gap_md, a.w_full]}>
<H3 nativeID="dialog-title">Dialog</H3> <H3 nativeID="dialog-title">Dialog</H3>
<P nativeID="dialog-description">Description</P> <P nativeID="dialog-description">Description</P>
<View style={{height: 1000}} />
<View style={[a.flex_row, a.justify_end]}> <View style={[a.flex_row, a.justify_end]}>
<Button <Button
variant="outline" variant="outline"
@@ -66,7 +69,7 @@ export function Dialogs() {
</Button> </Button>
</View> </View>
</View> </View>
</Dialog.Inner> </Dialog.ScrollableInner>
</Dialog.Outer> </Dialog.Outer>
</> </>
) )
+2
View File
@@ -28,6 +28,7 @@ import {isAndroid} from 'platform/detection'
import {useSession} from '#/state/session' import {useSession} from '#/state/session'
import {useCloseAnyActiveElement} from '#/state/util' import {useCloseAnyActiveElement} from '#/state/util'
import * as notifications from 'lib/notifications/notifications' import * as notifications from 'lib/notifications/notifications'
import {Outlet as PortalOutlet} from '#/components/Portal'
function ShellInner() { function ShellInner() {
const isDrawerOpen = useIsDrawerOpen() const isDrawerOpen = useIsDrawerOpen()
@@ -94,6 +95,7 @@ function ShellInner() {
</View> </View>
<Composer winHeight={winDim.height} /> <Composer winHeight={winDim.height} />
<ModalsContainer /> <ModalsContainer />
<PortalOutlet />
<Lightbox /> <Lightbox />
</> </>
) )
+2
View File
@@ -15,6 +15,7 @@ import {useAuxClick} from 'lib/hooks/useAuxClick'
import {t} from '@lingui/macro' import {t} from '@lingui/macro'
import {useIsDrawerOpen, useSetDrawerOpen} from '#/state/shell' import {useIsDrawerOpen, useSetDrawerOpen} from '#/state/shell'
import {useCloseAllActiveElements} from '#/state/util' import {useCloseAllActiveElements} from '#/state/util'
import {Outlet as PortalOutlet} from '#/components/Portal'
function ShellInner() { function ShellInner() {
const isDrawerOpen = useIsDrawerOpen() const isDrawerOpen = useIsDrawerOpen()
@@ -41,6 +42,7 @@ function ShellInner() {
</View> </View>
<Composer winHeight={0} /> <Composer winHeight={0} />
<ModalsContainer /> <ModalsContainer />
<PortalOutlet />
<Lightbox /> <Lightbox />
{!isDesktop && isDrawerOpen && ( {!isDesktop && isDrawerOpen && (
<TouchableOpacity <TouchableOpacity