Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b2e8245c08 | |||
| 3d41a82c74 | |||
| 6de66ee472 | |||
| 8de4c2db61 | |||
| adb3c82d7c | |||
| f10360406f | |||
| 3e72838119 | |||
| bb733dc085 |
+2
-3
@@ -208,7 +208,7 @@
|
||||
"react-native-web-webview": "^1.0.2",
|
||||
"react-native-webview": "13.13.5",
|
||||
"react-remove-scroll-bar": "^2.3.8",
|
||||
"react-responsive": "^9.0.2",
|
||||
"react-responsive": "^10.0.1",
|
||||
"react-textarea-autosize": "^8.5.3",
|
||||
"rn-fetch-blob": "^0.12.0",
|
||||
"statsig-react-native-expo": "^4.6.1",
|
||||
@@ -238,8 +238,8 @@
|
||||
"@types/lodash.isequal": "^4.5.6",
|
||||
"@types/lodash.shuffle": "^4.2.7",
|
||||
"@types/psl": "^1.1.1",
|
||||
"@types/react": "^19.1.7",
|
||||
"@types/react-dom": "^19.1.2",
|
||||
"@types/react-responsive": "^8.0.5",
|
||||
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
||||
"@typescript-eslint/parser": "^7.18.0",
|
||||
"babel-jest": "^29.7.0",
|
||||
@@ -277,7 +277,6 @@
|
||||
"@expo/image-utils": "0.6.3",
|
||||
"@react-native/babel-preset": "0.79.2",
|
||||
"@react-native/normalize-colors": "0.79.2",
|
||||
"@types/react": "^18",
|
||||
"**/expo-constants": "17.0.3",
|
||||
"**/expo-device": "7.0.1",
|
||||
"**/zod": "3.23.8",
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/node_modules/@discord/bottom-sheet/src/hooks/useStableCallback.ts b/node_modules/@discord/bottom-sheet/src/hooks/useStableCallback.ts
|
||||
index 1c788ab..d30f330 100644
|
||||
--- a/node_modules/@discord/bottom-sheet/src/hooks/useStableCallback.ts
|
||||
+++ b/node_modules/@discord/bottom-sheet/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),
|
||||
[]
|
||||
+11
-8
@@ -58,6 +58,7 @@ import {Provider as ProgressGuideProvider} from '#/state/shell/progress-guide'
|
||||
import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed'
|
||||
import {Provider as StarterPackProvider} from '#/state/shell/starter-pack'
|
||||
import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies'
|
||||
import {Provider as UnstablePostSourceProvider} from '#/state/unstable-post-source'
|
||||
import {TestCtrls} from '#/view/com/testing/TestCtrls'
|
||||
import {Provider as VideoVolumeProvider} from '#/view/com/util/post-embeds/VideoVolumeContext'
|
||||
import * as Toast from '#/view/com/util/Toast'
|
||||
@@ -150,14 +151,16 @@ function InnerApp() {
|
||||
<MutedThreadsProvider>
|
||||
<ProgressGuideProvider>
|
||||
<ServiceAccountManager>
|
||||
<GestureHandlerRootView
|
||||
style={s.h100pct}>
|
||||
<IntentDialogProvider>
|
||||
<TestCtrls />
|
||||
<Shell />
|
||||
<NuxDialogs />
|
||||
</IntentDialogProvider>
|
||||
</GestureHandlerRootView>
|
||||
<UnstablePostSourceProvider>
|
||||
<GestureHandlerRootView
|
||||
style={s.h100pct}>
|
||||
<IntentDialogProvider>
|
||||
<TestCtrls />
|
||||
<Shell />
|
||||
<NuxDialogs />
|
||||
</IntentDialogProvider>
|
||||
</GestureHandlerRootView>
|
||||
</UnstablePostSourceProvider>
|
||||
</ServiceAccountManager>
|
||||
</ProgressGuideProvider>
|
||||
</MutedThreadsProvider>
|
||||
|
||||
+7
-4
@@ -48,6 +48,7 @@ import {Provider as ProgressGuideProvider} from '#/state/shell/progress-guide'
|
||||
import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed'
|
||||
import {Provider as StarterPackProvider} from '#/state/shell/starter-pack'
|
||||
import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies'
|
||||
import {Provider as UnstablePostSourceProvider} from '#/state/unstable-post-source'
|
||||
import {Provider as ActiveVideoProvider} from '#/view/com/util/post-embeds/ActiveVideoWebContext'
|
||||
import {Provider as VideoVolumeProvider} from '#/view/com/util/post-embeds/VideoVolumeContext'
|
||||
import * as Toast from '#/view/com/util/Toast'
|
||||
@@ -131,10 +132,12 @@ function InnerApp() {
|
||||
<SafeAreaProvider>
|
||||
<ProgressGuideProvider>
|
||||
<ServiceConfigProvider>
|
||||
<IntentDialogProvider>
|
||||
<Shell />
|
||||
<NuxDialogs />
|
||||
</IntentDialogProvider>
|
||||
<UnstablePostSourceProvider>
|
||||
<IntentDialogProvider>
|
||||
<Shell />
|
||||
<NuxDialogs />
|
||||
</IntentDialogProvider>
|
||||
</UnstablePostSourceProvider>
|
||||
</ServiceConfigProvider>
|
||||
</ProgressGuideProvider>
|
||||
</SafeAreaProvider>
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
import * as React from 'react'
|
||||
import {type JSX, useCallback, useRef} from 'react'
|
||||
import {i18n, type MessageDescriptor} from '@lingui/core'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {
|
||||
@@ -484,7 +484,7 @@ function commonScreens(Stack: typeof Flat, unreadCountLabel?: string) {
|
||||
* in 3 distinct tab-stacks with a different root screen on each.
|
||||
*/
|
||||
function TabsNavigator() {
|
||||
const tabBar = React.useCallback(
|
||||
const tabBar = useCallback(
|
||||
(props: JSX.IntrinsicAttributes & BottomTabBarProps) => (
|
||||
<BottomBar {...props} />
|
||||
),
|
||||
@@ -712,7 +712,7 @@ const LINKING = {
|
||||
function RoutesContainer({children}: React.PropsWithChildren<{}>) {
|
||||
const theme = useColorSchemeStyle(DefaultTheme, DarkTheme)
|
||||
const {currentAccount} = useSession()
|
||||
const prevLoggedRouteName = React.useRef<string | undefined>(undefined)
|
||||
const prevLoggedRouteName = useRef<string | undefined>(undefined)
|
||||
const emailDialogControl = useEmailDialogControl()
|
||||
|
||||
function onReady() {
|
||||
|
||||
@@ -3,7 +3,6 @@ import {type TextProps as RNTextProps} from 'react-native'
|
||||
import {type StyleProp, type TextStyle} from 'react-native'
|
||||
import {UITextView} from 'react-native-uitextview'
|
||||
import createEmojiRegex from 'emoji-regex'
|
||||
import type React from 'react'
|
||||
|
||||
import {isNative} from '#/platform/detection'
|
||||
import {isIOS} from '#/platform/detection'
|
||||
|
||||
@@ -65,8 +65,8 @@ export type ButtonState = {
|
||||
export type ButtonContext = VariantProps & ButtonState
|
||||
|
||||
type NonTextElements =
|
||||
| React.ReactElement
|
||||
| Iterable<React.ReactElement | null | undefined | boolean>
|
||||
| React.ReactElement<any>
|
||||
| Iterable<React.ReactElement<any> | null | undefined | boolean>
|
||||
|
||||
export type ButtonProps = Pick<
|
||||
PressableProps,
|
||||
|
||||
@@ -119,7 +119,8 @@ export function Root({children}: {children: React.ReactNode}) {
|
||||
const hoverablesSV = useSharedValue<
|
||||
Record<string, {id: string; rect: Measurement}>
|
||||
>({})
|
||||
const syncHoverablesThrottleRef = useRef<ReturnType<typeof setTimeout>>()
|
||||
const syncHoverablesThrottleRef =
|
||||
useRef<ReturnType<typeof setTimeout>>(undefined)
|
||||
const [hoveredMenuItem, setHoveredMenuItem] = useState<string | null>(null)
|
||||
|
||||
const onHoverableTouchUp = useCallback((id: string) => {
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
type ViewStyle,
|
||||
} from 'react-native'
|
||||
import {type SharedValue} from 'react-native-reanimated'
|
||||
import type React from 'react'
|
||||
|
||||
import type * as Dialog from '#/components/Dialog'
|
||||
import {
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
View,
|
||||
type ViewStyle,
|
||||
} from 'react-native'
|
||||
import type React from 'react'
|
||||
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {Text} from '#/components/Typography'
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import React from 'react'
|
||||
import type {
|
||||
AccessibilityProps,
|
||||
GestureResponderEvent,
|
||||
ScrollViewProps,
|
||||
import {
|
||||
type AccessibilityProps,
|
||||
type GestureResponderEvent,
|
||||
type ScrollViewProps,
|
||||
} from 'react-native'
|
||||
import {ViewStyle} from 'react-native'
|
||||
import {StyleProp} from 'react-native'
|
||||
import {type ViewStyle} from 'react-native'
|
||||
import {type StyleProp} from 'react-native'
|
||||
|
||||
import {ViewStyleProp} from '#/alf'
|
||||
import {BottomSheetViewProps} from '../../../modules/bottom-sheet'
|
||||
import {BottomSheetSnapPoint} from '../../../modules/bottom-sheet/src/BottomSheet.types'
|
||||
import {type ViewStyleProp} from '#/alf'
|
||||
import {type BottomSheetViewProps} from '../../../modules/bottom-sheet'
|
||||
import {type BottomSheetSnapPoint} from '../../../modules/bottom-sheet/src/BottomSheet.types'
|
||||
|
||||
type A11yProps = Required<AccessibilityProps>
|
||||
|
||||
@@ -34,7 +33,7 @@ export type DialogControlRefProps = {
|
||||
*/
|
||||
export type DialogControlProps = DialogControlRefProps & {
|
||||
id: string
|
||||
ref: React.RefObject<DialogControlRefProps>
|
||||
ref: React.RefObject<DialogControlRefProps | null>
|
||||
isOpen?: boolean
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
useState,
|
||||
} from 'react'
|
||||
|
||||
type Component = React.ReactElement
|
||||
type Component = React.ReactElement<any>
|
||||
|
||||
type ContextType = {
|
||||
outlet: Component | null
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
} from '@atproto/api'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import type React from 'react'
|
||||
|
||||
import {type Shadow} from '#/state/cache/post-shadow'
|
||||
import {EventStopper} from '#/view/com/util/EventStopper'
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import type React from 'react'
|
||||
|
||||
export type ProfileHoverCardProps = {
|
||||
children: React.ReactElement
|
||||
children: React.ReactElement<any>
|
||||
did: string
|
||||
inline?: boolean
|
||||
disable?: boolean
|
||||
|
||||
@@ -301,8 +301,8 @@ let Header = ({
|
||||
interestsDisplayNames,
|
||||
}: {
|
||||
guide: Follow10ProgressGuide
|
||||
inputRef: React.RefObject<TextInput>
|
||||
listRef: React.RefObject<ListMethods>
|
||||
inputRef: React.RefObject<TextInput | null>
|
||||
listRef: React.RefObject<ListMethods | null>
|
||||
onSelectTab: (v: string) => void
|
||||
searchText: string
|
||||
setHeaderHeight: (v: number) => void
|
||||
@@ -653,7 +653,7 @@ function SearchInput({
|
||||
}: {
|
||||
onChangeText: (text: string) => void
|
||||
onEscape: () => void
|
||||
inputRef: React.RefObject<TextInput>
|
||||
inputRef: React.RefObject<TextInput | null>
|
||||
defaultValue: string
|
||||
}) {
|
||||
const t = useTheme()
|
||||
|
||||
@@ -14,7 +14,7 @@ import {useLingui} from '@lingui/react'
|
||||
import {isWeb} from '#/platform/detection'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {Portal} from '#/components/Portal'
|
||||
import {AnimatedCheck, AnimatedCheckRef} from '../anim/AnimatedCheck'
|
||||
import {AnimatedCheck, type AnimatedCheckRef} from '../anim/AnimatedCheck'
|
||||
import {Text} from '../Typography'
|
||||
|
||||
export interface ProgressGuideToastRef {
|
||||
@@ -39,7 +39,7 @@ export const ProgressGuideToast = React.forwardRef<
|
||||
const translateY = useSharedValue(0)
|
||||
const opacity = useSharedValue(0)
|
||||
const animatedCheckRef = React.useRef<AnimatedCheckRef | null>(null)
|
||||
const timeoutRef = React.useRef<NodeJS.Timeout | undefined>()
|
||||
const timeoutRef = React.useRef<NodeJS.Timeout | undefined>(undefined)
|
||||
const winDim = useWindowDimensions()
|
||||
|
||||
/**
|
||||
|
||||
@@ -160,7 +160,7 @@ export type ContentProps<T> = {
|
||||
item: T,
|
||||
index: number,
|
||||
selectedValue?: string | null,
|
||||
) => React.ReactElement
|
||||
) => React.ReactElement<any>
|
||||
/*
|
||||
* Extracts the value from an item. Defaults to `item => item.value`
|
||||
*/
|
||||
|
||||
@@ -5,7 +5,7 @@ import React, {
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import {TextInput, View} from 'react-native'
|
||||
import {type TextInput, View} from 'react-native'
|
||||
import {useWindowDimensions} from 'react-native'
|
||||
import {Image} from 'expo-image'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
@@ -15,13 +15,13 @@ import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {cleanError} from '#/lib/strings/errors'
|
||||
import {isWeb} from '#/platform/detection'
|
||||
import {
|
||||
Gif,
|
||||
type Gif,
|
||||
useFeaturedGifsQuery,
|
||||
useGifSearchQuery,
|
||||
} from '#/state/queries/tenor'
|
||||
import {ErrorScreen} from '#/view/com/util/error/ErrorScreen'
|
||||
import {ErrorBoundary} from '#/view/com/util/ErrorBoundary'
|
||||
import {ListMethods} from '#/view/com/util/List'
|
||||
import {type ListMethods} from '#/view/com/util/List'
|
||||
import {atoms as a, ios, native, useBreakpoints, useTheme, web} from '#/alf'
|
||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||
import * as Dialog from '#/components/Dialog'
|
||||
@@ -36,7 +36,7 @@ export function GifSelectDialog({
|
||||
onClose,
|
||||
onSelectGif: onSelectGifProp,
|
||||
}: {
|
||||
controlRef: React.RefObject<{open: () => void}>
|
||||
controlRef: React.RefObject<{open: () => void} | null>
|
||||
onClose?: () => void
|
||||
onSelectGif: (gif: Gif) => void
|
||||
}) {
|
||||
|
||||
@@ -483,7 +483,7 @@ function SearchInput({
|
||||
value: string
|
||||
onChangeText: (text: string) => void
|
||||
onEscape: () => void
|
||||
inputRef: React.RefObject<TextInput>
|
||||
inputRef: React.RefObject<TextInput | null>
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
|
||||
@@ -3,7 +3,6 @@ import {Pressable, View} from 'react-native'
|
||||
import {type ChatBskyConvoDefs} from '@atproto/api'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import type React from 'react'
|
||||
|
||||
import {useConvoActive} from '#/state/messages/convo'
|
||||
import {useSession} from '#/state/session'
|
||||
|
||||
@@ -21,11 +21,14 @@ export function InputGroup(props: React.PropsWithChildren<{}>) {
|
||||
/>
|
||||
) : null}
|
||||
{React.cloneElement(child, {
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
style: [
|
||||
// @ts-expect-error
|
||||
...(Array.isArray(child.props?.style)
|
||||
? child.props.style
|
||||
: [child.props.style || {}]),
|
||||
? // @ts-expect-error
|
||||
child.props.style
|
||||
: // @ts-expect-error
|
||||
[child.props.style || {}]),
|
||||
{
|
||||
borderTopLeftRadius: i > 0 ? 0 : undefined,
|
||||
borderTopRightRadius: i > 0 ? 0 : undefined,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import React from 'react'
|
||||
import {
|
||||
AccessibilityProps,
|
||||
type AccessibilityProps,
|
||||
StyleSheet,
|
||||
TextInput,
|
||||
TextInputProps,
|
||||
TextStyle,
|
||||
type TextInputProps,
|
||||
type TextStyle,
|
||||
View,
|
||||
ViewStyle,
|
||||
type ViewStyle,
|
||||
} from 'react-native'
|
||||
|
||||
import {HITSLOP_20} from '#/lib/constants'
|
||||
@@ -16,17 +16,17 @@ import {
|
||||
applyFonts,
|
||||
atoms as a,
|
||||
ios,
|
||||
TextStyleProp,
|
||||
type TextStyleProp,
|
||||
useAlf,
|
||||
useTheme,
|
||||
web,
|
||||
} from '#/alf'
|
||||
import {useInteractionState} from '#/components/hooks/useInteractionState'
|
||||
import {Props as SVGIconProps} from '#/components/icons/common'
|
||||
import {type Props as SVGIconProps} from '#/components/icons/common'
|
||||
import {Text} from '#/components/Typography'
|
||||
|
||||
const Context = React.createContext<{
|
||||
inputRef: React.RefObject<TextInput> | null
|
||||
inputRef: React.RefObject<TextInput | null> | null
|
||||
isInvalid: boolean
|
||||
hovered: boolean
|
||||
onHoverIn: () => void
|
||||
@@ -140,7 +140,7 @@ export type InputProps = Omit<TextInputProps, 'value' | 'onChangeText'> & {
|
||||
value?: string
|
||||
onChangeText?: (value: string) => void
|
||||
isInvalid?: boolean
|
||||
inputRef?: React.RefObject<TextInput> | React.ForwardedRef<TextInput>
|
||||
inputRef?: React.RefObject<TextInput | null> | React.ForwardedRef<TextInput>
|
||||
}
|
||||
|
||||
export function createInput(Component: typeof TextInput) {
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import React from 'react'
|
||||
import {AccessibilityProps, TextStyle, View, ViewStyle} from 'react-native'
|
||||
import {
|
||||
type AccessibilityProps,
|
||||
type TextStyle,
|
||||
View,
|
||||
type ViewStyle,
|
||||
} from 'react-native'
|
||||
|
||||
import {atoms as a, native, useTheme} from '#/alf'
|
||||
import * as Toggle from '#/components/forms/Toggle'
|
||||
@@ -7,7 +12,7 @@ import {Text} from '#/components/Typography'
|
||||
|
||||
type ItemProps = Omit<Toggle.ItemProps, 'style' | 'role' | 'children'> &
|
||||
AccessibilityProps & {
|
||||
children: React.ReactElement
|
||||
children: React.ReactElement<any>
|
||||
testID?: string
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ function fullscreenSubscribe(onChange: () => void) {
|
||||
return () => document.removeEventListener('fullscreenchange', onChange)
|
||||
}
|
||||
|
||||
export function useFullscreen(ref?: React.RefObject<HTMLElement>) {
|
||||
export function useFullscreen(ref?: React.RefObject<HTMLElement | null>) {
|
||||
if (!isWeb) throw new Error("'useFullscreen' is a web-only hook")
|
||||
const isFullscreen = useSyncExternalStore(fullscreenSubscribe, () =>
|
||||
Boolean(document.fullscreenElement),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as React from 'react'
|
||||
import {useRef} from 'react'
|
||||
import {Animated} from 'react-native'
|
||||
|
||||
export function useAnimatedValue(initialValue: number) {
|
||||
const lazyRef = React.useRef<Animated.Value>()
|
||||
const lazyRef = useRef<Animated.Value>(undefined)
|
||||
|
||||
if (lazyRef.current === undefined) {
|
||||
lazyRef.current = new Animated.Value(initialValue)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import {Alert, AppState, AppStateStatus} from 'react-native'
|
||||
import {Alert, AppState, type AppStateStatus} from 'react-native'
|
||||
import {nativeBuildVersion} from 'expo-application'
|
||||
import {
|
||||
checkForUpdateAsync,
|
||||
@@ -35,7 +35,7 @@ export function useOTAUpdates() {
|
||||
const appState = React.useRef<AppStateStatus>('active')
|
||||
const lastMinimize = React.useRef(0)
|
||||
const ranInitialCheck = React.useRef(false)
|
||||
const timeout = React.useRef<NodeJS.Timeout>()
|
||||
const timeout = React.useRef<NodeJS.Timeout>(undefined)
|
||||
const {isUpdatePending} = useUpdates()
|
||||
|
||||
const setCheckTimeout = React.useCallback(() => {
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
import * as React from 'react'
|
||||
|
||||
/**
|
||||
* Helper hook to run persistent timers on views
|
||||
*/
|
||||
export function useTimer(time: number, handler: () => void) {
|
||||
const timer = React.useRef<undefined | NodeJS.Timeout>(undefined)
|
||||
|
||||
// function to restart the timer
|
||||
const reset = React.useCallback(() => {
|
||||
if (timer.current) {
|
||||
clearTimeout(timer.current)
|
||||
}
|
||||
timer.current = setTimeout(handler, time)
|
||||
}, [time, timer, handler])
|
||||
|
||||
// function to cancel the timer
|
||||
const cancel = React.useCallback(() => {
|
||||
if (timer.current) {
|
||||
clearTimeout(timer.current)
|
||||
timer.current = undefined
|
||||
}
|
||||
}, [timer])
|
||||
|
||||
// start the timer immediately
|
||||
React.useEffect(() => {
|
||||
reset()
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
return [reset, cancel]
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
* returns a ref callback function that can be used to merge multiple refs into a single ref.
|
||||
*/
|
||||
export function mergeRefs<T = any>(
|
||||
refs: Array<React.MutableRefObject<T> | React.LegacyRef<T>>,
|
||||
refs: Array<React.MutableRefObject<T> | React.Ref<T>>,
|
||||
): React.RefCallback<T> {
|
||||
return value => {
|
||||
refs.forEach(ref => {
|
||||
|
||||
@@ -10,8 +10,6 @@ export enum LogContext {
|
||||
ConversationAgent = 'conversation-agent',
|
||||
DMsAgent = 'dms-agent',
|
||||
ReportDialog = 'report-dialog',
|
||||
FeedFeedback = 'feed-feedback',
|
||||
PostSource = 'post-source',
|
||||
|
||||
/**
|
||||
* METRIC IS FOR INTERNAL USE ONLY, don't create any other loggers using this
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {ReactElement} from 'react'
|
||||
import {type ReactElement} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {ComAtprotoServerDescribeServer} from '@atproto/api'
|
||||
import {type ComAtprotoServerDescribeServer} from '@atproto/api'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
@@ -42,7 +42,7 @@ export const Policies = ({
|
||||
)
|
||||
}
|
||||
|
||||
let els: ReactElement
|
||||
let els: ReactElement<any>
|
||||
if (tos && pp) {
|
||||
els = (
|
||||
<Trans>
|
||||
|
||||
@@ -57,7 +57,7 @@ export function StepInfo({
|
||||
|
||||
const [hasWarnedEmail, setHasWarnedEmail] = React.useState<boolean>(false)
|
||||
|
||||
const tldtsRef = React.useRef<typeof tldts>()
|
||||
const tldtsRef = React.useRef<typeof tldts>(undefined)
|
||||
React.useEffect(() => {
|
||||
// @ts-expect-error - valid path
|
||||
import('tldts/dist/index.cjs.min.js').then(tldts => {
|
||||
|
||||
@@ -12,7 +12,7 @@ import throttle from 'lodash.throttle'
|
||||
|
||||
import {FEEDBACK_FEEDS, STAGING_FEEDS} from '#/lib/constants'
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {Logger} from '#/logger'
|
||||
import {logger} from '#/logger'
|
||||
import {
|
||||
type FeedDescriptor,
|
||||
type FeedPostSliceItem,
|
||||
@@ -20,8 +20,6 @@ import {
|
||||
import {getItemsForFeedback} from '#/view/com/posts/PostFeed'
|
||||
import {useAgent} from './session'
|
||||
|
||||
const logger = Logger.create(Logger.Context.FeedFeedback)
|
||||
|
||||
export type StateContext = {
|
||||
enabled: boolean
|
||||
onItemSeen: (item: any) => void
|
||||
@@ -91,7 +89,6 @@ export function useFeedFeedback(
|
||||
}
|
||||
sendOrAggregateInteractionsForStats(aggregatedStats.current, interactions)
|
||||
throttledFlushAggregatedStats()
|
||||
logger.debug('flushed')
|
||||
}, [agent, throttledFlushAggregatedStats, feed])
|
||||
|
||||
const sendToFeed = useMemo(
|
||||
@@ -144,9 +141,6 @@ export function useFeedFeedback(
|
||||
if (!enabled) {
|
||||
return
|
||||
}
|
||||
logger.debug('sendInteraction', {
|
||||
...interaction,
|
||||
})
|
||||
if (!history.current.has(interaction)) {
|
||||
history.current.add(interaction)
|
||||
queue.current.add(toString(interaction))
|
||||
|
||||
@@ -2,10 +2,10 @@ import React from 'react'
|
||||
import {
|
||||
AppBskyEmbedRecord,
|
||||
AppBskyEmbedRecordWithMedia,
|
||||
AppBskyFeedDefs,
|
||||
type AppBskyFeedDefs,
|
||||
AppBskyFeedPostgate,
|
||||
AtUri,
|
||||
BskyAgent,
|
||||
type BskyAgent,
|
||||
} from '@atproto/api'
|
||||
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
@@ -173,7 +173,7 @@ export function useToggleQuoteDetachmentMutation() {
|
||||
const agent = useAgent()
|
||||
const queryClient = useQueryClient()
|
||||
const getPosts = useGetPosts()
|
||||
const prevEmbed = React.useRef<AppBskyFeedDefs.PostView['embed']>()
|
||||
const prevEmbed = React.useRef<AppBskyFeedDefs.PostView['embed']>(undefined)
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import type React from 'react'
|
||||
|
||||
import {Provider as ColorModeProvider} from './color-mode'
|
||||
import {Provider as DrawerOpenProvider} from './drawer-open'
|
||||
import {Provider as DrawerSwipableProvider} from './drawer-swipe-disabled'
|
||||
|
||||
@@ -1,97 +1,73 @@
|
||||
import {useEffect, useId, useState} from 'react'
|
||||
import {type AppBskyFeedDefs, AtUri} from '@atproto/api'
|
||||
import {createContext, useCallback, useContext, useState} from 'react'
|
||||
import {type AppBskyFeedDefs} from '@atproto/api'
|
||||
|
||||
import {Logger} from '#/logger'
|
||||
import {type FeedDescriptor} from '#/state/queries/post-feed'
|
||||
import {type FeedDescriptor} from './queries/post-feed'
|
||||
|
||||
/**
|
||||
* Separate logger for better debugging
|
||||
* For passing the source of the post (i.e. the original post, from the feed) to the threadview,
|
||||
* without using query params. Deliberately unstable to avoid using query params, use for FeedFeedback
|
||||
* and other ephemeral non-critical systems.
|
||||
*/
|
||||
const logger = Logger.create(Logger.Context.PostSource)
|
||||
|
||||
export type PostSource = {
|
||||
type Source = {
|
||||
post: AppBskyFeedDefs.FeedViewPost
|
||||
feed?: FeedDescriptor
|
||||
}
|
||||
|
||||
/**
|
||||
* A cache of sources that will be consumed by the post thread view. This is
|
||||
* cleaned up any time a source is consumed.
|
||||
*/
|
||||
const transientSources = new Map<string, PostSource>()
|
||||
const SetUnstablePostSourceContext = createContext<
|
||||
(key: string, source: Source) => void
|
||||
>(() => {})
|
||||
const ConsumeUnstablePostSourceContext = createContext<
|
||||
(uri: string) => Source | undefined
|
||||
>(() => undefined)
|
||||
|
||||
/**
|
||||
* A cache of sources that have been consumed by the post thread view. This is
|
||||
* not cleaned up, but because we use a new ID for each post thread view that
|
||||
* consumes a source, this is never reused unless a user navigates back to a
|
||||
* post thread view that has not been dropped from memory.
|
||||
*/
|
||||
const consumedSources = new Map<string, PostSource>()
|
||||
export function Provider({children}: {children: React.ReactNode}) {
|
||||
const [sources, setSources] = useState<Map<string, Source>>(() => new Map())
|
||||
|
||||
/**
|
||||
* For stashing the feed that the user was browsing when they clicked on a post.
|
||||
*
|
||||
* Used for FeedFeedback and other ephemeral non-critical systems.
|
||||
*/
|
||||
export function setUnstablePostSource(key: string, source: PostSource) {
|
||||
assertValid(
|
||||
key,
|
||||
`setUnstablePostSource key should be a URI containing a handle, received ${key} — use buildPostSourceKey`,
|
||||
const setUnstablePostSource = useCallback((key: string, source: Source) => {
|
||||
setSources(prev => {
|
||||
const newMap = new Map(prev)
|
||||
newMap.set(key, source)
|
||||
return newMap
|
||||
})
|
||||
}, [])
|
||||
|
||||
const consumeUnstablePostSource = useCallback(
|
||||
(uri: string) => {
|
||||
const source = sources.get(uri)
|
||||
if (source) {
|
||||
setSources(prev => {
|
||||
const newMap = new Map(prev)
|
||||
newMap.delete(uri)
|
||||
return newMap
|
||||
})
|
||||
}
|
||||
return source
|
||||
},
|
||||
[sources],
|
||||
)
|
||||
logger.debug('set', {key, source})
|
||||
transientSources.set(key, source)
|
||||
|
||||
return (
|
||||
<SetUnstablePostSourceContext.Provider value={setUnstablePostSource}>
|
||||
<ConsumeUnstablePostSourceContext.Provider
|
||||
value={consumeUnstablePostSource}>
|
||||
{children}
|
||||
</ConsumeUnstablePostSourceContext.Provider>
|
||||
</SetUnstablePostSourceContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export function useSetUnstablePostSource() {
|
||||
return useContext(SetUnstablePostSourceContext)
|
||||
}
|
||||
|
||||
/**
|
||||
* This hook is unstable and should only be used for FeedFeedback and other
|
||||
* ephemeral non-critical systems. Views that use this hook will continue to
|
||||
* return a reference to the same source until those views are dropped from
|
||||
* memory.
|
||||
* DANGER - This hook is unstable and should only be used for FeedFeedback
|
||||
* and other ephemeral non-critical systems. Does not change when the URI changes.
|
||||
*/
|
||||
export function useUnstablePostSource(key: string) {
|
||||
const id = useId()
|
||||
const [source] = useState(() => {
|
||||
assertValid(
|
||||
key,
|
||||
`consumeUnstablePostSource key should be a URI containing a handle, received ${key} — use buildPostSourceKey`,
|
||||
)
|
||||
const source = consumedSources.get(id) || transientSources.get(key)
|
||||
if (source) {
|
||||
logger.debug('consume', {id, key, source})
|
||||
transientSources.delete(key)
|
||||
consumedSources.set(id, source)
|
||||
}
|
||||
return source
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
consumedSources.delete(id)
|
||||
logger.debug('cleanup', {id})
|
||||
}
|
||||
}, [id])
|
||||
export function useUnstablePostSource(uri: string) {
|
||||
const consume = useContext(ConsumeUnstablePostSourceContext)
|
||||
|
||||
const [source] = useState(() => consume(uri))
|
||||
return source
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a post source key. This (atm) is a URI where the `host` is the post
|
||||
* author's handle, not DID.
|
||||
*/
|
||||
export function buildPostSourceKey(key: string, handle: string) {
|
||||
const urip = new AtUri(key)
|
||||
urip.host = handle
|
||||
return urip.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Just a lil dev helper
|
||||
*/
|
||||
function assertValid(key: string, message: string) {
|
||||
if (__DEV__) {
|
||||
const urip = new AtUri(key)
|
||||
if (urip.host.startsWith('did:')) {
|
||||
throw new Error(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ export const ComposePost = ({
|
||||
videoUri: initVideoUri,
|
||||
cancelRef,
|
||||
}: Props & {
|
||||
cancelRef?: React.RefObject<CancelRef>
|
||||
cancelRef?: React.RefObject<CancelRef | null>
|
||||
}) => {
|
||||
const {currentAccount} = useSession()
|
||||
const agent = useAgent()
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import type React from 'react'
|
||||
|
||||
import {type ComposerImage} from '#/state/gallery'
|
||||
import type * as Dialog from '#/components/Dialog'
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ function EditImageInner({
|
||||
aspectRatio,
|
||||
}: Required<Pick<EditImageDialogProps, 'image'>> &
|
||||
Omit<EditImageDialogProps, 'control' | 'image'> & {
|
||||
saveRef: React.RefObject<{save: () => Promise<void>}>
|
||||
saveRef: React.RefObject<{save: () => Promise<void>} | null>
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const [isDragging, setIsDragging] = useState(false)
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
import {useCallback, useEffect, useMemo, useRef, useState} from 'react'
|
||||
import {
|
||||
type JSX,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {type AppBskyActorDefs, AppBskyFeedDefs} from '@atproto/api'
|
||||
import {msg} from '@lingui/macro'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {type JSX} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {type JSX} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import Animated from 'react-native-reanimated'
|
||||
import {msg} from '@lingui/macro'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, {useCallback} from 'react'
|
||||
import React, {type JSX, useCallback} from 'react'
|
||||
import {Dimensions, type StyleProp, View, type ViewStyle} from 'react-native'
|
||||
import {type AppBskyGraphDefs} from '@atproto/api'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import React from 'react'
|
||||
import React, {type JSX} from 'react'
|
||||
import {
|
||||
ActivityIndicator,
|
||||
FlatList as RNFlatList,
|
||||
RefreshControl,
|
||||
StyleProp,
|
||||
type StyleProp,
|
||||
View,
|
||||
ViewStyle,
|
||||
type ViewStyle,
|
||||
} from 'react-native'
|
||||
import {AppBskyGraphDefs as GraphDefs} from '@atproto/api'
|
||||
import {type AppBskyGraphDefs as GraphDefs} from '@atproto/api'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
@@ -16,7 +16,7 @@ import {cleanError} from '#/lib/strings/errors'
|
||||
import {s} from '#/lib/styles'
|
||||
import {logger} from '#/logger'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {MyListsFilter, useMyListsQuery} from '#/state/queries/my-lists'
|
||||
import {type MyListsFilter, useMyListsQuery} from '#/state/queries/my-lists'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {BulletList_Stroke2_Corner0_Rounded as ListIcon} from '#/components/icons/BulletList'
|
||||
import * as ListCard from '#/components/ListCard'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import React, {type JSX} from 'react'
|
||||
import {
|
||||
ActivityIndicator,
|
||||
type ListRenderItemInfo,
|
||||
|
||||
@@ -230,7 +230,7 @@ let NotificationFeedItem = ({
|
||||
: ''
|
||||
|
||||
let a11yLabel = ''
|
||||
let notificationContent: ReactElement
|
||||
let notificationContent: ReactElement<any>
|
||||
let icon = (
|
||||
<HeartIconFilled
|
||||
size="xl"
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import React, {forwardRef, useCallback, useContext} from 'react'
|
||||
import React, {forwardRef, type JSX, useCallback, useContext} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {DrawerGestureContext} from 'react-native-drawer-layout'
|
||||
import {Gesture, GestureDetector} from 'react-native-gesture-handler'
|
||||
import PagerView, {
|
||||
PagerViewOnPageScrollEventData,
|
||||
PagerViewOnPageSelectedEvent,
|
||||
PagerViewOnPageSelectedEventData,
|
||||
PageScrollStateChangedNativeEventData,
|
||||
type PagerViewOnPageScrollEventData,
|
||||
type PagerViewOnPageSelectedEvent,
|
||||
type PagerViewOnPageSelectedEventData,
|
||||
type PageScrollStateChangedNativeEventData,
|
||||
} from 'react-native-pager-view'
|
||||
import Animated, {
|
||||
runOnJS,
|
||||
SharedValue,
|
||||
type SharedValue,
|
||||
useEvent,
|
||||
useHandler,
|
||||
useSharedValue,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import React, {type JSX} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {flushSync} from 'react-dom'
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import * as React from 'react'
|
||||
import React, {type JSX} from 'react'
|
||||
import {
|
||||
LayoutChangeEvent,
|
||||
NativeScrollEvent,
|
||||
ScrollView,
|
||||
type LayoutChangeEvent,
|
||||
type NativeScrollEvent,
|
||||
type ScrollView,
|
||||
StyleSheet,
|
||||
View,
|
||||
} from 'react-native'
|
||||
import Animated, {
|
||||
AnimatedRef,
|
||||
type AnimatedRef,
|
||||
runOnJS,
|
||||
runOnUI,
|
||||
scrollTo,
|
||||
SharedValue,
|
||||
type SharedValue,
|
||||
useAnimatedRef,
|
||||
useAnimatedStyle,
|
||||
useSharedValue,
|
||||
@@ -20,9 +20,13 @@ import Animated, {
|
||||
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
||||
import {ScrollProvider} from '#/lib/ScrollContext'
|
||||
import {isIOS} from '#/platform/detection'
|
||||
import {Pager, PagerRef, RenderTabBarFnProps} from '#/view/com/pager/Pager'
|
||||
import {
|
||||
Pager,
|
||||
type PagerRef,
|
||||
type RenderTabBarFnProps,
|
||||
} from '#/view/com/pager/Pager'
|
||||
import {useTheme} from '#/alf'
|
||||
import {ListMethods} from '../util/List'
|
||||
import {type ListMethods} from '../util/List'
|
||||
import {PagerHeaderProvider} from './PagerHeaderContext'
|
||||
import {TabBar} from './TabBar'
|
||||
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import * as React from 'react'
|
||||
import {ScrollView, View} from 'react-native'
|
||||
import React, {type JSX} from 'react'
|
||||
import {type ScrollView, View} from 'react-native'
|
||||
import {useAnimatedRef} from 'react-native-reanimated'
|
||||
|
||||
import {Pager, PagerRef, RenderTabBarFnProps} from '#/view/com/pager/Pager'
|
||||
import {
|
||||
Pager,
|
||||
type PagerRef,
|
||||
type RenderTabBarFnProps,
|
||||
} from '#/view/com/pager/Pager'
|
||||
import {atoms as a, web} from '#/alf'
|
||||
import * as Layout from '#/components/Layout'
|
||||
import {ListMethods} from '../util/List'
|
||||
import {type ListMethods} from '../util/List'
|
||||
import {TabBar} from './TabBar'
|
||||
|
||||
export interface PagerWithHeaderChildParams {
|
||||
|
||||
@@ -106,7 +106,9 @@ export function TabBar({
|
||||
<PressableWithHover
|
||||
testID={`${testID}-selector-${i}`}
|
||||
key={`${item}-${i}`}
|
||||
ref={node => (itemRefs.current[i] = node as any)}
|
||||
ref={node => {
|
||||
itemRefs.current[i] = node as any
|
||||
}}
|
||||
style={styles.item}
|
||||
hoverStyle={t.atoms.bg_contrast_25}
|
||||
onPress={() => onPressItem(i)}
|
||||
|
||||
@@ -22,7 +22,6 @@ import {ScrollProvider} from '#/lib/ScrollContext'
|
||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||
import {cleanError} from '#/lib/strings/errors'
|
||||
import {isAndroid, isNative, isWeb} from '#/platform/detection'
|
||||
import {useFeedFeedback} from '#/state/feed-feedback'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {
|
||||
fillThreadModerationCache,
|
||||
@@ -38,7 +37,6 @@ import {useSetThreadViewPreferencesMutation} from '#/state/queries/preferences'
|
||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
|
||||
import {useUnstablePostSource} from '#/state/unstable-post-source'
|
||||
import {List, type ListMethods} from '#/view/com/util/List'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {Button, ButtonIcon} from '#/components/Button'
|
||||
@@ -95,7 +93,7 @@ const keyExtractor = (item: RowItem) => {
|
||||
return item._reactKey
|
||||
}
|
||||
|
||||
export function PostThread({uri}: {uri: string}) {
|
||||
export function PostThread({uri}: {uri: string | undefined}) {
|
||||
const {hasSession, currentAccount} = useSession()
|
||||
const {_} = useLingui()
|
||||
const t = useTheme()
|
||||
@@ -106,8 +104,6 @@ export function PostThread({uri}: {uri: string}) {
|
||||
HiddenRepliesState.Hide,
|
||||
)
|
||||
const headerRef = React.useRef<View | null>(null)
|
||||
const anchorPostSource = useUnstablePostSource(uri)
|
||||
const feedFeedback = useFeedFeedback(anchorPostSource?.feed, hasSession)
|
||||
|
||||
const {data: preferences} = usePreferencesQuery()
|
||||
const {
|
||||
@@ -399,18 +395,10 @@ export function PostThread({uri}: {uri: string}) {
|
||||
)
|
||||
|
||||
const {openComposer} = useOpenComposer()
|
||||
const onReplyToAnchor = React.useCallback(() => {
|
||||
const onPressReply = React.useCallback(() => {
|
||||
if (thread?.type !== 'post') {
|
||||
return
|
||||
}
|
||||
if (anchorPostSource) {
|
||||
feedFeedback.sendInteraction({
|
||||
item: thread.post.uri,
|
||||
event: 'app.bsky.feed.defs#interactionReply',
|
||||
feedContext: anchorPostSource.post.feedContext,
|
||||
reqId: anchorPostSource.post.reqId,
|
||||
})
|
||||
}
|
||||
openComposer({
|
||||
replyTo: {
|
||||
uri: thread.post.uri,
|
||||
@@ -422,14 +410,7 @@ export function PostThread({uri}: {uri: string}) {
|
||||
},
|
||||
onPost: onPostReply,
|
||||
})
|
||||
}, [
|
||||
openComposer,
|
||||
thread,
|
||||
onPostReply,
|
||||
threadModerationCache,
|
||||
anchorPostSource,
|
||||
feedFeedback,
|
||||
])
|
||||
}, [openComposer, thread, onPostReply, threadModerationCache])
|
||||
|
||||
const canReply = !error && rootPost && !rootPost.viewer?.replyDisabled
|
||||
const hasParents =
|
||||
@@ -442,7 +423,7 @@ export function PostThread({uri}: {uri: string}) {
|
||||
return (
|
||||
<View>
|
||||
{!isMobile && (
|
||||
<PostThreadComposePrompt onPressCompose={onReplyToAnchor} />
|
||||
<PostThreadComposePrompt onPressCompose={onPressReply} />
|
||||
)}
|
||||
</View>
|
||||
)
|
||||
@@ -530,7 +511,6 @@ export function PostThread({uri}: {uri: string}) {
|
||||
}
|
||||
onPostReply={onPostReply}
|
||||
hideTopBorder={index === 0 && !item.ctx.isParentLoading}
|
||||
anchorPostSource={anchorPostSource}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
@@ -606,7 +586,7 @@ export function PostThread({uri}: {uri: string}) {
|
||||
/>
|
||||
</ScrollProvider>
|
||||
{isMobile && canReply && hasSession && (
|
||||
<MobileComposePrompt onPressReply={onReplyToAnchor} />
|
||||
<MobileComposePrompt onPressReply={onPressReply} />
|
||||
)}
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -40,7 +40,7 @@ import {useLanguagePrefs} from '#/state/preferences'
|
||||
import {type ThreadPost} from '#/state/queries/post-thread'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
|
||||
import {type PostSource} from '#/state/unstable-post-source'
|
||||
import {useUnstablePostSource} from '#/state/unstable-post-source'
|
||||
import {PostThreadFollowBtn} from '#/view/com/post-thread/PostThreadFollowBtn'
|
||||
import {ErrorMessage} from '#/view/com/util/error/ErrorMessage'
|
||||
import {Link, TextLink} from '#/view/com/util/Link'
|
||||
@@ -87,7 +87,6 @@ export function PostThreadItem({
|
||||
onPostReply,
|
||||
hideTopBorder,
|
||||
threadgateRecord,
|
||||
anchorPostSource,
|
||||
}: {
|
||||
post: AppBskyFeedDefs.PostView
|
||||
record: AppBskyFeedPost.Record
|
||||
@@ -105,7 +104,6 @@ export function PostThreadItem({
|
||||
onPostReply: (postUri: string | undefined) => void
|
||||
hideTopBorder?: boolean
|
||||
threadgateRecord?: AppBskyFeedThreadgate.Record
|
||||
anchorPostSource?: PostSource
|
||||
}) {
|
||||
const postShadowed = usePostShadow(post)
|
||||
const richText = useMemo(
|
||||
@@ -141,7 +139,6 @@ export function PostThreadItem({
|
||||
onPostReply={onPostReply}
|
||||
hideTopBorder={hideTopBorder}
|
||||
threadgateRecord={threadgateRecord}
|
||||
anchorPostSource={anchorPostSource}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -187,7 +184,6 @@ let PostThreadItemLoaded = ({
|
||||
onPostReply,
|
||||
hideTopBorder,
|
||||
threadgateRecord,
|
||||
anchorPostSource,
|
||||
}: {
|
||||
post: Shadow<AppBskyFeedDefs.PostView>
|
||||
record: AppBskyFeedPost.Record
|
||||
@@ -206,10 +202,10 @@ let PostThreadItemLoaded = ({
|
||||
onPostReply: (postUri: string | undefined) => void
|
||||
hideTopBorder?: boolean
|
||||
threadgateRecord?: AppBskyFeedThreadgate.Record
|
||||
anchorPostSource?: PostSource
|
||||
}): React.ReactNode => {
|
||||
const {currentAccount, hasSession} = useSession()
|
||||
const feedFeedback = useFeedFeedback(anchorPostSource?.feed, hasSession)
|
||||
const source = useUnstablePostSource(post.uri)
|
||||
const feedFeedback = useFeedFeedback(source?.feed, hasSession)
|
||||
|
||||
const t = useTheme()
|
||||
const pal = usePalette('default')
|
||||
@@ -280,12 +276,12 @@ let PostThreadItemLoaded = ({
|
||||
)
|
||||
|
||||
const onPressReply = () => {
|
||||
if (anchorPostSource && isHighlightedPost) {
|
||||
if (source) {
|
||||
feedFeedback.sendInteraction({
|
||||
item: post.uri,
|
||||
event: 'app.bsky.feed.defs#interactionReply',
|
||||
feedContext: anchorPostSource.post.feedContext,
|
||||
reqId: anchorPostSource.post.reqId,
|
||||
feedContext: source.post.feedContext,
|
||||
reqId: source.post.reqId,
|
||||
})
|
||||
}
|
||||
openComposer({
|
||||
@@ -302,23 +298,23 @@ let PostThreadItemLoaded = ({
|
||||
}
|
||||
|
||||
const onOpenAuthor = () => {
|
||||
if (anchorPostSource) {
|
||||
if (source) {
|
||||
feedFeedback.sendInteraction({
|
||||
item: post.uri,
|
||||
event: 'app.bsky.feed.defs#clickthroughAuthor',
|
||||
feedContext: anchorPostSource.post.feedContext,
|
||||
reqId: anchorPostSource.post.reqId,
|
||||
feedContext: source.post.feedContext,
|
||||
reqId: source.post.reqId,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const onOpenEmbed = () => {
|
||||
if (anchorPostSource) {
|
||||
if (source) {
|
||||
feedFeedback.sendInteraction({
|
||||
item: post.uri,
|
||||
event: 'app.bsky.feed.defs#clickthroughEmbed',
|
||||
feedContext: anchorPostSource.post.feedContext,
|
||||
reqId: anchorPostSource.post.reqId,
|
||||
feedContext: source.post.feedContext,
|
||||
reqId: source.post.reqId,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -329,7 +325,7 @@ let PostThreadItemLoaded = ({
|
||||
|
||||
const {isActive: live} = useActorStatus(post.author)
|
||||
|
||||
const reason = anchorPostSource?.post.reason
|
||||
const reason = source?.post.reason
|
||||
const viaRepost = useMemo(() => {
|
||||
if (AppBskyFeedDefs.isReasonRepost(reason) && reason.uri && reason.cid) {
|
||||
return {
|
||||
@@ -554,8 +550,8 @@ let PostThreadItemLoaded = ({
|
||||
onPostReply={onPostReply}
|
||||
logContext="PostThreadItem"
|
||||
threadgateRecord={threadgateRecord}
|
||||
feedContext={anchorPostSource?.post?.feedContext}
|
||||
reqId={anchorPostSource?.post?.reqId}
|
||||
feedContext={source?.post?.feedContext}
|
||||
reqId={source?.post?.reqId}
|
||||
viaRepost={viaRepost}
|
||||
/>
|
||||
</FeedFeedbackProvider>
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import * as React from 'react'
|
||||
import {useMemo} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {AppBskyFeedDefs, AtUri} from '@atproto/api'
|
||||
import {type AppBskyFeedDefs, AtUri} from '@atproto/api'
|
||||
import {Trans} from '@lingui/macro'
|
||||
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
import {Link} from '#/view/com/util/Link'
|
||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {Link} from '../util/Link'
|
||||
import {UserAvatar} from '../util/UserAvatar'
|
||||
|
||||
export function PostThreadLoadMore({post}: {post: AppBskyFeedDefs.PostView}) {
|
||||
const t = useTheme()
|
||||
|
||||
const postHref = React.useMemo(() => {
|
||||
const postHref = useMemo(() => {
|
||||
const urip = new AtUri(post.uri)
|
||||
return makeProfileLink(post.author, 'post', urip.rkey)
|
||||
}, [post.uri, post.author])
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
import {memo, useCallback, useEffect, useMemo, useRef, useState} from 'react'
|
||||
import {
|
||||
type JSX,
|
||||
memo,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import {
|
||||
ActivityIndicator,
|
||||
AppState,
|
||||
|
||||
@@ -36,10 +36,7 @@ import {useFeedFeedbackContext} from '#/state/feed-feedback'
|
||||
import {unstableCacheProfileView} from '#/state/queries/profile'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
|
||||
import {
|
||||
buildPostSourceKey,
|
||||
setUnstablePostSource,
|
||||
} from '#/state/unstable-post-source'
|
||||
import {useSetUnstablePostSource} from '#/state/unstable-post-source'
|
||||
import {FeedNameText} from '#/view/com/util/FeedInfoText'
|
||||
import {Link, TextLink, TextLinkOnWebOnly} from '#/view/com/util/Link'
|
||||
import {PostEmbeds, PostEmbedViewContext} from '#/view/com/util/post-embeds'
|
||||
@@ -179,6 +176,7 @@ let FeedItemInner = ({
|
||||
return makeProfileLink(post.author, 'post', urip.rkey)
|
||||
}, [post.uri, post.author])
|
||||
const {sendInteraction, feedDescriptor} = useFeedFeedbackContext()
|
||||
const unstableSetPostSource = useSetUnstablePostSource()
|
||||
|
||||
const onPressReply = () => {
|
||||
sendInteraction({
|
||||
@@ -234,7 +232,7 @@ let FeedItemInner = ({
|
||||
reqId,
|
||||
})
|
||||
unstableCacheProfileView(queryClient, post.author)
|
||||
setUnstablePostSource(buildPostSourceKey(post.uri, post.author.handle), {
|
||||
unstableSetPostSource(post.uri, {
|
||||
feed: feedDescriptor,
|
||||
post: {
|
||||
post,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {View, type ViewStyle} from 'react-native'
|
||||
import type React from 'react'
|
||||
|
||||
/**
|
||||
* This utility function captures events and stops
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {memo, useCallback, useMemo} from 'react'
|
||||
import {type JSX, memo, useCallback, useMemo} from 'react'
|
||||
import {
|
||||
type GestureResponderEvent,
|
||||
Platform,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, {memo} from 'react'
|
||||
import {RefreshControl, ViewToken} from 'react-native'
|
||||
import {RefreshControl, type ViewToken} from 'react-native'
|
||||
import {
|
||||
FlatListPropsWithLayout,
|
||||
type FlatListPropsWithLayout,
|
||||
runOnJS,
|
||||
useSharedValue,
|
||||
} from 'react-native-reanimated'
|
||||
@@ -57,7 +57,7 @@ let List = React.forwardRef<ListMethods, ListProps>(
|
||||
...props
|
||||
},
|
||||
ref,
|
||||
): React.ReactElement => {
|
||||
): React.ReactElement<any> => {
|
||||
const isScrolledDown = useSharedValue(false)
|
||||
const t = useTheme()
|
||||
const dedupe = useDedupe(400)
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
import React, {isValidElement, memo, startTransition, useRef} from 'react'
|
||||
import {FlatListProps, StyleSheet, View, ViewProps} from 'react-native'
|
||||
import {ReanimatedScrollEvent} from 'react-native-reanimated/lib/typescript/hook/commonTypes'
|
||||
import React, {
|
||||
isValidElement,
|
||||
type JSX,
|
||||
memo,
|
||||
startTransition,
|
||||
useRef,
|
||||
} from 'react'
|
||||
import {
|
||||
type FlatListProps,
|
||||
StyleSheet,
|
||||
View,
|
||||
type ViewProps,
|
||||
} from 'react-native'
|
||||
import {type ReanimatedScrollEvent} from 'react-native-reanimated/lib/typescript/hook/commonTypes'
|
||||
|
||||
import {batchedUpdates} from '#/lib/batchedUpdates'
|
||||
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
||||
@@ -377,10 +388,10 @@ function EdgeVisibility({
|
||||
containerRef,
|
||||
onVisibleChange,
|
||||
}: {
|
||||
root?: React.RefObject<HTMLDivElement> | null
|
||||
root?: React.RefObject<HTMLDivElement | null> | null
|
||||
topMargin?: string
|
||||
bottomMargin?: string
|
||||
containerRef: React.RefObject<Element>
|
||||
containerRef: React.RefObject<Element | null>
|
||||
onVisibleChange: (isVisible: boolean) => void
|
||||
}) {
|
||||
const [containerHeight, setContainerHeight] = React.useState(0)
|
||||
@@ -399,7 +410,7 @@ function EdgeVisibility({
|
||||
}
|
||||
|
||||
function useResizeObserver(
|
||||
ref: React.RefObject<Element>,
|
||||
ref: React.RefObject<Element | null>,
|
||||
onResize: undefined | ((w: number, h: number) => void),
|
||||
) {
|
||||
const handleResize = useNonReactiveCallback(onResize ?? (() => {}))
|
||||
@@ -504,7 +515,7 @@ let Visibility = ({
|
||||
onVisibleChange,
|
||||
style,
|
||||
}: {
|
||||
root?: React.RefObject<HTMLDivElement> | null
|
||||
root?: React.RefObject<HTMLDivElement | null> | null
|
||||
topMargin?: string
|
||||
bottomMargin?: string
|
||||
onVisibleChange: (isVisible: boolean) => void
|
||||
@@ -546,7 +557,7 @@ Visibility = React.memo(Visibility)
|
||||
|
||||
export const List = memo(React.forwardRef(ListImpl)) as <ItemT>(
|
||||
props: ListProps<ItemT> & {ref?: React.Ref<ListMethods>},
|
||||
) => React.ReactElement
|
||||
) => React.ReactElement<any>
|
||||
|
||||
// https://stackoverflow.com/questions/7944460/detect-safari-browser
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import {type AppBskyActorDefs, type ModerationDecision} from '@atproto/api'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
import type React from 'react'
|
||||
|
||||
import {useActorStatus} from '#/lib/actor-status'
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import {I18n} from '@lingui/core'
|
||||
import React, {type JSX} from 'react'
|
||||
import {type I18n} from '@lingui/core'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {useGetTimeAgo} from '#/lib/hooks/useTimeAgo'
|
||||
|
||||
@@ -68,7 +68,7 @@ function Toast({
|
||||
}, 1e3)
|
||||
}
|
||||
|
||||
const destroyTimeoutRef = useRef<ReturnType<typeof setTimeout>>()
|
||||
const destroyTimeoutRef = useRef<ReturnType<typeof setTimeout>>(undefined)
|
||||
const hideAndDestroyAfterTimeout = useNonReactiveCallback(() => {
|
||||
clearTimeout(destroyTimeoutRef.current)
|
||||
destroyTimeoutRef.current = setTimeout(hideAndDestroyImmediately, TIMEOUT)
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
type FontAwesomeIconStyle,
|
||||
type Props as FontAwesomeProps,
|
||||
} from '@fortawesome/react-native-fontawesome'
|
||||
import type React from 'react'
|
||||
|
||||
const DURATION = 3500
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import {type JSX} from 'react'
|
||||
|
||||
import {Header} from '#/components/Layout'
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, {useEffect, useState} from 'react'
|
||||
import React, {type JSX, useEffect, useState} from 'react'
|
||||
import {
|
||||
NativeScrollEvent,
|
||||
NativeSyntheticEvent,
|
||||
type NativeScrollEvent,
|
||||
type NativeSyntheticEvent,
|
||||
Pressable,
|
||||
RefreshControl,
|
||||
ScrollView,
|
||||
@@ -36,7 +36,7 @@ export const ViewSelector = React.forwardRef<
|
||||
renderItem: (item: any) => JSX.Element
|
||||
ListFooterComponent?:
|
||||
| React.ComponentType<any>
|
||||
| React.ReactElement
|
||||
| React.ReactElement<any>
|
||||
| null
|
||||
| undefined
|
||||
onSelectView?: (viewIndex: number) => void
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {ComponentProps} from 'react'
|
||||
import {StyleSheet, TouchableWithoutFeedback} from 'react-native'
|
||||
import {type ComponentProps, type JSX} from 'react'
|
||||
import {StyleSheet, type TouchableWithoutFeedback} from 'react-native'
|
||||
import Animated from 'react-native-reanimated'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
import {LinearGradient} from 'expo-linear-gradient'
|
||||
|
||||
@@ -158,7 +158,7 @@ function DropdownContent({
|
||||
menuRef,
|
||||
}: {
|
||||
items: DropdownItem[]
|
||||
menuRef: React.RefObject<HTMLDivElement>
|
||||
menuRef: React.RefObject<HTMLDivElement | null>
|
||||
}) {
|
||||
const pal = usePalette('default')
|
||||
const theme = useTheme()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, {useCallback, useState} from 'react'
|
||||
import {ActivityIndicator, View} from 'react-native'
|
||||
import {ImageBackground} from 'expo-image'
|
||||
import {AppBskyEmbedVideo} from '@atproto/api'
|
||||
import {type AppBskyEmbedVideo} from '@atproto/api'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, {useCallback, useEffect, useRef, useState} from 'react'
|
||||
import {useCallback, useEffect, useRef, useState} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {AppBskyEmbedVideo} from '@atproto/api'
|
||||
import {type AppBskyEmbedVideo} from '@atproto/api'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
@@ -30,7 +30,7 @@ export function VideoEmbed({
|
||||
useActiveVideoWeb()
|
||||
const [onScreen, setOnScreen] = useState(false)
|
||||
const [isFullscreen] = useFullscreen()
|
||||
const lastKnownTime = useRef<number | undefined>()
|
||||
const lastKnownTime = useRef<number | undefined>(undefined)
|
||||
|
||||
useEffect(() => {
|
||||
if (!ref.current) return
|
||||
|
||||
@@ -139,7 +139,7 @@ function useHLS({
|
||||
playlist: string
|
||||
setHasSubtitleTrack: (v: boolean) => void
|
||||
setError: (v: Error | null) => void
|
||||
videoRef: React.RefObject<HTMLVideoElement>
|
||||
videoRef: React.RefObject<HTMLVideoElement | null>
|
||||
setHlsLoading: (v: boolean) => void
|
||||
}) {
|
||||
const [Hls, setHls] = useState<typeof HlsTypes.default | undefined>(
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from 'react'
|
||||
import {SvgProps} from 'react-native-svg'
|
||||
import {type SvgProps} from 'react-native-svg'
|
||||
|
||||
import {atoms as a, useTheme, web} from '#/alf'
|
||||
import {PressableWithHover} from '../../../PressableWithHover'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, {useCallback, useEffect, useRef, useState} from 'react'
|
||||
import {useCallback, useEffect, useRef, useState} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, {useCallback, useEffect, useRef, useState} from 'react'
|
||||
import {useCallback, useEffect, useRef, useState} from 'react'
|
||||
import {Pressable, View} from 'react-native'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
@@ -46,14 +46,14 @@ export function Controls({
|
||||
hlsLoading,
|
||||
hasSubtitleTrack,
|
||||
}: {
|
||||
videoRef: React.RefObject<HTMLVideoElement>
|
||||
hlsRef: React.RefObject<Hls | undefined>
|
||||
videoRef: React.RefObject<HTMLVideoElement | null>
|
||||
hlsRef: React.RefObject<Hls | undefined | null>
|
||||
active: boolean
|
||||
setActive: () => void
|
||||
focused: boolean
|
||||
setFocused: (focused: boolean) => void
|
||||
onScreen: boolean
|
||||
fullscreenRef: React.RefObject<HTMLDivElement>
|
||||
fullscreenRef: React.RefObject<HTMLDivElement | null>
|
||||
hlsLoading: boolean
|
||||
hasSubtitleTrack: boolean
|
||||
}) {
|
||||
@@ -232,7 +232,7 @@ export function Controls({
|
||||
}, [onSeek, videoRef])
|
||||
|
||||
const [showCursor, setShowCursor] = useState(true)
|
||||
const cursorTimeoutRef = useRef<ReturnType<typeof setTimeout>>()
|
||||
const cursorTimeoutRef = useRef<ReturnType<typeof setTimeout>>(undefined)
|
||||
const onPointerMoveEmptySpace = useCallback(() => {
|
||||
setShowCursor(true)
|
||||
if (cursorTimeoutRef.current) {
|
||||
@@ -264,7 +264,7 @@ export function Controls({
|
||||
[hovered],
|
||||
)
|
||||
|
||||
const timeoutRef = useRef<ReturnType<typeof setTimeout>>()
|
||||
const timeoutRef = useRef<ReturnType<typeof setTimeout>>(undefined)
|
||||
|
||||
const onHoverWithTimeout = useCallback(() => {
|
||||
onHover()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, {useCallback} from 'react'
|
||||
import {useCallback} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import Animated, {FadeIn, FadeOut} from 'react-native-reanimated'
|
||||
import {msg} from '@lingui/macro'
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React, {useCallback, useEffect, useRef, useState} from 'react'
|
||||
import {useCallback, useEffect, useRef, useState} from 'react'
|
||||
|
||||
import {isSafari} from '#/lib/browser'
|
||||
import {useVideoVolumeState} from '../../VideoVolumeContext'
|
||||
|
||||
export function useVideoElement(ref: React.RefObject<HTMLVideoElement>) {
|
||||
export function useVideoElement(ref: React.RefObject<HTMLVideoElement | null>) {
|
||||
const [playing, setPlaying] = useState(false)
|
||||
const [muted, setMuted] = useState(true)
|
||||
const [currentTime, setCurrentTime] = useState(0)
|
||||
|
||||
@@ -22,7 +22,7 @@ export function Dialogs() {
|
||||
React.useState<boolean>()
|
||||
const [shouldRenderUnmountTest, setShouldRenderUnmountTest] =
|
||||
React.useState(false)
|
||||
const unmountTestInterval = React.useRef<number>()
|
||||
const unmountTestInterval = React.useRef<number>(undefined)
|
||||
|
||||
const onUnmountTestStartPressWithClose = () => {
|
||||
setShouldRenderUnmountTest(true)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, {type ComponentProps} from 'react'
|
||||
import React, {type ComponentProps, type JSX} from 'react'
|
||||
import {Linking, ScrollView, TouchableOpacity, View} from 'react-native'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
import {msg, Plural, plural, Trans} from '@lingui/macro'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {useCallback} from 'react'
|
||||
import {type JSX, useCallback} from 'react'
|
||||
import {type GestureResponderEvent, View} from 'react-native'
|
||||
import Animated from 'react-native-reanimated'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
|
||||
@@ -8,7 +8,7 @@ import {useNavigationState} from '@react-navigation/native'
|
||||
import {useMinimalShellFooterTransform} from '#/lib/hooks/useMinimalShellTransform'
|
||||
import {getCurrentRoute, isTab} from '#/lib/routes/helpers'
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
import {CommonNavigatorParams} from '#/lib/routes/types'
|
||||
import {type CommonNavigatorParams} from '#/lib/routes/types'
|
||||
import {useGate} from '#/lib/statsig/statsig'
|
||||
import {useHomeBadge} from '#/state/home-badge'
|
||||
import {useUnreadMessageCount} from '#/state/queries/messages/list-conversations'
|
||||
@@ -223,7 +223,7 @@ export function BottomBarWeb() {
|
||||
}
|
||||
|
||||
const NavItem: React.FC<{
|
||||
children: (props: {isActive: boolean}) => React.ReactChild
|
||||
children: (props: {isActive: boolean}) => React.ReactNode
|
||||
href: string
|
||||
routeName: string
|
||||
hasNew?: boolean
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as React from 'react'
|
||||
import {useEffect} from 'react'
|
||||
import {View} from 'react-native'
|
||||
// Based on @react-navigation/native-stack/src/navigators/createNativeStackNavigator.ts
|
||||
// MIT License
|
||||
@@ -75,8 +75,7 @@ function NativeStackNavigator({
|
||||
screenOptions,
|
||||
screenLayout,
|
||||
})
|
||||
|
||||
React.useEffect(
|
||||
useEffect(
|
||||
() =>
|
||||
// @ts-expect-error: there may not be a tab navigator in parent
|
||||
navigation?.addListener?.('tabPress', (e: any) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {useCallback, useMemo, useState} from 'react'
|
||||
import {type JSX, useCallback, useMemo, useState} from 'react'
|
||||
import {StyleSheet, View} from 'react-native'
|
||||
import {type AppBskyActorDefs} from '@atproto/api'
|
||||
import {msg, plural, Trans} from '@lingui/macro'
|
||||
|
||||
@@ -7542,11 +7542,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
|
||||
integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
|
||||
|
||||
"@types/prop-types@*":
|
||||
version "15.7.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf"
|
||||
integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
|
||||
|
||||
"@types/psl@^1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/psl/-/psl-1.1.1.tgz#3ba9e6d4bd2a32652a639fd5df7e539151d0a3b2"
|
||||
@@ -7567,20 +7562,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.1.3.tgz#3f0c60804441bf34d19f8dd0d44405c0c0e21bfa"
|
||||
integrity sha512-rJXC08OG0h3W6wDMFxQrZF00Kq6qQvw0djHRdzl3U5DnIERz0MRce3WVc7IS6JYBwtaP/DwYtRRjVlvivNveKg==
|
||||
|
||||
"@types/react-responsive@^8.0.5":
|
||||
version "8.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-responsive/-/react-responsive-8.0.5.tgz#77769862d2a0711434feb972be08e3e6c334440a"
|
||||
integrity sha512-k3gQJgI87oP5IrVZe//3LKJFnAeFaqqWmmtl5eoYL2H3HqFcIhUaE30kRK1CsW3DHdojZxcVj4ZNc2ClsEu2PA==
|
||||
"@types/react@^19.1.7":
|
||||
version "19.1.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.7.tgz#9fc4ab6003a8e4f38710c83cb5f8afbdacb7d687"
|
||||
integrity sha512-BnsPLV43ddr05N71gaGzyZ5hzkCmGwhMvYc8zmvI8Ci1bRkkDSzDDVfAXfN2tk748OwI7ediiPX6PfT9p0QGVg==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*", "@types/react@^18":
|
||||
version "18.2.20"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.20.tgz#1605557a83df5c8a2cc4eeb743b3dfc0eb6aaeb2"
|
||||
integrity sha512-WKNtmsLWJM/3D5mG4U84cysVY31ivmyw85dE84fOCk5Hx78wezB/XEjVPWl2JTZ5FkEeaTJf+VgUAUn3PE7Isw==
|
||||
dependencies:
|
||||
"@types/prop-types" "*"
|
||||
"@types/scheduler" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/retry@0.12.0":
|
||||
@@ -7588,11 +7574,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d"
|
||||
integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==
|
||||
|
||||
"@types/scheduler@*":
|
||||
version "0.16.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5"
|
||||
integrity sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==
|
||||
|
||||
"@types/semver@^7.3.12":
|
||||
version "7.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.0.tgz#591c1ce3a702c45ee15f47a42ade72c2fd78978a"
|
||||
@@ -14446,10 +14427,10 @@ marky@^1.2.2:
|
||||
resolved "https://registry.yarnpkg.com/marky/-/marky-1.2.5.tgz#55796b688cbd72390d2d399eaaf1832c9413e3c0"
|
||||
integrity sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==
|
||||
|
||||
matchmediaquery@^0.3.0:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/matchmediaquery/-/matchmediaquery-0.3.1.tgz#8247edc47e499ebb7c58f62a9ff9ccf5b815c6d7"
|
||||
integrity sha512-Hlk20WQHRIm9EE9luN1kjRjYXAQToHOIAHPJn9buxBwuhfTHoKUcX+lXBbxc85DVQfXYbEQ4HcwQdd128E3qHQ==
|
||||
matchmediaquery@^0.4.2:
|
||||
version "0.4.2"
|
||||
resolved "https://registry.yarnpkg.com/matchmediaquery/-/matchmediaquery-0.4.2.tgz#22582bd4ae63ad9f54c53001bba80cbed0f7eafa"
|
||||
integrity sha512-wrZpoT50ehYOudhDjt/YvUJc6eUzcdFPdmbizfgvswCKNHD1/OBOHYJpHie+HXpu6bSkEGieFMYk6VuutaiRfA==
|
||||
dependencies:
|
||||
css-mediaquery "^0.1.2"
|
||||
|
||||
@@ -17057,15 +17038,15 @@ react-remove-scroll@^2.6.3:
|
||||
use-callback-ref "^1.3.3"
|
||||
use-sidecar "^1.1.3"
|
||||
|
||||
react-responsive@^9.0.2:
|
||||
version "9.0.2"
|
||||
resolved "https://registry.yarnpkg.com/react-responsive/-/react-responsive-9.0.2.tgz#34531ca77a61e7a8775714016d21241df7e4205c"
|
||||
integrity sha512-+4CCab7z8G8glgJoRjAwocsgsv6VA2w7JPxFWHRc7kvz8mec1/K5LutNC2MG28Mn8mu6+bu04XZxHv5gyfT7xQ==
|
||||
react-responsive@^10.0.1:
|
||||
version "10.0.1"
|
||||
resolved "https://registry.yarnpkg.com/react-responsive/-/react-responsive-10.0.1.tgz#293d4d2562da93409861216f0110d146c5676eb3"
|
||||
integrity sha512-OM5/cRvbtUWEX8le8RCT8scA8y2OPtb0Q/IViEyCEM5FBN8lRrkUOZnu87I88A6njxDldvxG+rLBxWiA7/UM9g==
|
||||
dependencies:
|
||||
hyphenate-style-name "^1.0.0"
|
||||
matchmediaquery "^0.3.0"
|
||||
matchmediaquery "^0.4.2"
|
||||
prop-types "^15.6.1"
|
||||
shallow-equal "^1.2.1"
|
||||
shallow-equal "^3.1.0"
|
||||
|
||||
react-server-dom-webpack@~19.0.0:
|
||||
version "19.0.0"
|
||||
@@ -17928,10 +17909,10 @@ sf-symbols-typescript@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/sf-symbols-typescript/-/sf-symbols-typescript-1.0.0.tgz#94e9210bf27e7583f9749a0d07bd4f4937ea488f"
|
||||
integrity sha512-DkS7q3nN68dEMb4E18HFPDAvyrjDZK9YAQQF2QxeFu9gp2xRDXFMF8qLJ1EmQ/qeEGQmop4lmMM1WtYJTIcCMw==
|
||||
|
||||
shallow-equal@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-1.2.1.tgz#4c16abfa56043aa20d050324efa68940b0da79da"
|
||||
integrity sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==
|
||||
shallow-equal@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-3.1.0.tgz#e7a54bac629c7f248eff6c2f5b63122ba4320bec"
|
||||
integrity sha512-pfVOw8QZIXpMbhBWvzBISicvToTiM5WBF1EeAUZDDSb5Dt29yl4AYbyywbJFSEsRUMr7gJaxqCdr4L3tQf9wVg==
|
||||
|
||||
sharp@^0.33.5:
|
||||
version "0.33.5"
|
||||
|
||||
Reference in New Issue
Block a user