about summary refs log tree commit diff
path: root/src/view/shell
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/shell')
-rw-r--r--src/view/shell/Composer.ios.tsx80
-rw-r--r--src/view/shell/Composer.tsx159
-rw-r--r--src/view/shell/Composer.web.tsx1
3 files changed, 138 insertions, 102 deletions
diff --git a/src/view/shell/Composer.ios.tsx b/src/view/shell/Composer.ios.tsx
new file mode 100644
index 000000000..a732e0cde
--- /dev/null
+++ b/src/view/shell/Composer.ios.tsx
@@ -0,0 +1,80 @@
+import React, {useLayoutEffect} from 'react'
+import {Modal, View} from 'react-native'
+import {StatusBar} from 'expo-status-bar'
+import * as SystemUI from 'expo-system-ui'
+import {observer} from 'mobx-react-lite'
+
+import {useComposerState} from '#/state/shell/composer'
+import {atoms as a, useTheme} from '#/alf'
+import {getBackgroundColor, useThemeName} from '#/alf/util/useColorModeTheme'
+import {ComposePost, useComposerCancelRef} from '../com/composer/Composer'
+
+export const Composer = observer(function ComposerImpl({}: {
+  winHeight: number
+}) {
+  const t = useTheme()
+  const state = useComposerState()
+  const ref = useComposerCancelRef()
+
+  const open = !!state
+
+  return (
+    <Modal
+      aria-modal
+      accessibilityViewIsModal
+      visible={open}
+      presentationStyle="pageSheet"
+      animationType="slide"
+      onRequestClose={() => ref.current?.onPressCancel()}>
+      <View style={[t.atoms.bg, a.flex_1]}>
+        <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
+  return (
+    <>
+      {children}
+      <IOSModalBackground active={open} />
+    </>
+  )
+}
+
+// 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}) {
+  const theme = useThemeName()
+
+  useLayoutEffect(() => {
+    SystemUI.setBackgroundColorAsync('black')
+
+    return () => {
+      SystemUI.setBackgroundColorAsync(getBackgroundColor(theme))
+    }
+  }, [theme])
+
+  // Set the status bar to light - however, only if the modal is active
+  // If we rely on this component being mounted to set this,
+  // there'll be a delay before it switches back to default.
+  return active ? <StatusBar style="light" animated /> : null
+}
diff --git a/src/view/shell/Composer.tsx b/src/view/shell/Composer.tsx
index 1d656ca8f..b978d6b85 100644
--- a/src/view/shell/Composer.tsx
+++ b/src/view/shell/Composer.tsx
@@ -1,116 +1,73 @@
-import React, {useLayoutEffect, useState} 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 React, {useEffect} from 'react'
+import {Animated, Easing, StyleSheet, View} from 'react-native'
 import {observer} from 'mobx-react-lite'
 
-import {isIOS} from '#/platform/detection'
-import {Provider as LegacyModalProvider} from '#/state/modals'
-import {useComposerState} from '#/state/shell/composer'
-import {ModalsContainer as LegacyModalsContainer} from '#/view/com/modals/Modal'
-import {atoms as a, useTheme} from '#/alf'
-import {getBackgroundColor, useThemeName} from '#/alf/util/useColorModeTheme'
-import {
-  Outlet as PortalOutlet,
-  Provider as PortalProvider,
-} from '#/components/Portal'
-import {ComposePost, useComposerCancelRef} from '../com/composer/Composer'
+import {useAnimatedValue} from 'lib/hooks/useAnimatedValue'
+import {usePalette} from 'lib/hooks/usePalette'
+import {useComposerState} from 'state/shell/composer'
+import {ComposePost} from '../com/composer/Composer'
 
-export const Composer = observer(function ComposerImpl({}: {
+export const Composer = observer(function ComposerImpl({
+  winHeight,
+}: {
   winHeight: number
 }) {
-  const t = useTheme()
   const state = useComposerState()
-  const ref = useComposerCancelRef()
-  const [isModalReady, setIsModalReady] = useState(false)
+  const pal = usePalette('default')
+  const initInterp = useAnimatedValue(0)
 
-  const open = !!state
-  const [prevOpen, setPrevOpen] = useState(open)
-  if (open !== prevOpen) {
-    setPrevOpen(open)
-    if (!open) {
-      setIsModalReady(false)
+  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 />
   }
 
   return (
-    <Modal
+    <Animated.View
+      style={[styles.wrapper, pal.view, wrapperAnimStyle]}
       aria-modal
-      accessibilityViewIsModal
-      visible={open}
-      presentationStyle="formSheet"
-      animationType="slide"
-      onShow={() => setIsModalReady(true)}
-      onRequestClose={() => ref.current?.onPressCancel()}>
-      <View style={[t.atoms.bg, a.flex_1]}>
-        <Providers open={open}>
-          <ComposePost
-            isModalReady={isModalReady}
-            cancelRef={ref}
-            replyTo={state?.replyTo}
-            onPost={state?.onPost}
-            quote={state?.quote}
-            mention={state?.mention}
-            text={state?.text}
-            imageUris={state?.imageUris}
-          />
-        </Providers>
-      </View>
-    </Modal>
+      accessibilityViewIsModal>
+      <ComposePost
+        replyTo={state.replyTo}
+        onPost={state.onPost}
+        quote={state.quote}
+        mention={state.mention}
+        text={state.text}
+        imageUris={state.imageUris}
+      />
+    </Animated.View>
   )
 })
 
-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}) {
-  const theme = useThemeName()
-
-  useLayoutEffect(() => {
-    SystemUI.setBackgroundColorAsync('black')
-
-    return () => {
-      SystemUI.setBackgroundColorAsync(getBackgroundColor(theme))
-    }
-  }, [theme])
-
-  // Set the status bar to light - however, only if the modal is active
-  // If we rely on this component being mounted to set this,
-  // there'll be a delay before it switches back to default.
-  return active ? <StatusBar style="light" animated /> : null
-}
+const styles = StyleSheet.create({
+  wrapper: {
+    position: 'absolute',
+    top: 0,
+    bottom: 0,
+    width: '100%',
+  },
+})
diff --git a/src/view/shell/Composer.web.tsx b/src/view/shell/Composer.web.tsx
index 47322d4ea..64353db23 100644
--- a/src/view/shell/Composer.web.tsx
+++ b/src/view/shell/Composer.web.tsx
@@ -56,7 +56,6 @@ export function Composer({}: {winHeight: number}) {
           t.atoms.border_contrast_medium,
         ]}>
         <ComposePost
-          isModalReady={true}
           replyTo={state.replyTo}
           quote={state.quote}
           onPost={state.onPost}