Rip out Modal system completely (#9903)
This commit is contained in:
+1
-2
@@ -109,7 +109,6 @@
|
||||
"@bsky.app/sift": "^0.3.9",
|
||||
"@bsky.app/tapper": "^0.6.1",
|
||||
"@bsky.app/video": "0.3.6",
|
||||
"@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet",
|
||||
"@emoji-mart/data": "^1.2.1",
|
||||
"@emoji-mart/react": "^1.1.1",
|
||||
"@expo/html-elements": "^0.12.5",
|
||||
@@ -332,7 +331,7 @@
|
||||
"^await-lock$": "<rootDir>/node_modules/await-lock/build/AwaitLock.js"
|
||||
},
|
||||
"transformIgnorePatterns": [
|
||||
"node_modules/(?!((jest-)?react-native|@react-native(-community)?)|@discord|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|nanoid|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|normalize-url|react-native-svg|@sentry/.*|sentry-expo|bcp-47-match|@atproto/.*|multiformats|uint8arrays|@ipld/.*|cborg|await-lock)"
|
||||
"node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|nanoid|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|normalize-url|react-native-svg|@sentry/.*|sentry-expo|bcp-47-match|@atproto/.*|multiformats|uint8arrays|@ipld/.*|cborg|await-lock)"
|
||||
],
|
||||
"modulePathIgnorePatterns": [
|
||||
"__tests__/.*/__mocks__",
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
diff --git a/src/hooks/useStableCallback.ts b/src/hooks/useStableCallback.ts
|
||||
index 1c788ab72351c21c5aea178d7b416741aa940e1f..d30f330ab1f082ea0477c19e2fa05b7a0b1a3e0d 100644
|
||||
--- a/src/hooks/useStableCallback.ts
|
||||
+++ b/src/hooks/useStableCallback.ts
|
||||
@@ -6,7 +6,7 @@ type Callback = (...args: any[]) => any;
|
||||
* https://gist.github.com/JakeCoxon/c7ebf6e6496f8468226fd36b596e1985
|
||||
*/
|
||||
export const useStableCallback = (callback: Callback) => {
|
||||
- const callbackRef = useRef<Callback>();
|
||||
+ const callbackRef = useRef<Callback>(undefined);
|
||||
const memoCallback = useCallback(
|
||||
(...args: any) => callbackRef.current && callbackRef.current(...args),
|
||||
[]
|
||||
Generated
-58
@@ -215,7 +215,6 @@ overrides:
|
||||
react-native-screens: 4.24.0
|
||||
|
||||
patchedDependencies:
|
||||
'@discord/bottom-sheet@4.6.1': 253965341bfbc8e63630dfca511c5d0e0878900e5fe414b2278bd322fc215e2a
|
||||
'@sentry/react-native@6.20.0': 1d48e4d5178f5684eb33262299e7eed283bf9601f79b9ae1af63a7f607d3483a
|
||||
expo-glass-effect@55.0.8: 6c9fa5b104e53b87df4e17b320acb3b94d12ac90c0101190045dd620681efff0
|
||||
expo-haptics@15.0.8: b33910ba2753c4eccdc885b449e6e33aa90b9cefa75ca8639762a26013141410
|
||||
@@ -286,9 +285,6 @@ importers:
|
||||
'@bsky.app/video':
|
||||
specifier: 0.3.6
|
||||
version: 0.3.6(expo@54.0.34(@babel/core@7.29.0)(react-native-webview@13.15.0(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||
'@discord/bottom-sheet':
|
||||
specifier: bluesky-social/react-native-bottom-sheet
|
||||
version: https://codeload.github.com/bluesky-social/react-native-bottom-sheet/tar.gz/28a87d1bb55e10fc355fa1455545a30734995908(patch_hash=253965341bfbc8e63630dfca511c5d0e0878900e5fe414b2278bd322fc215e2a)(@shopify/flash-list@2.3.1(@babel/runtime@7.29.2)(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(@types/react@19.1.17)(react-native-gesture-handler@2.28.0(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-reanimated@3.19.1(patch_hash=97a1967f37a4213fbab59e1fd59a1bf859b5efc79af5e1b528a47fe488e6c5d6)(@babel/core@7.29.0)(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||
'@emoji-mart/data':
|
||||
specifier: ^1.2.1
|
||||
version: 1.2.1
|
||||
@@ -1699,23 +1695,6 @@ packages:
|
||||
resolution: {integrity: sha512-JRrHvitc0w+r/h6XXSOq917HxsjRoxPEtyNYSmylKirjiPNrRx84VKtqFlOIWIFCOZI5BoXg6hNpE0Zq7CwVBA==}
|
||||
hasBin: true
|
||||
|
||||
'@discord/bottom-sheet@https://codeload.github.com/bluesky-social/react-native-bottom-sheet/tar.gz/28a87d1bb55e10fc355fa1455545a30734995908':
|
||||
resolution: {gitHosted: true, integrity: sha512-zsoB8sFUx8O9aO0fKAkzoWLMyaX7EBd3ooNYjzsh9vr/c9zg/a3jOAbWzWbvM86QCZIszfbW9GXeJZKZRVk/tg==, tarball: https://codeload.github.com/bluesky-social/react-native-bottom-sheet/tar.gz/28a87d1bb55e10fc355fa1455545a30734995908}
|
||||
version: 4.6.1
|
||||
peerDependencies:
|
||||
'@shopify/flash-list': '*'
|
||||
'@types/react': '*'
|
||||
'@types/react-native': '*'
|
||||
react: '*'
|
||||
react-native: '*'
|
||||
react-native-gesture-handler: '>=1.10.1'
|
||||
react-native-reanimated: 3.19.1
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
'@types/react-native':
|
||||
optional: true
|
||||
|
||||
'@discoveryjs/json-ext@0.5.7':
|
||||
resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
@@ -2107,12 +2086,6 @@ packages:
|
||||
'@formatjs/intl-supportedvaluesof@2.3.7':
|
||||
resolution: {integrity: sha512-ZTXEKijV5H08z19odngZPsXlmGndfukHuVnjd9qyER77XSk/yJwDMiSjoJYY5C5WxFs2UN4s/EMtu75e6Tp3ug==}
|
||||
|
||||
'@gorhom/portal@1.0.14':
|
||||
resolution: {integrity: sha512-MXyL4xvCjmgaORr/rtryDNFy3kU4qUbKlwtQqqsygd0xX3mhKjOLn6mQK8wfu0RkoE0pBE0nAasRoHua+/QZ7A==}
|
||||
peerDependencies:
|
||||
react: '*'
|
||||
react-native: '*'
|
||||
|
||||
'@growthbook/growthbook-react@1.6.5':
|
||||
resolution: {integrity: sha512-afi/RUbwazVNKv2acn6wDQz4BJNRAEpwIuHfggQup2/aE5PLAxy3+95gjjRMgCcPR0Pf3sFmhYGvOmxLD0ZRbQ==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -3367,13 +3340,6 @@ packages:
|
||||
peerDependencies:
|
||||
webpack: '>=4.40.0'
|
||||
|
||||
'@shopify/flash-list@2.3.1':
|
||||
resolution: {integrity: sha512-7oktg2NQR7KAODjFoDaWe8/OBzyYbdTE3zQTrUBMxjIbxHTHN7UXRX1hX3DHk8KvtkgQdRfZOV8Gjj2l4fGrXw==}
|
||||
peerDependencies:
|
||||
'@babel/runtime': '*'
|
||||
react: '*'
|
||||
react-native: '*'
|
||||
|
||||
'@sinclair/typebox@0.27.10':
|
||||
resolution: {integrity: sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==}
|
||||
|
||||
@@ -10521,18 +10487,6 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
|
||||
? '@discord/bottom-sheet@https://codeload.github.com/bluesky-social/react-native-bottom-sheet/tar.gz/28a87d1bb55e10fc355fa1455545a30734995908(patch_hash=253965341bfbc8e63630dfca511c5d0e0878900e5fe414b2278bd322fc215e2a)(@shopify/flash-list@2.3.1(@babel/runtime@7.29.2)(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(@types/react@19.1.17)(react-native-gesture-handler@2.28.0(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-reanimated@3.19.1(patch_hash=97a1967f37a4213fbab59e1fd59a1bf859b5efc79af5e1b528a47fe488e6c5d6)(@babel/core@7.29.0)(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)'
|
||||
: dependencies:
|
||||
'@gorhom/portal': 1.0.14(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||
'@shopify/flash-list': 2.3.1(@babel/runtime@7.29.2)(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||
invariant: 2.2.4
|
||||
react: 19.1.0
|
||||
react-native: 0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0)
|
||||
react-native-gesture-handler: 2.28.0(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||
react-native-reanimated: 3.19.1(patch_hash=97a1967f37a4213fbab59e1fd59a1bf859b5efc79af5e1b528a47fe488e6c5d6)(@babel/core@7.29.0)(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.17
|
||||
|
||||
'@discoveryjs/json-ext@0.5.7': {}
|
||||
|
||||
'@egjs/hammerjs@2.0.17':
|
||||
@@ -11103,12 +11057,6 @@ snapshots:
|
||||
dependencies:
|
||||
'@formatjs/fast-memoize': 3.1.5
|
||||
|
||||
'@gorhom/portal@1.0.14(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)':
|
||||
dependencies:
|
||||
nanoid: 3.3.12
|
||||
react: 19.1.0
|
||||
react-native: 0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0)
|
||||
|
||||
'@growthbook/growthbook-react@1.6.5(react@19.1.0)':
|
||||
dependencies:
|
||||
'@growthbook/growthbook': 1.6.5
|
||||
@@ -12616,12 +12564,6 @@ snapshots:
|
||||
- encoding
|
||||
- supports-color
|
||||
|
||||
'@shopify/flash-list@2.3.1(@babel/runtime@7.29.2)(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.29.2
|
||||
react: 19.1.0
|
||||
react-native: 0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0)
|
||||
|
||||
'@sinclair/typebox@0.27.10': {}
|
||||
|
||||
'@sinclair/typebox@0.34.49': {}
|
||||
|
||||
@@ -19,7 +19,6 @@ allowBuilds:
|
||||
'esbuild': true
|
||||
'unrs-resolver': true
|
||||
patchedDependencies:
|
||||
'@discord/bottom-sheet@4.6.1': patches/@discord__bottom-sheet@4.6.1.patch
|
||||
'@sentry/react-native@6.20.0': patches/@sentry__react-native@6.20.0.patch
|
||||
'expo-glass-effect@55.0.8': patches/expo-glass-effect@55.0.8.patch
|
||||
'expo-haptics@15.0.8': patches/expo-haptics@15.0.8.patch
|
||||
|
||||
+14
-17
@@ -31,7 +31,6 @@ import {listenSessionDropped} from '#/state/events'
|
||||
import {GlobalGestureEventsProvider} from '#/state/global-gesture-events'
|
||||
import {Provider as HomeBadgeProvider} from '#/state/home-badge'
|
||||
import {MessagesProvider} from '#/state/messages'
|
||||
import {Provider as ModalStateProvider} from '#/state/modals'
|
||||
import {init as initPersistedState} from '#/state/persisted'
|
||||
import {Provider as PrefsStateProvider} from '#/state/preferences'
|
||||
import {Provider as LabelDefsProvider} from '#/state/preferences/label-defs'
|
||||
@@ -241,22 +240,20 @@ function App() {
|
||||
<PrefsStateProvider>
|
||||
<I18nProvider>
|
||||
<ShellStateProvider>
|
||||
<ModalStateProvider>
|
||||
<DialogStateProvider>
|
||||
<LightboxStateProvider>
|
||||
<PortalProvider>
|
||||
<BottomSheetProvider>
|
||||
<LandingProvider>
|
||||
<SafeAreaProvider
|
||||
initialMetrics={initialWindowMetrics}>
|
||||
<InnerApp />
|
||||
</SafeAreaProvider>
|
||||
</LandingProvider>
|
||||
</BottomSheetProvider>
|
||||
</PortalProvider>
|
||||
</LightboxStateProvider>
|
||||
</DialogStateProvider>
|
||||
</ModalStateProvider>
|
||||
<DialogStateProvider>
|
||||
<LightboxStateProvider>
|
||||
<PortalProvider>
|
||||
<BottomSheetProvider>
|
||||
<LandingProvider>
|
||||
<SafeAreaProvider
|
||||
initialMetrics={initialWindowMetrics}>
|
||||
<InnerApp />
|
||||
</SafeAreaProvider>
|
||||
</LandingProvider>
|
||||
</BottomSheetProvider>
|
||||
</PortalProvider>
|
||||
</LightboxStateProvider>
|
||||
</DialogStateProvider>
|
||||
</ShellStateProvider>
|
||||
</I18nProvider>
|
||||
</PrefsStateProvider>
|
||||
|
||||
+9
-12
@@ -24,7 +24,6 @@ import {Provider as EmailVerificationProvider} from '#/state/email-verification'
|
||||
import {listenSessionDropped} from '#/state/events'
|
||||
import {Provider as HomeBadgeProvider} from '#/state/home-badge'
|
||||
import {MessagesProvider} from '#/state/messages'
|
||||
import {Provider as ModalStateProvider} from '#/state/modals'
|
||||
import {init as initPersistedState} from '#/state/persisted'
|
||||
import {Provider as PrefsStateProvider} from '#/state/preferences'
|
||||
import {Provider as LabelDefsProvider} from '#/state/preferences/label-defs'
|
||||
@@ -220,17 +219,15 @@ function App() {
|
||||
<PrefsStateProvider>
|
||||
<I18nProvider>
|
||||
<ShellStateProvider>
|
||||
<ModalStateProvider>
|
||||
<DialogStateProvider>
|
||||
<LightboxStateProvider>
|
||||
<PortalProvider>
|
||||
<LandingProvider>
|
||||
<InnerApp />
|
||||
</LandingProvider>
|
||||
</PortalProvider>
|
||||
</LightboxStateProvider>
|
||||
</DialogStateProvider>
|
||||
</ModalStateProvider>
|
||||
<DialogStateProvider>
|
||||
<LightboxStateProvider>
|
||||
<PortalProvider>
|
||||
<LandingProvider>
|
||||
<InnerApp />
|
||||
</LandingProvider>
|
||||
</PortalProvider>
|
||||
</LightboxStateProvider>
|
||||
</DialogStateProvider>
|
||||
</ShellStateProvider>
|
||||
</I18nProvider>
|
||||
</PrefsStateProvider>
|
||||
|
||||
@@ -26,7 +26,6 @@ import {
|
||||
isExternalUrl,
|
||||
linkRequiresWarning,
|
||||
} from '#/lib/strings/url-helpers'
|
||||
import {useModalControls} from '#/state/modals'
|
||||
import {useInAppBrowser} from '#/state/preferences/in-app-browser'
|
||||
import {atoms as a, flatten, type TextStyleProp, useTheme, web} from '#/alf'
|
||||
import {Button, type ButtonProps} from '#/components/Button'
|
||||
@@ -140,7 +139,6 @@ export function useLink({
|
||||
}
|
||||
|
||||
const isExternal = isExternalUrl(href)
|
||||
const {closeModal} = useModalControls()
|
||||
const {linkWarningDialogControl} = useGlobalDialogsControlContext()
|
||||
const openLink = useOpenLink()
|
||||
const groupChatJoinIntent = useGroupChatJoinIntent()
|
||||
@@ -188,8 +186,6 @@ export function useLink({
|
||||
) {
|
||||
void openLink(href)
|
||||
} else {
|
||||
closeModal() // close any active modals
|
||||
|
||||
const [screen, params] = router.matchPath(href) as [
|
||||
screen: keyof AllNavigatorParams,
|
||||
params?: RouteParams,
|
||||
@@ -242,7 +238,6 @@ export function useLink({
|
||||
isExternal,
|
||||
href,
|
||||
openLink,
|
||||
closeModal,
|
||||
action,
|
||||
navigation,
|
||||
overridePresentation,
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
import {createContext, useContext, useEffect, useMemo, useState} from 'react'
|
||||
|
||||
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
||||
import {useHotkeysContext} from '#/lib/hotkeys'
|
||||
|
||||
export interface ContentLanguagesSettingsModal {
|
||||
name: 'content-languages-settings'
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated DO NOT ADD NEW MODALS
|
||||
*/
|
||||
export type Modal =
|
||||
// Curation
|
||||
ContentLanguagesSettingsModal
|
||||
|
||||
const ModalContext = createContext<{
|
||||
isModalActive: boolean
|
||||
activeModals: Modal[]
|
||||
}>({
|
||||
isModalActive: false,
|
||||
activeModals: [],
|
||||
})
|
||||
ModalContext.displayName = 'ModalContext'
|
||||
|
||||
const ModalControlContext = createContext<{
|
||||
openModal: (modal: Modal) => void
|
||||
closeModal: () => boolean
|
||||
closeAllModals: () => boolean
|
||||
}>({
|
||||
openModal: () => {},
|
||||
closeModal: () => false,
|
||||
closeAllModals: () => false,
|
||||
})
|
||||
ModalControlContext.displayName = 'ModalControlContext'
|
||||
|
||||
export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||
const [activeModals, setActiveModals] = useState<Modal[]>([])
|
||||
const {disableScope, enableScope} = useHotkeysContext()
|
||||
|
||||
useEffect(() => {
|
||||
if (activeModals.length > 0) {
|
||||
disableScope('global')
|
||||
} else {
|
||||
enableScope('global')
|
||||
}
|
||||
}, [activeModals.length, disableScope, enableScope])
|
||||
|
||||
const openModal = useNonReactiveCallback((modal: Modal) => {
|
||||
setActiveModals(modals => [...modals, modal])
|
||||
})
|
||||
|
||||
const closeModal = useNonReactiveCallback(() => {
|
||||
let wasActive = activeModals.length > 0
|
||||
setActiveModals(modals => {
|
||||
return modals.slice(0, -1)
|
||||
})
|
||||
return wasActive
|
||||
})
|
||||
|
||||
const closeAllModals = useNonReactiveCallback(() => {
|
||||
let wasActive = activeModals.length > 0
|
||||
setActiveModals([])
|
||||
return wasActive
|
||||
})
|
||||
|
||||
const state = useMemo(
|
||||
() => ({
|
||||
isModalActive: activeModals.length > 0,
|
||||
activeModals,
|
||||
}),
|
||||
[activeModals],
|
||||
)
|
||||
|
||||
const methods = useMemo(
|
||||
() => ({
|
||||
openModal,
|
||||
closeModal,
|
||||
closeAllModals,
|
||||
}),
|
||||
[openModal, closeModal, closeAllModals],
|
||||
)
|
||||
|
||||
return (
|
||||
<ModalContext.Provider value={state}>
|
||||
<ModalControlContext.Provider value={methods}>
|
||||
{children}
|
||||
</ModalControlContext.Provider>
|
||||
</ModalContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use the dialog system from `#/components/Dialog.tsx`
|
||||
*/
|
||||
export function useModals() {
|
||||
return useContext(ModalContext)
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use the dialog system from `#/components/Dialog.tsx`
|
||||
*/
|
||||
export function useModalControls() {
|
||||
return useContext(ModalControlContext)
|
||||
}
|
||||
+2
-15
@@ -2,7 +2,6 @@ import {useCallback} from 'react'
|
||||
|
||||
import {useDialogStateControlContext} from '#/state/dialogs'
|
||||
import {useLightboxControls} from '#/components/Lightbox/state'
|
||||
import {useModalControls} from './modals'
|
||||
import {useComposerControls} from './shell/composer'
|
||||
import {useSetDrawerOpen} from './shell/drawer-open'
|
||||
|
||||
@@ -12,7 +11,6 @@ import {useSetDrawerOpen} from './shell/drawer-open'
|
||||
*/
|
||||
export function useCloseAnyActiveElement() {
|
||||
const {closeLightbox} = useLightboxControls()
|
||||
const {closeModal} = useModalControls()
|
||||
const {closeComposer} = useComposerControls()
|
||||
const {closeAllDialogs} = useDialogStateControlContext()
|
||||
const setDrawerOpen = useSetDrawerOpen()
|
||||
@@ -20,9 +18,6 @@ export function useCloseAnyActiveElement() {
|
||||
if (closeLightbox()) {
|
||||
return true
|
||||
}
|
||||
if (closeModal()) {
|
||||
return true
|
||||
}
|
||||
if (closeAllDialogs()) {
|
||||
return true
|
||||
}
|
||||
@@ -31,7 +26,7 @@ export function useCloseAnyActiveElement() {
|
||||
}
|
||||
setDrawerOpen(false)
|
||||
return false
|
||||
}, [closeLightbox, closeModal, closeComposer, setDrawerOpen, closeAllDialogs])
|
||||
}, [closeLightbox, closeComposer, setDrawerOpen, closeAllDialogs])
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,21 +34,13 @@ export function useCloseAnyActiveElement() {
|
||||
*/
|
||||
export function useCloseAllActiveElements() {
|
||||
const {closeLightbox} = useLightboxControls()
|
||||
const {closeAllModals} = useModalControls()
|
||||
const {closeComposer} = useComposerControls()
|
||||
const {closeAllDialogs: closeAlfDialogs} = useDialogStateControlContext()
|
||||
const setDrawerOpen = useSetDrawerOpen()
|
||||
return useCallback(() => {
|
||||
closeLightbox()
|
||||
closeAllModals()
|
||||
closeComposer()
|
||||
closeAlfDialogs()
|
||||
setDrawerOpen(false)
|
||||
}, [
|
||||
closeLightbox,
|
||||
closeAllModals,
|
||||
closeComposer,
|
||||
closeAlfDialogs,
|
||||
setDrawerOpen,
|
||||
])
|
||||
}, [closeLightbox, closeComposer, closeAlfDialogs, setDrawerOpen])
|
||||
}
|
||||
|
||||
@@ -86,7 +86,6 @@ import {
|
||||
createComposerImage,
|
||||
pasteImage,
|
||||
} from '#/state/gallery'
|
||||
import {useModalControls} from '#/state/modals'
|
||||
import {useRequireAltTextEnabled} from '#/state/preferences'
|
||||
import {
|
||||
fromPostLanguages,
|
||||
@@ -283,7 +282,6 @@ export const ComposePost = ({
|
||||
useSaveDraftMutation()
|
||||
const {mutate: cleanupPublishedDraft} = useCleanupPublishedDraftMutation()
|
||||
const {closeAllDialogs} = useDialogStateControlContext()
|
||||
const {closeAllModals} = useModalControls()
|
||||
const {data: preferences} = usePreferencesQuery()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
|
||||
@@ -835,7 +833,7 @@ export const ComposePost = ({
|
||||
const backHandler = BackHandler.addEventListener(
|
||||
'hardwareBackPress',
|
||||
() => {
|
||||
if (closeAllDialogs() || closeAllModals()) {
|
||||
if (closeAllDialogs()) {
|
||||
return true
|
||||
}
|
||||
onPressCancel()
|
||||
@@ -845,7 +843,7 @@ export const ComposePost = ({
|
||||
return () => {
|
||||
backHandler.remove()
|
||||
}
|
||||
}, [onPressCancel, closeAllDialogs, closeAllModals])
|
||||
}, [onPressCancel, closeAllDialogs])
|
||||
|
||||
const missingAltError = useMemo(() => {
|
||||
if (!requireAltTextEnabled) {
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
import {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 {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {useModalControls, useModals} from '#/state/modals'
|
||||
import {FullWindowOverlay} from '#/components/FullWindowOverlay'
|
||||
import {createCustomBackdrop} from '../util/BottomSheetCustomBackdrop'
|
||||
|
||||
const DEFAULT_SNAPPOINTS = ['90%']
|
||||
const HANDLE_HEIGHT = 24
|
||||
|
||||
export function ModalsContainer() {
|
||||
const {isModalActive, activeModals} = useModals()
|
||||
const {closeModal} = useModalControls()
|
||||
const bottomSheetRef = useRef<BottomSheet>(null)
|
||||
const pal = usePalette('default')
|
||||
const activeModal = activeModals[activeModals.length - 1]
|
||||
|
||||
const onBottomSheetChange = async (snapPoint: number) => {
|
||||
if (snapPoint === -1) {
|
||||
closeModal()
|
||||
}
|
||||
}
|
||||
|
||||
const onClose = () => {
|
||||
bottomSheetRef.current?.close()
|
||||
closeModal()
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (isModalActive) {
|
||||
bottomSheetRef.current?.snapToIndex(0)
|
||||
} else {
|
||||
bottomSheetRef.current?.close()
|
||||
}
|
||||
}, [isModalActive, bottomSheetRef, activeModal?.name])
|
||||
|
||||
let snapPoints: (string | number)[] = DEFAULT_SNAPPOINTS
|
||||
let element
|
||||
{
|
||||
return null
|
||||
}
|
||||
|
||||
if (snapPoints[0] === 'fullscreen') {
|
||||
return (
|
||||
<SafeAreaView style={[styles.fullscreenContainer, pal.view]}>
|
||||
{element}
|
||||
</SafeAreaView>
|
||||
)
|
||||
}
|
||||
|
||||
const Container = activeModal ? FullWindowOverlay : Fragment
|
||||
|
||||
return (
|
||||
<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]}
|
||||
backgroundStyle={pal.view}
|
||||
onChange={onBottomSheetChange}>
|
||||
{element}
|
||||
</BottomSheet>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
handle: {
|
||||
borderTopLeftRadius: 10,
|
||||
borderTopRightRadius: 10,
|
||||
},
|
||||
fullscreenContainer: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
},
|
||||
})
|
||||
@@ -1,101 +0,0 @@
|
||||
import {StyleSheet, TouchableWithoutFeedback, View} from 'react-native'
|
||||
import Animated, {FadeIn, FadeOut} from 'react-native-reanimated'
|
||||
import {RemoveScrollBar} from 'react-remove-scroll-bar'
|
||||
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||
import {type Modal as ModalIface} from '#/state/modals'
|
||||
import {useModalControls, useModals} from '#/state/modals'
|
||||
|
||||
export function ModalsContainer() {
|
||||
const {isModalActive, activeModals} = useModals()
|
||||
|
||||
if (!isModalActive) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<RemoveScrollBar />
|
||||
{activeModals.map((modal, i) => (
|
||||
<Modal key={`modal-${i}`} modal={modal} />
|
||||
))}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function Modal({modal: _modal}: {modal: ModalIface}) {
|
||||
const {isModalActive} = useModals()
|
||||
const {closeModal} = useModalControls()
|
||||
const pal = usePalette('default')
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
|
||||
if (!isModalActive) {
|
||||
return null
|
||||
}
|
||||
|
||||
const onPressMask = () => {
|
||||
closeModal()
|
||||
}
|
||||
const onInnerPress = () => {
|
||||
// TODO: can we use prevent default?
|
||||
// do nothing, we just want to stop it from bubbling
|
||||
}
|
||||
|
||||
let element
|
||||
{
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line react-native-a11y/has-valid-accessibility-descriptors
|
||||
<TouchableWithoutFeedback onPress={onPressMask}>
|
||||
<Animated.View
|
||||
style={styles.mask}
|
||||
entering={FadeIn.duration(150)}
|
||||
exiting={FadeOut}>
|
||||
{/* eslint-disable-next-line react-native-a11y/has-valid-accessibility-descriptors */}
|
||||
<TouchableWithoutFeedback onPress={onInnerPress}>
|
||||
<View
|
||||
style={[
|
||||
styles.container,
|
||||
isMobile && styles.containerMobile,
|
||||
pal.view,
|
||||
pal.border,
|
||||
]}>
|
||||
{element}
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
</Animated.View>
|
||||
</TouchableWithoutFeedback>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
mask: {
|
||||
// @ts-ignore
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
backgroundColor: '#000c',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
container: {
|
||||
width: 600,
|
||||
// @ts-ignore web only
|
||||
maxWidth: '100vw',
|
||||
// @ts-ignore web only
|
||||
maxHeight: '90vh',
|
||||
paddingVertical: 20,
|
||||
paddingHorizontal: 24,
|
||||
borderRadius: 8,
|
||||
borderWidth: 1,
|
||||
},
|
||||
containerMobile: {
|
||||
borderRadius: 0,
|
||||
paddingHorizontal: 0,
|
||||
},
|
||||
})
|
||||
@@ -1,4 +0,0 @@
|
||||
export {
|
||||
BottomSheetScrollView as ScrollView,
|
||||
BottomSheetTextInput as TextInput,
|
||||
} from '@discord/bottom-sheet/src'
|
||||
@@ -1 +0,0 @@
|
||||
export {ScrollView, TextInput} from 'react-native'
|
||||
@@ -1,48 +0,0 @@
|
||||
import {useMemo} from 'react'
|
||||
import {TouchableWithoutFeedback} from 'react-native'
|
||||
import Animated, {
|
||||
Extrapolation,
|
||||
interpolate,
|
||||
useAnimatedStyle,
|
||||
} from 'react-native-reanimated'
|
||||
import {type BottomSheetBackdropProps} from '@discord/bottom-sheet/src'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
export function createCustomBackdrop(
|
||||
onClose?: () => void,
|
||||
): React.FC<BottomSheetBackdropProps> {
|
||||
const CustomBackdrop = ({animatedIndex, style}: BottomSheetBackdropProps) => {
|
||||
const {_} = useLingui()
|
||||
|
||||
// animated variables
|
||||
const opacity = useAnimatedStyle(() => ({
|
||||
opacity: interpolate(
|
||||
animatedIndex.get(), // current snap index
|
||||
[-1, 0], // input range
|
||||
[0, 0.5], // output range
|
||||
Extrapolation.CLAMP,
|
||||
),
|
||||
}))
|
||||
|
||||
const containerStyle = useMemo(
|
||||
() => [style, {backgroundColor: '#000'}, opacity],
|
||||
[style, opacity],
|
||||
)
|
||||
|
||||
return (
|
||||
<TouchableWithoutFeedback
|
||||
onPress={onClose}
|
||||
accessibilityLabel={_(msg`Close bottom drawer`)}
|
||||
accessibilityHint=""
|
||||
onAccessibilityEscape={() => {
|
||||
if (onClose !== undefined) {
|
||||
onClose()
|
||||
}
|
||||
}}>
|
||||
<Animated.View style={containerStyle} />
|
||||
</TouchableWithoutFeedback>
|
||||
)
|
||||
}
|
||||
return CustomBackdrop
|
||||
}
|
||||
@@ -28,7 +28,6 @@ import {
|
||||
} from '#/lib/strings/url-helpers'
|
||||
import {type TypographyVariant} from '#/lib/ThemeContext'
|
||||
import {emitSoftReset} from '#/state/events'
|
||||
import {useModalControls} from '#/state/modals'
|
||||
import {WebAuxClickWrapper} from '#/view/com/util/WebAuxClickWrapper'
|
||||
import {useTheme} from '#/alf'
|
||||
import {useGlobalDialogsControlContext} from '#/components/dialogs/Context'
|
||||
@@ -79,7 +78,6 @@ export const Link = memo(function Link({
|
||||
...props
|
||||
}: Props) {
|
||||
const t = useTheme()
|
||||
const {closeModal} = useModalControls()
|
||||
const navigation = useNavigationDeduped()
|
||||
const anchorHref = asAnchor ? sanitizeUrl(href) : undefined
|
||||
const openLink = useOpenLink()
|
||||
@@ -90,7 +88,6 @@ export const Link = memo(function Link({
|
||||
onBeforePress?.()
|
||||
if (typeof href === 'string') {
|
||||
return onPressInner(
|
||||
closeModal,
|
||||
navigation,
|
||||
sanitizeUrl(href),
|
||||
navigationAction,
|
||||
@@ -101,7 +98,6 @@ export const Link = memo(function Link({
|
||||
}
|
||||
},
|
||||
[
|
||||
closeModal,
|
||||
navigation,
|
||||
navigationAction,
|
||||
href,
|
||||
@@ -205,7 +201,6 @@ export const TextLink = memo(function TextLink({
|
||||
onBeforePress?: () => void
|
||||
} & TextProps) {
|
||||
const navigation = useNavigationDeduped()
|
||||
const {closeModal} = useModalControls()
|
||||
const {linkWarningDialogControl} = useGlobalDialogsControlContext()
|
||||
const openLink = useOpenLink()
|
||||
const groupChatJoinIntent = useGroupChatJoinIntent()
|
||||
@@ -246,7 +241,6 @@ export const TextLink = memo(function TextLink({
|
||||
return onPressProp()
|
||||
}
|
||||
return onPressInner(
|
||||
closeModal,
|
||||
navigation,
|
||||
sanitizeUrl(href),
|
||||
navigationAction,
|
||||
@@ -258,7 +252,6 @@ export const TextLink = memo(function TextLink({
|
||||
[
|
||||
onBeforePress,
|
||||
onPressProp,
|
||||
closeModal,
|
||||
navigation,
|
||||
href,
|
||||
text,
|
||||
@@ -383,7 +376,6 @@ const EXEMPT_PATHS = ['/robots.txt', '/security.txt', '/.well-known/']
|
||||
// needed customizations
|
||||
// -prf
|
||||
function onPressInner(
|
||||
closeModal = () => {},
|
||||
navigation: DebouncedNavigationProp,
|
||||
href: string,
|
||||
navigationAction: 'push' | 'replace' | 'navigate' = 'push',
|
||||
@@ -429,8 +421,6 @@ function onPressInner(
|
||||
) {
|
||||
openLink(href)
|
||||
} else {
|
||||
closeModal() // close any active modals
|
||||
|
||||
const [routeName, params] = router.matchPath(href)
|
||||
if (navigationAction === 'push') {
|
||||
// @ts-ignore we're not able to type check on this one -prf
|
||||
|
||||
@@ -3,7 +3,6 @@ import {DismissableLayer, FocusGuards, FocusScope} from 'radix-ui/internal'
|
||||
import {RemoveScrollBar} from 'react-remove-scroll-bar'
|
||||
|
||||
import {useA11y} from '#/state/a11y'
|
||||
import {useModals} from '#/state/modals'
|
||||
import {type ComposerOpts, useComposerState} from '#/state/shell/composer'
|
||||
import {ComposePost, useComposerCancelRef} from '#/view/com/composer/Composer'
|
||||
import {atoms as a, flatten, useBreakpoints, useTheme} from '#/alf'
|
||||
@@ -28,7 +27,6 @@ export function Composer() {
|
||||
|
||||
function Inner({state}: {state: ComposerOpts}) {
|
||||
const ref = useComposerCancelRef()
|
||||
const {isModalActive} = useModals()
|
||||
const t = useTheme()
|
||||
const {gtMobile} = useBreakpoints()
|
||||
const {reduceMotionEnabled} = useA11y()
|
||||
@@ -51,12 +49,7 @@ function Inner({state}: {state: ComposerOpts}) {
|
||||
])}
|
||||
onFocusOutside={evt => evt.preventDefault()}
|
||||
onInteractOutside={evt => evt.preventDefault()}
|
||||
onDismiss={() => {
|
||||
// TEMP: remove when all modals are ALF'd -sfn
|
||||
if (!isModalActive) {
|
||||
ref.current?.onPressCancel()
|
||||
}
|
||||
}}>
|
||||
onDismiss={() => ref.current?.onPressCancel()}>
|
||||
<View
|
||||
style={[
|
||||
styles.container,
|
||||
|
||||
@@ -19,7 +19,6 @@ import {
|
||||
useSetDrawerOpen,
|
||||
} from '#/state/shell'
|
||||
import {useCloseAnyActiveElement} from '#/state/util'
|
||||
import {ModalsContainer} from '#/view/com/modals/Modal'
|
||||
import {ErrorBoundary} from '#/view/com/util/ErrorBoundary'
|
||||
import {Deactivated} from '#/screens/Deactivated'
|
||||
import {Takendown} from '#/screens/Takendown'
|
||||
@@ -108,7 +107,6 @@ function ShellInner() {
|
||||
</ErrorBoundary>
|
||||
</View>
|
||||
<Composer />
|
||||
<ModalsContainer />
|
||||
<MutedWordsDialog />
|
||||
<SigninDialog />
|
||||
<EmailDialog />
|
||||
|
||||
@@ -10,7 +10,6 @@ import {type NavigationProp} from '#/lib/routes/types'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useIsDrawerOpen, useSetDrawerOpen} from '#/state/shell'
|
||||
import {useCloseAllActiveElements} from '#/state/util'
|
||||
import {ModalsContainer} from '#/view/com/modals/Modal'
|
||||
import {ErrorBoundary} from '#/view/com/util/ErrorBoundary'
|
||||
import {Deactivated} from '#/screens/Deactivated'
|
||||
import {Takendown} from '#/screens/Takendown'
|
||||
@@ -65,7 +64,6 @@ function ShellInner() {
|
||||
<FlatNavigator layout={drawerLayout} />
|
||||
</ErrorBoundary>
|
||||
<Composer />
|
||||
<ModalsContainer />
|
||||
<MutedWordsDialog />
|
||||
<SigninDialog />
|
||||
<EmailDialog />
|
||||
|
||||
Reference in New Issue
Block a user