diff --git a/package.json b/package.json
index eaf242a5..9baf7df1 100644
--- a/package.json
+++ b/package.json
@@ -49,6 +49,7 @@
"@atproto/api": "^0.12.2",
"@bam.tech/react-native-image-resizer": "^3.0.4",
"@braintree/sanitize-url": "^6.0.2",
+ "@discord/bottom-sheet": "https://github.com/bluesky-social/react-native-bottom-sheet.git#discord-fork-4.6.1",
"@emoji-mart/react": "^1.1.1",
"@expo/html-elements": "^0.4.2",
"@expo/webpack-config": "^19.0.0",
@@ -56,7 +57,6 @@
"@fortawesome/free-regular-svg-icons": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1",
"@fortawesome/react-native-fontawesome": "^0.3.0",
- "@gorhom/bottom-sheet": "^4.5.1",
"@lingui/react": "^4.5.0",
"@mattermost/react-native-paste-input": "^0.6.4",
"@miblanchard/react-native-slider": "^2.3.1",
@@ -93,6 +93,7 @@
"@tiptap/pm": "^2.0.0-beta.220",
"@tiptap/react": "^2.0.0-beta.220",
"@tiptap/suggestion": "^2.0.0-beta.220",
+ "@types/invariant": "^2.2.37",
"@types/node": "^18.16.2",
"@zxing/text-encoding": "^0.9.0",
"array.prototype.findlast": "^1.2.3",
diff --git a/src/App.native.tsx b/src/App.native.tsx
index e825ffa0..f2e0c4f7 100644
--- a/src/App.native.tsx
+++ b/src/App.native.tsx
@@ -1,59 +1,58 @@
import 'react-native-url-polyfill/auto'
import 'lib/sentry' // must be near top
-
-import React, {useState, useEffect} from 'react'
-import {RootSiblingParent} from 'react-native-root-siblings'
-import * as SplashScreen from 'expo-splash-screen'
-import {GestureHandlerRootView} from 'react-native-gesture-handler'
-import {PersistQueryClientProvider} from '@tanstack/react-query-persist-client'
-import {
- SafeAreaProvider,
- initialWindowMetrics,
-} from 'react-native-safe-area-context'
-
import 'view/icons'
-import {ThemeProvider as Alf} from '#/alf'
-import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
-import {init as initPersistedState} from '#/state/persisted'
-import {listenSessionDropped} from './state/events'
-import {ThemeProvider} from 'lib/ThemeContext'
-import {s} from 'lib/styles'
-import {Shell} from 'view/shell'
-import * as notifications from 'lib/notifications/notifications'
-import * as Toast from 'view/com/util/Toast'
+import React, {useEffect, useState} from 'react'
+import {GestureHandlerRootView} from 'react-native-gesture-handler'
+import {RootSiblingParent} from 'react-native-root-siblings'
+import {
+ initialWindowMetrics,
+ SafeAreaProvider,
+} from 'react-native-safe-area-context'
+import * as SplashScreen from 'expo-splash-screen'
+import {StatusBar} from 'expo-status-bar'
+import {msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+import {PersistQueryClientProvider} from '@tanstack/react-query-persist-client'
+
+import {Provider as StatsigProvider} from '#/lib/statsig/statsig'
+import {init as initPersistedState} from '#/state/persisted'
+import * as persisted from '#/state/persisted'
+import {Provider as LabelDefsProvider} from '#/state/preferences/label-defs'
+import {useIntentHandler} from 'lib/hooks/useIntentHandler'
+import * as notifications from 'lib/notifications/notifications'
import {
- queryClient,
asyncStoragePersister,
dehydrateOptions,
+ queryClient,
} from 'lib/react-query'
-import {TestCtrls} from 'view/com/testing/TestCtrls'
-import {Provider as ShellStateProvider} from 'state/shell'
-import {Provider as ModalStateProvider} from 'state/modals'
+import {s} from 'lib/styles'
+import {ThemeProvider} from 'lib/ThemeContext'
+import {isAndroid} from 'platform/detection'
import {Provider as DialogStateProvider} from 'state/dialogs'
-import {Provider as LightboxStateProvider} from 'state/lightbox'
-import {Provider as MutedThreadsProvider} from 'state/muted-threads'
import {Provider as InvitesStateProvider} from 'state/invites'
+import {Provider as LightboxStateProvider} from 'state/lightbox'
+import {Provider as ModalStateProvider} from 'state/modals'
+import {Provider as MutedThreadsProvider} from 'state/muted-threads'
import {Provider as PrefsStateProvider} from 'state/preferences'
-import {Provider as LoggedOutViewProvider} from 'state/shell/logged-out'
-import {Provider as SelectedFeedProvider} from 'state/shell/selected-feed'
-import {Provider as LabelDefsProvider} from '#/state/preferences/label-defs'
-import I18nProvider from './locale/i18nProvider'
+import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unread'
import {
Provider as SessionProvider,
useSession,
useSessionApi,
} from 'state/session'
-import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unread'
-import * as persisted from '#/state/persisted'
-import {Splash} from '#/Splash'
+import {Provider as ShellStateProvider} from 'state/shell'
+import {Provider as LoggedOutViewProvider} from 'state/shell/logged-out'
+import {Provider as SelectedFeedProvider} from 'state/shell/selected-feed'
+import {TestCtrls} from 'view/com/testing/TestCtrls'
+import * as Toast from 'view/com/util/Toast'
+import {Shell} from 'view/shell'
+import {ThemeProvider as Alf} from '#/alf'
+import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
import {Provider as PortalProvider} from '#/components/Portal'
-import {Provider as StatsigProvider} from '#/lib/statsig/statsig'
-import {msg} from '@lingui/macro'
-import {useLingui} from '@lingui/react'
-import {useIntentHandler} from 'lib/hooks/useIntentHandler'
-import {StatusBar} from 'expo-status-bar'
-import {isAndroid} from 'platform/detection'
+import {Splash} from '#/Splash'
+import I18nProvider from './locale/i18nProvider'
+import {listenSessionDropped} from './state/events'
SplashScreen.preventAutoHideAsync()
diff --git a/src/components/Dialog/index.tsx b/src/components/Dialog/index.tsx
index a85a1c4f..07e101f8 100644
--- a/src/components/Dialog/index.tsx
+++ b/src/components/Dialog/index.tsx
@@ -1,31 +1,31 @@
import React, {useImperativeHandle} from 'react'
-import {View, Dimensions, Keyboard, Pressable} from 'react-native'
+import {Dimensions, Pressable, View} from 'react-native'
+import Animated, {useAnimatedStyle} from 'react-native-reanimated'
+import {useSafeAreaInsets} from 'react-native-safe-area-context'
import BottomSheet, {
BottomSheetBackdropProps,
BottomSheetScrollView,
+ BottomSheetScrollViewMethods,
BottomSheetTextInput,
BottomSheetView,
useBottomSheet,
WINDOW_HEIGHT,
-} from '@gorhom/bottom-sheet'
-import {useSafeAreaInsets} from 'react-native-safe-area-context'
-import Animated, {useAnimatedStyle} from 'react-native-reanimated'
+} from '@discord/bottom-sheet/src'
-import {useTheme, atoms as a, flatten} from '#/alf'
-import {Portal} from '#/components/Portal'
-import {createInput} from '#/components/forms/TextField'
import {logger} from '#/logger'
import {useDialogStateControlContext} from '#/state/dialogs'
-
+import {isNative} from 'platform/detection'
+import {atoms as a, flatten, useTheme} from '#/alf'
+import {Context} from '#/components/Dialog/context'
import {
- DialogOuterProps,
DialogControlProps,
DialogInnerProps,
+ DialogOuterProps,
} from '#/components/Dialog/types'
-import {Context} from '#/components/Dialog/context'
-import {isNative} from 'platform/detection'
+import {createInput} from '#/components/forms/TextField'
+import {Portal} from '#/components/Portal'
-export {useDialogControl, useDialogContext} from '#/components/Dialog/context'
+export {useDialogContext, useDialogControl} from '#/components/Dialog/context'
export * from '#/components/Dialog/types'
// @ts-ignore
export const Input = createInput(BottomSheetTextInput)
@@ -122,7 +122,6 @@ export function Outer({
)
const onCloseInner = React.useCallback(() => {
- Keyboard.dismiss()
try {
closeCallback.current?.()
} catch (e: any) {
@@ -206,16 +205,14 @@ export function Inner({children, style}: DialogInnerProps) {
)
}
-export function ScrollableInner({
- children,
- keyboardDismissMode,
- style,
-}: DialogInnerProps) {
+export const ScrollableInner = React.forwardRef<
+ BottomSheetScrollViewMethods,
+ DialogInnerProps
+>(function ScrollableInner({children, style}, ref) {
const insets = useSafeAreaInsets()
return (
+ contentContainerStyle={isNative ? a.pb_4xl : undefined}
+ ref={ref}>
{children}
)
-}
+})
export function Handle() {
const t = useTheme()
- const onTouchStart = React.useCallback(() => {
- Keyboard.dismiss()
- }, [])
-
return (
-
+
(null)
+ useOnKeyboardDidShow(() => {
+ ref.current?.scrollToEnd({animated: true})
+ })
+
return (
-
+
{isLoading ? (
@@ -55,8 +60,6 @@ function ReportDialogInner(props: ReportDialogProps) {
) : (
)}
-
-
)
}
diff --git a/src/components/hooks/useOnKeyboard.ts b/src/components/hooks/useOnKeyboard.ts
new file mode 100644
index 00000000..5de681a4
--- /dev/null
+++ b/src/components/hooks/useOnKeyboard.ts
@@ -0,0 +1,12 @@
+import React from 'react'
+import {Keyboard} from 'react-native'
+
+export function useOnKeyboardDidShow(cb: () => unknown) {
+ React.useEffect(() => {
+ const subscription = Keyboard.addListener('keyboardDidShow', cb)
+
+ return () => {
+ subscription.remove()
+ }
+ }, [cb])
+}
diff --git a/src/view/com/modals/Modal.tsx b/src/view/com/modals/Modal.tsx
index 238cfc50..af86f13a 100644
--- a/src/view/com/modals/Modal.tsx
+++ b/src/view/com/modals/Modal.tsx
@@ -1,33 +1,33 @@
-import React, {useRef, useEffect} from 'react'
+import React, {useEffect, useRef} from 'react'
import {StyleSheet} from 'react-native'
import {SafeAreaView} from 'react-native-safe-area-context'
-import BottomSheet from '@gorhom/bottom-sheet'
-import {createCustomBackdrop} from '../util/BottomSheetCustomBackdrop'
-import {usePalette} from 'lib/hooks/usePalette'
+import BottomSheet from '@discord/bottom-sheet/src'
-import {useModals, useModalControls} from '#/state/modals'
-import * as EditProfileModal from './EditProfile'
-import * as RepostModal from './Repost'
-import * as SelfLabelModal from './SelfLabel'
-import * as ThreadgateModal from './Threadgate'
-import * as CreateOrEditListModal from './CreateOrEditList'
-import * as UserAddRemoveListsModal from './UserAddRemoveLists'
-import * as ListAddUserModal from './ListAddRemoveUsers'
+import {useModalControls, useModals} from '#/state/modals'
+import {usePalette} from 'lib/hooks/usePalette'
+import {createCustomBackdrop} from '../util/BottomSheetCustomBackdrop'
+import * as AddAppPassword from './AddAppPasswords'
import * as AltImageModal from './AltImage'
import * as EditImageModal from './AltImage'
-import * as DeleteAccountModal from './DeleteAccount'
-import * as ChangeHandleModal from './ChangeHandle'
-import * as InviteCodesModal from './InviteCodes'
-import * as AddAppPassword from './AddAppPasswords'
-import * as ContentLanguagesSettingsModal from './lang-settings/ContentLanguagesSettings'
-import * as PostLanguagesSettingsModal from './lang-settings/PostLanguagesSettings'
-import * as VerifyEmailModal from './VerifyEmail'
import * as ChangeEmailModal from './ChangeEmail'
+import * as ChangeHandleModal from './ChangeHandle'
import * as ChangePasswordModal from './ChangePassword'
-import * as SwitchAccountModal from './SwitchAccount'
-import * as LinkWarningModal from './LinkWarning'
+import * as CreateOrEditListModal from './CreateOrEditList'
+import * as DeleteAccountModal from './DeleteAccount'
+import * as EditProfileModal from './EditProfile'
import * as EmbedConsentModal from './EmbedConsent'
import * as InAppBrowserConsentModal from './InAppBrowserConsent'
+import * as InviteCodesModal from './InviteCodes'
+import * as ContentLanguagesSettingsModal from './lang-settings/ContentLanguagesSettings'
+import * as PostLanguagesSettingsModal from './lang-settings/PostLanguagesSettings'
+import * as LinkWarningModal from './LinkWarning'
+import * as ListAddUserModal from './ListAddRemoveUsers'
+import * as RepostModal from './Repost'
+import * as SelfLabelModal from './SelfLabel'
+import * as SwitchAccountModal from './SwitchAccount'
+import * as ThreadgateModal from './Threadgate'
+import * as UserAddRemoveListsModal from './UserAddRemoveLists'
+import * as VerifyEmailModal from './VerifyEmail'
const DEFAULT_SNAPPOINTS = ['90%']
const HANDLE_HEIGHT = 24
diff --git a/src/view/com/modals/SwitchAccount.tsx b/src/view/com/modals/SwitchAccount.tsx
index 892b07c9..03bef719 100644
--- a/src/view/com/modals/SwitchAccount.tsx
+++ b/src/view/com/modals/SwitchAccount.tsx
@@ -5,22 +5,23 @@ import {
TouchableOpacity,
View,
} from 'react-native'
-import {Text} from '../util/text/Text'
-import {s} from 'lib/styles'
-import {usePalette} from 'lib/hooks/usePalette'
+import {BottomSheetScrollView} from '@discord/bottom-sheet/src'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+
+import {useProfileQuery} from '#/state/queries/profile'
+import {SessionAccount, useSession, useSessionApi} from '#/state/session'
+import {useCloseAllActiveElements} from '#/state/util'
import {useAnalytics} from 'lib/analytics/analytics'
+import {Haptics} from 'lib/haptics'
import {useAccountSwitcher} from 'lib/hooks/useAccountSwitcher'
-import {UserAvatar} from '../util/UserAvatar'
+import {usePalette} from 'lib/hooks/usePalette'
+import {makeProfileLink} from 'lib/routes/links'
+import {s} from 'lib/styles'
import {AccountDropdownBtn} from '../util/AccountDropdownBtn'
import {Link} from '../util/Link'
-import {makeProfileLink} from 'lib/routes/links'
-import {BottomSheetScrollView} from '@gorhom/bottom-sheet'
-import {Haptics} from 'lib/haptics'
-import {Trans, msg} from '@lingui/macro'
-import {useLingui} from '@lingui/react'
-import {useSession, useSessionApi, SessionAccount} from '#/state/session'
-import {useProfileQuery} from '#/state/queries/profile'
-import {useCloseAllActiveElements} from '#/state/util'
+import {Text} from '../util/text/Text'
+import {UserAvatar} from '../util/UserAvatar'
export const snapPoints = ['40%', '90%']
diff --git a/src/view/com/modals/util.tsx b/src/view/com/modals/util.tsx
index 06f394ec..c047a052 100644
--- a/src/view/com/modals/util.tsx
+++ b/src/view/com/modals/util.tsx
@@ -1,4 +1,4 @@
export {
BottomSheetScrollView as ScrollView,
BottomSheetTextInput as TextInput,
-} from '@gorhom/bottom-sheet'
+} from '@discord/bottom-sheet/src'
diff --git a/src/view/com/util/BottomSheetCustomBackdrop.tsx b/src/view/com/util/BottomSheetCustomBackdrop.tsx
index ab657025..0d15c5e5 100644
--- a/src/view/com/util/BottomSheetCustomBackdrop.tsx
+++ b/src/view/com/util/BottomSheetCustomBackdrop.tsx
@@ -1,11 +1,11 @@
import React, {useMemo} from 'react'
import {TouchableWithoutFeedback} from 'react-native'
-import {BottomSheetBackdropProps} from '@gorhom/bottom-sheet'
import Animated, {
Extrapolate,
interpolate,
useAnimatedStyle,
} from 'react-native-reanimated'
+import {BottomSheetBackdropProps} from '@discord/bottom-sheet/src'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
diff --git a/yarn.lock b/yarn.lock
index 286ddfd5..c81f1206 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2814,6 +2814,13 @@
pino "^8.11.0"
pino-http "^8.3.3"
+"@discord/bottom-sheet@https://github.com/bluesky-social/react-native-bottom-sheet.git#discord-fork-4.6.1":
+ version "4.6.1"
+ resolved "https://github.com/bluesky-social/react-native-bottom-sheet.git#54dc2e0e318b0524a2d2d8fb817f6c48101bb0b1"
+ dependencies:
+ "@gorhom/portal" "1.0.14"
+ invariant "^2.2.4"
+
"@discoveryjs/json-ext@^0.5.0":
version "0.5.7"
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
@@ -3602,14 +3609,6 @@
resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
-"@gorhom/bottom-sheet@^4.5.1":
- version "4.5.1"
- resolved "https://registry.yarnpkg.com/@gorhom/bottom-sheet/-/bottom-sheet-4.5.1.tgz#1ac4b234a80e7dff263f0b7ac207f92e41562849"
- integrity sha512-4Qy6hzvN32fXu2hDxDXOIS0IBGBT6huST7J7+K1V5bXemZ08KIx5ZffyLgwhCUl+CnyeG2KG6tqk6iYLkIwi7Q==
- dependencies:
- "@gorhom/portal" "1.0.14"
- invariant "^2.2.4"
-
"@gorhom/portal@1.0.14":
version "1.0.14"
resolved "https://registry.yarnpkg.com/@gorhom/portal/-/portal-1.0.14.tgz#1953edb76aaba80fb24021dc774550194a18e111"
@@ -7629,6 +7628,11 @@
dependencies:
"@types/node" "*"
+"@types/invariant@^2.2.37":
+ version "2.2.37"
+ resolved "https://registry.yarnpkg.com/@types/invariant/-/invariant-2.2.37.tgz#1709741e534364d653c87dff22fc76fa94aa7bc0"
+ integrity sha512-IwpIMieE55oGWiXkQPSBY1nw1nFs6bsKXTFskNY8sdS17K24vyEBRQZEwlRS7ZmXCWnJcQtbxWzly+cODWGs2A==
+
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
version "2.0.4"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44"