diff options
author | Samuel Newman <mozzius@protonmail.com> | 2024-05-30 07:44:20 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-30 05:44:20 +0100 |
commit | c4abaa1abcde54f15133b2e2b546f0d54a3a1d07 (patch) | |
tree | 996d1adcdc3ae1fa6a3c4a959e2a0df8d02235e6 /src | |
parent | fba4a9ca023b5acfe8ae51e1839d4e5e305ea967 (diff) | |
download | voidsky-c4abaa1abcde54f15133b2e2b546f0d54a3a1d07.tar.zst |
Use `<Modal>` for Composer (#3588)
* use <Modal> to display composer * trigger `onPressCancel` on modal cancel * remove android top padding * use light statusbar on ios * use KeyboardStickyView from r-n-keyboard-controller * make extra bottom padding ios-only * make cancelRef optional * scope legacy modals * don't change bg color on ios * use fullScreen instead of formSheet * adjust padding on keyboardaccessory to account for new buttons * Revert "use KeyboardStickyView from r-n-keyboard-controller" This reverts commit 426c812904f427bdd08107cffc32e4be1d9b83bc. * fix insets * tweaks and merge * revert 89f51c72 * nit * import keyboard provider --------- Co-authored-by: Hailey <me@haileyok.com> Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/alf/util/useColorModeTheme.ts | 6 | ||||
-rw-r--r-- | src/view/com/composer/Composer.tsx | 51 | ||||
-rw-r--r-- | src/view/com/composer/KeyboardAccessory.tsx | 34 | ||||
-rw-r--r-- | src/view/shell/Composer.tsx | 104 |
4 files changed, 99 insertions, 96 deletions
diff --git a/src/alf/util/useColorModeTheme.ts b/src/alf/util/useColorModeTheme.ts index 4f8921bf9..301c993dd 100644 --- a/src/alf/util/useColorModeTheme.ts +++ b/src/alf/util/useColorModeTheme.ts @@ -1,10 +1,10 @@ import React from 'react' import {ColorSchemeName, useColorScheme} from 'react-native' +import * as SystemUI from 'expo-system-ui' -import {useThemePrefs} from 'state/shell' import {isWeb} from 'platform/detection' -import {ThemeName, light, dark, dim} from '#/alf/themes' -import * as SystemUI from 'expo-system-ui' +import {useThemePrefs} from 'state/shell' +import {dark, dim, light, ThemeName} from '#/alf/themes' export function useColorModeTheme(): ThemeName { const colorScheme = useColorScheme() diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index 12e57c411..5746454c2 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -1,7 +1,13 @@ -import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react' +import React, { + useCallback, + useEffect, + useImperativeHandle, + useMemo, + useRef, + useState, +} from 'react' import { ActivityIndicator, - BackHandler, Keyboard, ScrollView, StyleSheet, @@ -79,6 +85,10 @@ import {TextInput, TextInputRef} from './text-input/TextInput' import {ThreadgateBtn} from './threadgate/ThreadgateBtn' import {useExternalLinkFetch} from './useExternalLinkFetch' +type CancelRef = { + onPressCancel: () => void +} + type Props = ComposerOpts export const ComposePost = observer(function ComposePost({ replyTo, @@ -88,7 +98,10 @@ export const ComposePost = observer(function ComposePost({ openPicker, text: initText, imageUris: initImageUris, -}: Props) { + cancelRef, +}: Props & { + cancelRef?: React.RefObject<CancelRef> +}) { const {currentAccount} = useSession() const agent = useAgent() const {data: currentProfile} = useProfileQuery({did: currentAccount!.did}) @@ -145,7 +158,7 @@ export const ComposePost = observer(function ComposePost({ () => ({ paddingBottom: isAndroid || (isIOS && !isKeyboardVisible) ? insets.bottom : 0, - paddingTop: isAndroid ? insets.top : isMobile ? 15 : 0, + paddingTop: isMobile && isWeb ? 15 : insets.top, }), [insets, isKeyboardVisible, isMobile], ) @@ -167,23 +180,8 @@ export const ComposePost = observer(function ComposePost({ discardPromptControl, onClose, ]) - // android back button - useEffect(() => { - if (!isAndroid) { - return - } - const backHandler = BackHandler.addEventListener( - 'hardwareBackPress', - () => { - onPressCancel() - return true - }, - ) - return () => { - backHandler.remove() - } - }, [onPressCancel]) + useImperativeHandle(cancelRef, () => ({onPressCancel})) // listen to escape key on desktop web const onEscape = useCallback( @@ -583,19 +581,18 @@ export const ComposePost = observer(function ComposePost({ ) }) +export function useComposerCancelRef() { + return useRef<CancelRef>(null) +} + const styles = StyleSheet.create({ - outer: { - flexDirection: 'column', - flex: 1, - height: '100%', - }, topbar: { flexDirection: 'row', alignItems: 'center', - paddingTop: 6, + marginTop: -14, paddingBottom: 4, paddingHorizontal: 20, - height: 55, + height: 50, gap: 4, }, topbarDesktop: { diff --git a/src/view/com/composer/KeyboardAccessory.tsx b/src/view/com/composer/KeyboardAccessory.tsx new file mode 100644 index 000000000..983a87dae --- /dev/null +++ b/src/view/com/composer/KeyboardAccessory.tsx @@ -0,0 +1,34 @@ +import React from 'react' +import {View} from 'react-native' +import {KeyboardStickyView} from 'react-native-keyboard-controller' +import {useSafeAreaInsets} from 'react-native-safe-area-context' + +import {isWeb} from '#/platform/detection' +import {atoms as a, useTheme} from '#/alf' + +export function KeyboardAccessory({children}: {children: React.ReactNode}) { + const t = useTheme() + const {bottom} = useSafeAreaInsets() + + const style = [ + a.flex_row, + a.py_xs, + a.pl_sm, + a.pr_xl, + a.align_center, + a.border_t, + t.atoms.border_contrast_medium, + t.atoms.bg, + ] + + // todo: when iPad support is added, it should also not use the KeyboardStickyView + if (isWeb) { + return <View style={style}>{children}</View> + } + + return ( + <KeyboardStickyView offset={{closed: -bottom}} style={style}> + {children} + </KeyboardStickyView> + ) +} diff --git a/src/view/shell/Composer.tsx b/src/view/shell/Composer.tsx index 1937fcb6e..17348a30c 100644 --- a/src/view/shell/Composer.tsx +++ b/src/view/shell/Composer.tsx @@ -1,77 +1,49 @@ -import React, {useEffect} from 'react' +import React from 'react' +import {Modal, View} from 'react-native' import {observer} from 'mobx-react-lite' -import {Animated, Easing, Platform, StyleSheet, View} from 'react-native' -import {ComposePost} from '../com/composer/Composer' + +import {Provider as LegacyModalProvider} from '#/state/modals' import {useComposerState} from 'state/shell/composer' -import {useAnimatedValue} from 'lib/hooks/useAnimatedValue' -import {usePalette} from 'lib/hooks/usePalette' +import {ModalsContainer as LegacyModalsContainer} from '#/view/com/modals/Modal' +import {useTheme} from '#/alf' +import { + Outlet as PortalOutlet, + Provider as PortalProvider, +} from '#/components/Portal' +import {ComposePost, useComposerCancelRef} from '../com/composer/Composer' -export const Composer = observer(function ComposerImpl({ - winHeight, -}: { +export const Composer = observer(function ComposerImpl({}: { winHeight: number }) { + const t = useTheme() const state = useComposerState() - const pal = usePalette('default') - const initInterp = useAnimatedValue(0) - - useEffect(() => { - if (state) { - Animated.timing(initInterp, { - toValue: 1, - duration: 300, - easing: Easing.out(Easing.exp), - useNativeDriver: true, - }).start() - } else { - initInterp.setValue(0) - } - }, [initInterp, state]) - const wrapperAnimStyle = { - transform: [ - { - translateY: initInterp.interpolate({ - inputRange: [0, 1], - outputRange: [winHeight, 0], - }), - }, - ], - } - - // rendering - // = - - if (!state) { - return <View /> - } + const ref = useComposerCancelRef() return ( - <Animated.View - style={[styles.wrapper, pal.view, wrapperAnimStyle]} + <Modal aria-modal - accessibilityViewIsModal> - <ComposePost - replyTo={state.replyTo} - onPost={state.onPost} - quote={state.quote} - mention={state.mention} - text={state.text} - imageUris={state.imageUris} - /> - </Animated.View> + accessibilityViewIsModal + visible={!!state} + presentationStyle="overFullScreen" + animationType="slide" + onRequestClose={() => ref.current?.onPressCancel()}> + <View style={[t.atoms.bg, {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> + </View> + </Modal> ) }) - -const styles = StyleSheet.create({ - wrapper: { - position: 'absolute', - top: 0, - bottom: 0, - width: '100%', - ...Platform.select({ - ios: { - paddingTop: 24, - }, - }), - }, -}) |