diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/components/Dialog/index.tsx | 85 | ||||
-rw-r--r-- | src/components/FullWindowOverlay.ios.tsx | 1 | ||||
-rw-r--r-- | src/components/FullWindowOverlay.tsx | 1 | ||||
-rw-r--r-- | src/view/com/composer/Composer.tsx | 226 | ||||
-rw-r--r-- | src/view/com/composer/ComposerReplyTo.tsx | 6 | ||||
-rw-r--r-- | src/view/com/composer/threadgate/ThreadgateBtn.tsx | 5 | ||||
-rw-r--r-- | src/view/com/modals/Modal.tsx | 41 | ||||
-rw-r--r-- | src/view/com/modals/Threadgate.tsx | 21 | ||||
-rw-r--r-- | src/view/com/util/BottomSheetCustomBackdrop.tsx | 4 | ||||
-rw-r--r-- | src/view/com/util/forms/DropdownButton.tsx | 35 | ||||
-rw-r--r-- | src/view/shell/Composer.tsx | 63 |
11 files changed, 268 insertions, 220 deletions
diff --git a/src/components/Dialog/index.tsx b/src/components/Dialog/index.tsx index f32e0e79e..158244c8e 100644 --- a/src/components/Dialog/index.tsx +++ b/src/components/Dialog/index.tsx @@ -32,6 +32,7 @@ import { DialogOuterProps, } from '#/components/Dialog/types' import {createInput} from '#/components/forms/TextField' +import {FullWindowOverlay} from '#/components/FullWindowOverlay' import {Portal} from '#/components/Portal' export {useDialogContext, useDialogControl} from '#/components/Dialog/context' @@ -170,47 +171,49 @@ export function Outer({ return ( isOpen && ( <Portal> - <View - // iOS - accessibilityViewIsModal - // Android - importantForAccessibility="yes" - style={[a.absolute, a.inset_0]} - testID={testID} - onTouchMove={() => Keyboard.dismiss()}> - <BottomSheet - enableDynamicSizing={!hasSnapPoints} - enablePanDownToClose - keyboardBehavior="interactive" - android_keyboardInputMode="adjustResize" - keyboardBlurBehavior="restore" - topInset={insets.top} - {...sheetOptions} - snapPoints={sheetOptions.snapPoints || ['100%']} - ref={sheet} - index={openIndex} - backgroundStyle={{backgroundColor: 'transparent'}} - backdropComponent={Backdrop} - handleIndicatorStyle={{backgroundColor: t.palette.primary_500}} - handleStyle={{display: 'none'}} - onClose={onCloseAnimationComplete}> - <Context.Provider value={context}> - <View - style={[ - a.absolute, - a.inset_0, - t.atoms.bg, - { - borderTopLeftRadius: 40, - borderTopRightRadius: 40, - height: Dimensions.get('window').height * 2, - }, - ]} - /> - {children} - </Context.Provider> - </BottomSheet> - </View> + <FullWindowOverlay> + <View + // iOS + accessibilityViewIsModal + // Android + importantForAccessibility="yes" + style={[a.absolute, a.inset_0]} + testID={testID} + onTouchMove={() => Keyboard.dismiss()}> + <BottomSheet + enableDynamicSizing={!hasSnapPoints} + enablePanDownToClose + keyboardBehavior="interactive" + android_keyboardInputMode="adjustResize" + keyboardBlurBehavior="restore" + topInset={insets.top} + {...sheetOptions} + snapPoints={sheetOptions.snapPoints || ['100%']} + ref={sheet} + index={openIndex} + backgroundStyle={{backgroundColor: 'transparent'}} + backdropComponent={Backdrop} + handleIndicatorStyle={{backgroundColor: t.palette.primary_500}} + handleStyle={{display: 'none'}} + onClose={onCloseAnimationComplete}> + <Context.Provider value={context}> + <View + style={[ + a.absolute, + a.inset_0, + t.atoms.bg, + { + borderTopLeftRadius: 40, + borderTopRightRadius: 40, + height: Dimensions.get('window').height * 2, + }, + ]} + /> + {children} + </Context.Provider> + </BottomSheet> + </View> + </FullWindowOverlay> </Portal> ) ) diff --git a/src/components/FullWindowOverlay.ios.tsx b/src/components/FullWindowOverlay.ios.tsx new file mode 100644 index 000000000..db516c658 --- /dev/null +++ b/src/components/FullWindowOverlay.ios.tsx @@ -0,0 +1 @@ +export {FullWindowOverlay} from 'react-native-screens' diff --git a/src/components/FullWindowOverlay.tsx b/src/components/FullWindowOverlay.tsx new file mode 100644 index 000000000..c9bdb6e72 --- /dev/null +++ b/src/components/FullWindowOverlay.tsx @@ -0,0 +1 @@ +export {Fragment as FullWindowOverlay} from 'react' diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index c8bb8d726..b1c020a10 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -181,12 +181,7 @@ export const ComposePost = observer(function ComposePost({ borderColor: interpolateColor( hasScrolled.value, [0, 1], - [ - 'transparent', - isWeb - ? t.atoms.border_contrast_low.borderColor - : t.atoms.border_contrast_high.borderColor, - ], + ['transparent', t.atoms.border_contrast_medium.borderColor], ), } }) @@ -405,106 +400,112 @@ export const ComposePost = observer(function ComposePost({ <KeyboardAvoidingView testID="composePostView" behavior="padding" - style={s.flex1} - keyboardVerticalOffset={replyTo ? 60 : isAndroid ? 120 : 100}> - <View style={[s.flex1, viewStyles]} aria-modal accessibilityViewIsModal> + style={a.flex_1} + keyboardVerticalOffset={replyTo ? 120 : isAndroid ? 180 : 150}> + <View + style={[a.flex_1, viewStyles]} + aria-modal + accessibilityViewIsModal> <Animated.View style={[ styles.topbar, topBarAnimatedStyle, isWeb && isTabletOrDesktop && styles.topbarDesktop, ]}> - <TouchableOpacity - testID="composerDiscardButton" - onPress={onPressCancel} - onAccessibilityEscape={onPressCancel} - accessibilityRole="button" - accessibilityLabel={_(msg`Cancel`)} - accessibilityHint={_( - msg`Closes post composer and discards post draft`, + <View style={styles.topbarInner}> + <TouchableOpacity + testID="composerDiscardButton" + onPress={onPressCancel} + onAccessibilityEscape={onPressCancel} + accessibilityRole="button" + accessibilityLabel={_(msg`Cancel`)} + accessibilityHint={_( + msg`Closes post composer and discards post draft`, + )} + hitSlop={HITSLOP_10}> + <Text style={[pal.link, s.f18]}> + <Trans>Cancel</Trans> + </Text> + </TouchableOpacity> + <View style={a.flex_1} /> + {isProcessing ? ( + <> + <Text style={pal.textLight}>{processingState}</Text> + <View style={styles.postBtn}> + <ActivityIndicator /> + </View> + </> + ) : ( + <> + <LabelsBtn + labels={labels} + onChange={setLabels} + hasMedia={hasMedia} + /> + {canPost ? ( + <TouchableOpacity + testID="composerPublishBtn" + onPress={onPressPublish} + accessibilityRole="button" + accessibilityLabel={ + replyTo ? _(msg`Publish reply`) : _(msg`Publish post`) + } + accessibilityHint=""> + <LinearGradient + colors={[ + gradients.blueLight.start, + gradients.blueLight.end, + ]} + start={{x: 0, y: 0}} + end={{x: 1, y: 1}} + style={styles.postBtn}> + <Text style={[s.white, s.f16, s.bold]}> + {replyTo ? ( + <Trans context="action">Reply</Trans> + ) : ( + <Trans context="action">Post</Trans> + )} + </Text> + </LinearGradient> + </TouchableOpacity> + ) : ( + <View style={[styles.postBtn, pal.btn]}> + <Text style={[pal.textLight, s.f16, s.bold]}> + <Trans context="action">Post</Trans> + </Text> + </View> + )} + </> )} - hitSlop={HITSLOP_10}> - <Text style={[pal.link, s.f18]}> - <Trans>Cancel</Trans> - </Text> - </TouchableOpacity> - <View style={s.flex1} /> - {isProcessing ? ( - <> - <Text style={pal.textLight}>{processingState}</Text> - <View style={styles.postBtn}> - <ActivityIndicator /> + </View> + + {isAltTextRequiredAndMissing && ( + <View style={[styles.reminderLine, pal.viewLight]}> + <View style={styles.errorIcon}> + <FontAwesomeIcon + icon="exclamation" + style={{color: colors.red4}} + size={10} + /> </View> - </> - ) : ( - <> - <LabelsBtn - labels={labels} - onChange={setLabels} - hasMedia={hasMedia} - /> - {canPost ? ( - <TouchableOpacity - testID="composerPublishBtn" - onPress={onPressPublish} - accessibilityRole="button" - accessibilityLabel={ - replyTo ? _(msg`Publish reply`) : _(msg`Publish post`) - } - accessibilityHint=""> - <LinearGradient - colors={[ - gradients.blueLight.start, - gradients.blueLight.end, - ]} - start={{x: 0, y: 0}} - end={{x: 1, y: 1}} - style={styles.postBtn}> - <Text style={[s.white, s.f16, s.bold]}> - {replyTo ? ( - <Trans context="action">Reply</Trans> - ) : ( - <Trans context="action">Post</Trans> - )} - </Text> - </LinearGradient> - </TouchableOpacity> - ) : ( - <View style={[styles.postBtn, pal.btn]}> - <Text style={[pal.textLight, s.f16, s.bold]}> - <Trans context="action">Post</Trans> - </Text> - </View> - )} - </> - )} - </Animated.View> - {isAltTextRequiredAndMissing && ( - <View style={[styles.reminderLine, pal.viewLight]}> - <View style={styles.errorIcon}> - <FontAwesomeIcon - icon="exclamation" - style={{color: colors.red4}} - size={10} - /> + <Text style={[pal.text, a.flex_1]}> + <Trans>One or more images is missing alt text.</Trans> + </Text> </View> - <Text style={[pal.text, s.flex1]}> - <Trans>One or more images is missing alt text.</Trans> - </Text> - </View> - )} - {error !== '' && ( - <View style={styles.errorLine}> - <View style={styles.errorIcon}> - <FontAwesomeIcon - icon="exclamation" - style={{color: colors.red4}} - size={10} - /> + )} + {error !== '' && ( + <View style={styles.errorLine}> + <View style={styles.errorIcon}> + <FontAwesomeIcon + icon="exclamation" + style={{color: colors.red4}} + size={10} + /> + </View> + <Text style={[s.red4, a.flex_1]}>{error}</Text> </View> - <Text style={[s.red4, s.flex1]}>{error}</Text> - </View> - )} + )} + </Animated.View> <Animated.ScrollView onScroll={scrollHandler} style={styles.scrollView} @@ -576,7 +577,12 @@ export const ComposePost = observer(function ComposePost({ {replyTo ? null : ( <ThreadgateBtn threadgate={threadgate} onChange={setThreadgate} /> )} - <View style={[pal.border, styles.bottomBar]}> + <View + style={[ + t.atoms.bg, + t.atoms.border_contrast_medium, + styles.bottomBar, + ]}> <View style={[a.flex_row, a.align_center, a.gap_xs]}> <SelectPhotoBtn gallery={gallery} disabled={!canSelectImages} /> <OpenCameraBtn gallery={gallery} disabled={!canSelectImages} /> @@ -598,7 +604,7 @@ export const ComposePost = observer(function ComposePost({ </Button> ) : null} </View> - <View style={s.flex1} /> + <View style={a.flex_1} /> <SelectLangBtn /> <CharProgress count={graphemeLength} /> </View> @@ -621,11 +627,6 @@ export function useComposerCancelRef() { const styles = StyleSheet.create({ topbar: { - flexDirection: 'row', - alignItems: 'center', - marginHorizontal: 16, - height: 54, - gap: 4, borderBottomWidth: StyleSheet.hairlineWidth, }, topbarDesktop: { @@ -633,6 +634,13 @@ const styles = StyleSheet.create({ paddingBottom: 10, height: 50, }, + topbarInner: { + flexDirection: 'row', + alignItems: 'center', + paddingHorizontal: 16, + height: 54, + gap: 4, + }, postBtn: { borderRadius: 20, paddingHorizontal: 20, @@ -643,19 +651,19 @@ const styles = StyleSheet.create({ flexDirection: 'row', backgroundColor: colors.red1, borderRadius: 6, - marginHorizontal: 15, + marginHorizontal: 16, paddingHorizontal: 8, paddingVertical: 6, - marginVertical: 6, + marginBottom: 8, }, reminderLine: { flexDirection: 'row', alignItems: 'center', borderRadius: 6, - marginHorizontal: 15, + marginHorizontal: 16, paddingHorizontal: 8, paddingVertical: 6, - marginBottom: 6, + marginBottom: 8, }, errorIcon: { borderWidth: hairlineWidth, @@ -690,8 +698,8 @@ const styles = StyleSheet.create({ bottomBar: { flexDirection: 'row', paddingVertical: 4, - paddingLeft: 15, - paddingRight: 20, + paddingLeft: 8, + paddingRight: 16, alignItems: 'center', borderTopWidth: hairlineWidth, }, diff --git a/src/view/com/composer/ComposerReplyTo.tsx b/src/view/com/composer/ComposerReplyTo.tsx index 902d60a46..6b38caff0 100644 --- a/src/view/com/composer/ComposerReplyTo.tsx +++ b/src/view/com/composer/ComposerReplyTo.tsx @@ -10,7 +10,6 @@ import { import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' -import {isWeb} from '#/platform/detection' import {sanitizeDisplayName} from 'lib/strings/display-names' import {sanitizeHandle} from 'lib/strings/handles' import {ComposerOptsPostRef} from 'state/shell/composer' @@ -76,10 +75,7 @@ export function ComposerReplyTo({replyTo}: {replyTo: ComposerOptsPostRef}) { return ( <Pressable - style={[ - isWeb ? t.atoms.border_contrast_low : t.atoms.border_contrast_high, - styles.replyToLayout, - ]} + style={[t.atoms.border_contrast_medium, styles.replyToLayout]} onPress={onPress} accessibilityRole="button" accessibilityLabel={_( diff --git a/src/view/com/composer/threadgate/ThreadgateBtn.tsx b/src/view/com/composer/threadgate/ThreadgateBtn.tsx index df2a31e2b..afc9f5bfa 100644 --- a/src/view/com/composer/threadgate/ThreadgateBtn.tsx +++ b/src/view/com/composer/threadgate/ThreadgateBtn.tsx @@ -7,7 +7,7 @@ import {isNative} from '#/platform/detection' import {useModalControls} from '#/state/modals' import {ThreadgateSetting} from '#/state/queries/threadgate' import {useAnalytics} from 'lib/analytics/analytics' -import {atoms as a} from '#/alf' +import {atoms as a, useTheme} from '#/alf' import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {CircleBanSign_Stroke2_Corner0_Rounded as CircleBanSign} from '#/components/icons/CircleBanSign' import {Earth_Stroke2_Corner0_Rounded as Earth} from '#/components/icons/Globe' @@ -22,6 +22,7 @@ export function ThreadgateBtn({ }) { const {track} = useAnalytics() const {_} = useLingui() + const t = useTheme() const {openModal} = useModalControls() const onPress = () => { @@ -45,7 +46,7 @@ export function ThreadgateBtn({ : _(msg`Some people can reply`) return ( - <View style={[a.flex_row, a.pb_sm, a.px_md]}> + <View style={[a.flex_row, a.py_xs, a.px_sm, t.atoms.bg]}> <Button variant="solid" color="secondary" diff --git a/src/view/com/modals/Modal.tsx b/src/view/com/modals/Modal.tsx index 3491b94e3..eb9666405 100644 --- a/src/view/com/modals/Modal.tsx +++ b/src/view/com/modals/Modal.tsx @@ -1,10 +1,11 @@ -import React, {useEffect, useRef} from 'react' +import React, {Fragment, useEffect, useRef} from 'react' import {StyleSheet} from 'react-native' import {SafeAreaView} from 'react-native-safe-area-context' import BottomSheet from '@discord/bottom-sheet/src' import {useModalControls, useModals} from '#/state/modals' import {usePalette} from 'lib/hooks/usePalette' +import {FullWindowOverlay} from '#/components/FullWindowOverlay' import {KeyboardPadding} from '#/components/KeyboardPadding' import {createCustomBackdrop} from '../util/BottomSheetCustomBackdrop' import * as AddAppPassword from './AddAppPasswords' @@ -127,24 +128,28 @@ export function ModalsContainer() { ) } + const Container = activeModal ? FullWindowOverlay : Fragment + return ( - <BottomSheet - ref={bottomSheetRef} - snapPoints={snapPoints} - handleHeight={HANDLE_HEIGHT} - index={isModalActive ? 0 : -1} - enablePanDownToClose - android_keyboardInputMode="adjustResize" - keyboardBlurBehavior="restore" - backdropComponent={ - isModalActive ? createCustomBackdrop(onClose) : undefined - } - handleIndicatorStyle={{backgroundColor: pal.text.color}} - handleStyle={[styles.handle, pal.view]} - onChange={onBottomSheetChange}> - {element} - <KeyboardPadding /> - </BottomSheet> + <Container> + <BottomSheet + ref={bottomSheetRef} + snapPoints={snapPoints} + handleHeight={HANDLE_HEIGHT} + index={isModalActive ? 0 : -1} + enablePanDownToClose + android_keyboardInputMode="adjustResize" + keyboardBlurBehavior="restore" + backdropComponent={ + isModalActive ? createCustomBackdrop(onClose) : undefined + } + handleIndicatorStyle={{backgroundColor: pal.text.color}} + handleStyle={[styles.handle, pal.view]} + onChange={onBottomSheetChange}> + {element} + <KeyboardPadding /> + </BottomSheet> + </Container> ) } diff --git a/src/view/com/modals/Threadgate.tsx b/src/view/com/modals/Threadgate.tsx index 0e49fc2f3..a2e9f391c 100644 --- a/src/view/com/modals/Threadgate.tsx +++ b/src/view/com/modals/Threadgate.tsx @@ -7,18 +7,19 @@ import { View, ViewStyle, } from 'react-native' -import {Text} from '../util/text/Text' -import {s, colors} from 'lib/styles' -import {usePalette} from 'lib/hooks/usePalette' -import {isWeb} from 'platform/detection' -import {ScrollView} from 'view/com/modals/util' -import {Trans, msg} from '@lingui/macro' +import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' +import isEqual from 'lodash.isequal' + import {useModalControls} from '#/state/modals' -import {ThreadgateSetting} from '#/state/queries/threadgate' import {useMyListsQuery} from '#/state/queries/my-lists' -import isEqual from 'lodash.isequal' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import {ThreadgateSetting} from '#/state/queries/threadgate' +import {usePalette} from 'lib/hooks/usePalette' +import {colors, s} from 'lib/styles' +import {isWeb} from 'platform/detection' +import {ScrollView} from 'view/com/modals/util' +import {Text} from '../util/text/Text' export const snapPoints = ['60%'] @@ -155,7 +156,7 @@ function Selectable({ accessibilityLabel={label} accessibilityHint="" style={[styles.selectable, pal.border, pal.view, style]}> - <Text type="xl" style={[pal.text]}> + <Text type="lg" style={[pal.text]}> {label} </Text> {isSelected ? ( diff --git a/src/view/com/util/BottomSheetCustomBackdrop.tsx b/src/view/com/util/BottomSheetCustomBackdrop.tsx index 0d15c5e55..25e882e87 100644 --- a/src/view/com/util/BottomSheetCustomBackdrop.tsx +++ b/src/view/com/util/BottomSheetCustomBackdrop.tsx @@ -1,7 +1,7 @@ import React, {useMemo} from 'react' import {TouchableWithoutFeedback} from 'react-native' import Animated, { - Extrapolate, + Extrapolation, interpolate, useAnimatedStyle, } from 'react-native-reanimated' @@ -21,7 +21,7 @@ export function createCustomBackdrop( animatedIndex.value, // current snap index [-1, 0], // input range [0, 0.5], // output range - Extrapolate.CLAMP, + Extrapolation.CLAMP, ), })) diff --git a/src/view/com/util/forms/DropdownButton.tsx b/src/view/com/util/forms/DropdownButton.tsx index 14b97161d..bfbafcad9 100644 --- a/src/view/com/util/forms/DropdownButton.tsx +++ b/src/view/com/util/forms/DropdownButton.tsx @@ -2,7 +2,6 @@ import React, {PropsWithChildren, useMemo, useRef} from 'react' import { Dimensions, GestureResponderEvent, - Platform, StyleProp, StyleSheet, TouchableOpacity, @@ -11,8 +10,8 @@ import { View, ViewStyle, } from 'react-native' +import Animated, {FadeIn, FadeInDown, FadeInUp} from 'react-native-reanimated' import RootSiblings from 'react-native-root-siblings' -import {FullWindowOverlay} from 'react-native-screens' import {IconProp} from '@fortawesome/fontawesome-svg-core' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {msg} from '@lingui/macro' @@ -23,6 +22,8 @@ import {usePalette} from 'lib/hooks/usePalette' import {colors} from 'lib/styles' import {useTheme} from 'lib/ThemeContext' import {isWeb} from 'platform/detection' +import {native} from '#/alf' +import {FullWindowOverlay} from '#/components/FullWindowOverlay' import {Text} from '../text/Text' import {Button, ButtonType} from './Button' @@ -127,6 +128,7 @@ export function DropdownButton({ pageY, menuWidth, items.filter(v => !!v) as DropdownItem[], + openUpwards, ) }, ) @@ -181,6 +183,7 @@ function createDropdownMenu( pageY: number, width: number, items: DropdownItem[], + opensUpwards = false, ): RootSiblings { const onPressItem = (index: number) => { sibling.destroy() @@ -200,6 +203,7 @@ function createDropdownMenu( width={width} items={items} onPressItem={onPressItem} + openUpwards={opensUpwards} /> ), ) @@ -214,6 +218,7 @@ type DropDownItemProps = { width: number items: DropdownItem[] onPressItem: (index: number) => void + openUpwards: boolean } const DropdownItems = ({ @@ -224,6 +229,7 @@ const DropdownItems = ({ width, items, onPressItem, + openUpwards, }: DropDownItemProps) => { const pal = usePalette('default') const theme = useTheme() @@ -242,13 +248,14 @@ const DropdownItems = ({ // - (On mobile) be buttons by default, accept `label` and `nativeID` // props, and always have an explicit label return ( - <Wrapper> + <FullWindowOverlay> {/* This TouchableWithoutFeedback renders the background so if the user clicks outside, the dropdown closes */} <TouchableWithoutFeedback onPress={onOuterPress} accessibilityLabel={_(msg`Toggle dropdown`)} accessibilityHint=""> - <View + <Animated.View + entering={FadeIn} style={[ styles.bg, // On web we need to adjust the top and bottom relative to the scroll position @@ -264,7 +271,10 @@ const DropdownItems = ({ ]} /> </TouchableWithoutFeedback> - <View + <Animated.View + entering={native( + openUpwards ? FadeInDown.springify(1000) : FadeInUp.springify(1000), + )} style={[ styles.menu, {left: x, top: y, width}, @@ -306,18 +316,11 @@ const DropdownItems = ({ } return null })} - </View> - </Wrapper> + </Animated.View> + </FullWindowOverlay> ) } -// on iOS, due to formSheet presentation style, we need to render the overlay -// as a full screen overlay -const Wrapper = Platform.select({ - ios: FullWindowOverlay, - default: ({children}) => <>{children}</>, -}) - function isSep(item: DropdownItem): item is DropdownItemSeparator { return 'sep' in item && item.sep } @@ -333,14 +336,12 @@ const styles = StyleSheet.create({ position: 'absolute', left: 0, width: '100%', - backgroundColor: '#000', - opacity: 0.1, + backgroundColor: 'rgba(0, 0, 0, 0.1)', }, menu: { position: 'absolute', backgroundColor: '#fff', borderRadius: 14, - opacity: 1, paddingVertical: 6, }, menuItem: { diff --git a/src/view/shell/Composer.tsx b/src/view/shell/Composer.tsx index ce53ffc01..c80d7845b 100644 --- a/src/view/shell/Composer.tsx +++ b/src/view/shell/Composer.tsx @@ -1,5 +1,7 @@ import React, {useLayoutEffect} from 'react' import {Modal, View} from 'react-native' +import {GestureHandlerRootView} from 'react-native-gesture-handler' +import {RootSiblingParent} from 'react-native-root-siblings' import {StatusBar} from 'expo-status-bar' import * as SystemUI from 'expo-system-ui' import {observer} from 'mobx-react-lite' @@ -34,27 +36,56 @@ export const Composer = observer(function ComposerImpl({}: { animationType="slide" onRequestClose={() => ref.current?.onPressCancel()}> <View style={[t.atoms.bg, a.flex_1]}> - <LegacyModalProvider> - <PortalProvider> - <ComposePost - cancelRef={ref} - replyTo={state?.replyTo} - onPost={state?.onPost} - quote={state?.quote} - mention={state?.mention} - text={state?.text} - imageUris={state?.imageUris} - /> - <LegacyModalsContainer /> - <PortalOutlet /> - </PortalProvider> - </LegacyModalProvider> - {isIOS && <IOSModalBackground active={open} />} + <Providers open={open}> + <ComposePost + cancelRef={ref} + replyTo={state?.replyTo} + onPost={state?.onPost} + quote={state?.quote} + mention={state?.mention} + text={state?.text} + imageUris={state?.imageUris} + /> + </Providers> </View> </Modal> ) }) +function Providers({ + children, + open, +}: { + children: React.ReactNode + open: boolean +}) { + // on iOS, it's a native formSheet. We use FullWindowOverlay to make + // the dialogs appear over it + if (isIOS) { + return ( + <> + {children} + <IOSModalBackground active={open} /> + </> + ) + } else { + // on Android we just nest the dialogs within it + return ( + <GestureHandlerRootView style={a.flex_1}> + <RootSiblingParent> + <LegacyModalProvider> + <PortalProvider> + {children} + <LegacyModalsContainer /> + <PortalOutlet /> + </PortalProvider> + </LegacyModalProvider> + </RootSiblingParent> + </GestureHandlerRootView> + ) + } +} + // Generally, the backdrop of the app is the theme color, but when this is open // we want it to be black due to the modal being a form sheet. function IOSModalBackground({active}: {active: boolean}) { |