Bluesky app fork with some witchin' additions 💫

Upgrade `@types/react` to 19 and run codemod (attempt 2) (#8918)

* update dependencies

* rm `import type React from 'react'`

* run codemods

* patch discord types

* update types/react-dom

* Update yarn.lock

authored by samuel.fm and committed by

GitHub 3e2c181c d496a223

+157 -143
+3 -4
package.json
··· 213 213 "react-native-web-webview": "^1.0.2", 214 214 "react-native-webview": "^13.13.5", 215 215 "react-remove-scroll-bar": "^2.3.8", 216 - "react-responsive": "^9.0.2", 216 + "react-responsive": "^10.0.1", 217 217 "react-textarea-autosize": "^8.5.3", 218 218 "sonner": "^2.0.7", 219 219 "sonner-native": "^0.21.0", ··· 245 245 "@types/lodash.isequal": "^4.5.6", 246 246 "@types/lodash.shuffle": "^4.2.7", 247 247 "@types/psl": "^1.1.1", 248 - "@types/react-dom": "^19.1.2", 249 - "@types/react-responsive": "^8.0.5", 248 + "@types/react": "^19.1.12", 249 + "@types/react-dom": "^19.1.8", 250 250 "@typescript-eslint/eslint-plugin": "^7.18.0", 251 251 "@typescript-eslint/parser": "^7.18.0", 252 252 "babel-jest": "^29.7.0", ··· 284 284 "@expo/image-utils": "0.6.3", 285 285 "@react-native/babel-preset": "0.79.3", 286 286 "@react-native/normalize-colors": "0.79.3", 287 - "@types/react": "^18", 288 287 "**/expo-constants": "17.0.3", 289 288 "**/expo-device": "7.1.4", 290 289 "**/zod": "3.23.8",
+13
patches/@discord+bottom-sheet+4.6.1.patch
··· 1 + diff --git a/node_modules/@discord/bottom-sheet/src/hooks/useStableCallback.ts b/node_modules/@discord/bottom-sheet/src/hooks/useStableCallback.ts 2 + index 1c788ab..d30f330 100644 3 + --- a/node_modules/@discord/bottom-sheet/src/hooks/useStableCallback.ts 4 + +++ b/node_modules/@discord/bottom-sheet/src/hooks/useStableCallback.ts 5 + @@ -6,7 +6,7 @@ type Callback = (...args: any[]) => any; 6 + * https://gist.github.com/JakeCoxon/c7ebf6e6496f8468226fd36b596e1985 7 + */ 8 + export const useStableCallback = (callback: Callback) => { 9 + - const callbackRef = useRef<Callback>(); 10 + + const callbackRef = useRef<Callback>(undefined); 11 + const memoCallback = useCallback( 12 + (...args: any) => callbackRef.current && callbackRef.current(...args), 13 + []
+1 -1
src/Navigation.tsx
··· 1 - import {useCallback, useRef} from 'react' 1 + import {type JSX, useCallback, useRef} from 'react' 2 2 import {Linking} from 'react-native' 3 3 import * as Notifications from 'expo-notifications' 4 4 import {i18n, type MessageDescriptor} from '@lingui/core'
-1
src/alf/typography.tsx
··· 3 3 import {type StyleProp, type TextStyle} from 'react-native' 4 4 import {UITextView} from 'react-native-uitextview' 5 5 import createEmojiRegex from 'emoji-regex' 6 - import type React from 'react' 7 6 8 7 import {isNative} from '#/platform/detection' 9 8 import {isIOS} from '#/platform/detection'
+2 -2
src/components/Button.tsx
··· 71 71 export type ButtonContext = VariantProps & ButtonState 72 72 73 73 type NonTextElements = 74 - | React.ReactElement 75 - | Iterable<React.ReactElement | null | undefined | boolean> 74 + | React.ReactElement<any> 75 + | Iterable<React.ReactElement<any> | null | undefined | boolean> 76 76 77 77 export type ButtonProps = Pick< 78 78 PressableProps,
+2 -1
src/components/ContextMenu/index.tsx
··· 119 119 const hoverablesSV = useSharedValue< 120 120 Record<string, {id: string; rect: Measurement}> 121 121 >({}) 122 - const syncHoverablesThrottleRef = useRef<ReturnType<typeof setTimeout>>() 122 + const syncHoverablesThrottleRef = 123 + useRef<ReturnType<typeof setTimeout>>(undefined) 123 124 const [hoveredMenuItem, setHoveredMenuItem] = useState<string | null>(null) 124 125 125 126 const onHoverableTouchUp = useCallback((id: string) => {
-1
src/components/ContextMenu/types.ts
··· 5 5 type ViewStyle, 6 6 } from 'react-native' 7 7 import {type SharedValue} from 'react-native-reanimated' 8 - import type React from 'react' 9 8 10 9 import type * as Dialog from '#/components/Dialog' 11 10 import {
+1 -2
src/components/Dialog/types.ts
··· 5 5 type StyleProp, 6 6 type ViewStyle, 7 7 } from 'react-native' 8 - import type React from 'react' 9 8 10 9 import {type ViewStyleProp} from '#/alf' 11 10 import {type BottomSheetViewProps} from '../../../modules/bottom-sheet' ··· 34 33 */ 35 34 export type DialogControlProps = DialogControlRefProps & { 36 35 id: string 37 - ref: React.RefObject<DialogControlRefProps> 36 + ref: React.RefObject<DialogControlRefProps | null> 38 37 isOpen?: boolean 39 38 } 40 39
-1
src/components/Lists.tsx
··· 2 2 import {type StyleProp, View, type ViewStyle} from 'react-native' 3 3 import {msg, Trans} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 - import type React from 'react' 6 5 7 6 import {cleanError} from '#/lib/strings/errors' 8 7 import {CenteredView} from '#/view/com/util/Views'
+1 -1
src/components/Portal.tsx
··· 10 10 useState, 11 11 } from 'react' 12 12 13 - type Component = React.ReactElement 13 + type Component = React.ReactElement<any> 14 14 15 15 type ContextType = { 16 16 outlet: Component | null
+1 -1
src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerWeb.tsx
··· 139 139 playlist: string 140 140 setHasSubtitleTrack: (v: boolean) => void 141 141 setError: (v: Error | null) => void 142 - videoRef: React.RefObject<HTMLVideoElement> 142 + videoRef: React.RefObject<HTMLVideoElement | null> 143 143 setHlsLoading: (v: boolean) => void 144 144 }) { 145 145 const [Hls, setHls] = useState<typeof HlsTypes.default | undefined>(
-1
src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoFallback.tsx
··· 1 1 import {View} from 'react-native' 2 2 import {msg, Trans} from '@lingui/macro' 3 3 import {useLingui} from '@lingui/react' 4 - import type React from 'react' 5 4 6 5 import {atoms as a, useTheme} from '#/alf' 7 6 import {Button, ButtonText} from '#/components/Button'
-1
src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/ControlButton.tsx
··· 1 1 import {type SvgProps} from 'react-native-svg' 2 - import type React from 'react' 3 2 4 3 import {PressableWithHover} from '#/view/com/util/PressableWithHover' 5 4 import {atoms as a, useTheme, web} from '#/alf'
-1
src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/Scrubber.tsx
··· 2 2 import {View} from 'react-native' 3 3 import {msg} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 - import type React from 'react' 6 5 7 6 import {isFirefox, isTouchDevice} from '#/lib/browser' 8 7 import {clamp} from '#/lib/numbers'
+5 -5
src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx
··· 46 46 hlsLoading, 47 47 hasSubtitleTrack, 48 48 }: { 49 - videoRef: React.RefObject<HTMLVideoElement> 50 - hlsRef: React.RefObject<Hls | undefined> 49 + videoRef: React.RefObject<HTMLVideoElement | null> 50 + hlsRef: React.RefObject<Hls | undefined | null> 51 51 active: boolean 52 52 setActive: () => void 53 53 focused: boolean 54 54 setFocused: (focused: boolean) => void 55 55 onScreen: boolean 56 - fullscreenRef: React.RefObject<HTMLDivElement> 56 + fullscreenRef: React.RefObject<HTMLDivElement | null> 57 57 hlsLoading: boolean 58 58 hasSubtitleTrack: boolean 59 59 }) { ··· 232 232 }, [onSeek, videoRef]) 233 233 234 234 const [showCursor, setShowCursor] = useState(true) 235 - const cursorTimeoutRef = useRef<ReturnType<typeof setTimeout>>() 235 + const cursorTimeoutRef = useRef<ReturnType<typeof setTimeout>>(undefined) 236 236 const onPointerMoveEmptySpace = useCallback(() => { 237 237 setShowCursor(true) 238 238 if (cursorTimeoutRef.current) { ··· 264 264 [hovered], 265 265 ) 266 266 267 - const timeoutRef = useRef<ReturnType<typeof setTimeout>>() 267 + const timeoutRef = useRef<ReturnType<typeof setTimeout>>(undefined) 268 268 269 269 const onHoverWithTimeout = useCallback(() => { 270 270 onHover()
-1
src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VolumeControl.tsx
··· 3 3 import Animated, {FadeIn, FadeOut} from 'react-native-reanimated' 4 4 import {msg} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 - import type React from 'react' 7 6 8 7 import {isSafari, isTouchDevice} from '#/lib/browser' 9 8 import {atoms as a} from '#/alf'
+1 -1
src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/utils.tsx
··· 4 4 import {logger} from '#/logger' 5 5 import {useVideoVolumeState} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext' 6 6 7 - export function useVideoElement(ref: RefObject<HTMLVideoElement>) { 7 + export function useVideoElement(ref: RefObject<HTMLVideoElement | null>) { 8 8 const [playing, setPlaying] = useState(false) 9 9 const [muted, setMuted] = useState(true) 10 10 const [currentTime, setCurrentTime] = useState(0)
+1 -2
src/components/Post/Embed/VideoEmbed/index.web.tsx
··· 10 10 import {type AppBskyEmbedVideo} from '@atproto/api' 11 11 import {msg} from '@lingui/macro' 12 12 import {useLingui} from '@lingui/react' 13 - import type React from 'react' 14 13 15 14 import {isFirefox} from '#/lib/browser' 16 15 import {ErrorBoundary} from '#/view/com/util/ErrorBoundary' ··· 38 37 useActiveVideoWeb() 39 38 const [onScreen, setOnScreen] = useState(false) 40 39 const [isFullscreen] = useFullscreen() 41 - const lastKnownTime = useRef<number | undefined>() 40 + const lastKnownTime = useRef<number | undefined>(undefined) 42 41 43 42 useEffect(() => { 44 43 if (!ref.current) return
-1
src/components/PostControls/PostMenu/index.tsx
··· 8 8 } from '@atproto/api' 9 9 import {msg} from '@lingui/macro' 10 10 import {useLingui} from '@lingui/react' 11 - import type React from 'react' 12 11 13 12 import {type Shadow} from '#/state/cache/post-shadow' 14 13 import {EventStopper} from '#/view/com/util/EventStopper'
-1
src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx
··· 3 3 import {msg, Trans} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5 import {useNavigation} from '@react-navigation/native' 6 - import type React from 'react' 7 6 8 7 import {makeProfileLink} from '#/lib/routes/links' 9 8 import {type NavigationProp} from '#/lib/routes/types'
-1
src/components/PostControls/ShareMenu/index.tsx
··· 9 9 } from '@atproto/api' 10 10 import {msg} from '@lingui/macro' 11 11 import {useLingui} from '@lingui/react' 12 - import type React from 'react' 13 12 14 13 import {makeProfileLink} from '#/lib/routes/links' 15 14 import {shareUrl} from '#/lib/sharing'
-2
src/components/ProfileHoverCard/types.ts
··· 1 - import type React from 'react' 2 - 3 1 import {type ViewStyleProp} from '#/alf' 4 2 5 3 export type ProfileHoverCardProps = ViewStyleProp & {
+3 -3
src/components/ProgressGuide/FollowDialog.tsx
··· 293 293 interestsDisplayNames, 294 294 }: { 295 295 guide: Follow10ProgressGuide 296 - inputRef: React.RefObject<TextInput> 297 - listRef: React.RefObject<ListMethods> 296 + inputRef: React.RefObject<TextInput | null> 297 + listRef: React.RefObject<ListMethods | null> 298 298 onSelectTab: (v: string) => void 299 299 searchText: string 300 300 setHeaderHeight: (v: number) => void ··· 565 565 }: { 566 566 onChangeText: (text: string) => void 567 567 onEscape: () => void 568 - inputRef: React.RefObject<TextInput> 568 + inputRef: React.RefObject<TextInput | null> 569 569 defaultValue: string 570 570 }) { 571 571 const t = useTheme()
+2 -2
src/components/ProgressGuide/Toast.tsx
··· 14 14 import {isWeb} from '#/platform/detection' 15 15 import {atoms as a, useTheme} from '#/alf' 16 16 import {Portal} from '#/components/Portal' 17 - import {AnimatedCheck, AnimatedCheckRef} from '../anim/AnimatedCheck' 17 + import {AnimatedCheck, type AnimatedCheckRef} from '../anim/AnimatedCheck' 18 18 import {Text} from '../Typography' 19 19 20 20 export interface ProgressGuideToastRef { ··· 39 39 const translateY = useSharedValue(0) 40 40 const opacity = useSharedValue(0) 41 41 const animatedCheckRef = React.useRef<AnimatedCheckRef | null>(null) 42 - const timeoutRef = React.useRef<NodeJS.Timeout | undefined>() 42 + const timeoutRef = React.useRef<NodeJS.Timeout | undefined>(undefined) 43 43 const winDim = useWindowDimensions() 44 44 45 45 /**
+1 -1
src/components/Select/types.ts
··· 160 160 item: T, 161 161 index: number, 162 162 selectedValue?: string | null, 163 - ) => React.ReactElement 163 + ) => React.ReactElement<any> 164 164 /* 165 165 * Extracts the value from an item. Defaults to `item => item.value` 166 166 */
+1 -1
src/components/dialogs/GifSelect.tsx
··· 37 37 onClose, 38 38 onSelectGif: onSelectGifProp, 39 39 }: { 40 - controlRef: React.RefObject<{open: () => void}> 40 + controlRef: React.RefObject<{open: () => void} | null> 41 41 onClose?: () => void 42 42 onSelectGif: (gif: Gif) => void 43 43 }) {
+1 -1
src/components/dialogs/SearchablePeopleList.tsx
··· 484 484 value: string 485 485 onChangeText: (text: string) => void 486 486 onEscape: () => void 487 - inputRef: React.RefObject<TextInput> 487 + inputRef: React.RefObject<TextInput | null> 488 488 }) { 489 489 const t = useTheme() 490 490 const {_} = useLingui()
-1
src/components/dms/ActionsWrapper.web.tsx
··· 3 3 import {type ChatBskyConvoDefs} from '@atproto/api' 4 4 import {msg} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 - import type React from 'react' 7 6 8 7 import {useConvoActive} from '#/state/messages/convo' 9 8 import {useSession} from '#/state/session'
+5 -2
src/components/forms/InputGroup.tsx
··· 23 23 {React.cloneElement(child, { 24 24 // @ts-ignore 25 25 style: [ 26 + // @ts-ignore 26 27 ...(Array.isArray(child.props?.style) 27 - ? child.props.style 28 - : [child.props.style || {}]), 28 + ? // @ts-ignore 29 + child.props.style 30 + : // @ts-ignore 31 + [child.props.style || {}]), 29 32 { 30 33 borderTopLeftRadius: i > 0 ? 0 : undefined, 31 34 borderTopRightRadius: i > 0 ? 0 : undefined,
+2 -2
src/components/forms/TextField.tsx
··· 28 28 import {Text} from '#/components/Typography' 29 29 30 30 const Context = createContext<{ 31 - inputRef: React.RefObject<TextInput> | null 31 + inputRef: React.RefObject<TextInput | null> | null 32 32 isInvalid: boolean 33 33 hovered: boolean 34 34 onHoverIn: () => void ··· 152 152 value?: string 153 153 onChangeText?: (value: string) => void 154 154 isInvalid?: boolean 155 - inputRef?: React.RefObject<TextInput> | React.ForwardedRef<TextInput> 155 + inputRef?: React.RefObject<TextInput | null> | React.ForwardedRef<TextInput> 156 156 } 157 157 158 158 export function createInput(Component: typeof TextInput) {
+7 -2
src/components/forms/ToggleButton.tsx
··· 1 1 import React from 'react' 2 - import {AccessibilityProps, TextStyle, View, ViewStyle} from 'react-native' 2 + import { 3 + type AccessibilityProps, 4 + type TextStyle, 5 + View, 6 + type ViewStyle, 7 + } from 'react-native' 3 8 4 9 import {atoms as a, native, useTheme} from '#/alf' 5 10 import * as Toggle from '#/components/forms/Toggle' ··· 7 12 8 13 type ItemProps = Omit<Toggle.ItemProps, 'style' | 'role' | 'children'> & 9 14 AccessibilityProps & { 10 - children: React.ReactElement 15 + children: React.ReactElement<any> 11 16 testID?: string 12 17 } 13 18
+1 -1
src/components/hooks/useFullscreen.ts
··· 14 14 return () => document.removeEventListener('fullscreenchange', onChange) 15 15 } 16 16 17 - export function useFullscreen(ref?: React.RefObject<HTMLElement>) { 17 + export function useFullscreen(ref?: React.RefObject<HTMLElement | null>) { 18 18 if (!isWeb) throw new Error("'useFullscreen' is a web-only hook") 19 19 const isFullscreen = useSyncExternalStore(fullscreenSubscribe, () => 20 20 Boolean(document.fullscreenElement),
-1
src/components/moderation/LabelPreference.tsx
··· 5 5 } from '@atproto/api' 6 6 import {msg, Trans} from '@lingui/macro' 7 7 import {useLingui} from '@lingui/react' 8 - import type React from 'react' 9 8 10 9 import {useGlobalLabelStrings} from '#/lib/moderation/useGlobalLabelStrings' 11 10 import {useLabelBehaviorDescription} from '#/lib/moderation/useLabelBehaviorDescription'
+1 -1
src/lib/hooks/useAnimatedValue.ts
··· 2 2 import {Animated} from 'react-native' 3 3 4 4 export function useAnimatedValue(initialValue: number) { 5 - const lazyRef = React.useRef<Animated.Value>() 5 + const lazyRef = React.useRef<Animated.Value>(undefined) 6 6 7 7 if (lazyRef.current === undefined) { 8 8 lazyRef.current = new Animated.Value(initialValue)
+1 -1
src/lib/hooks/useOTAUpdates.ts
··· 127 127 const appState = React.useRef<AppStateStatus>('active') 128 128 const lastMinimize = React.useRef(0) 129 129 const ranInitialCheck = React.useRef(false) 130 - const timeout = React.useRef<NodeJS.Timeout>() 130 + const timeout = React.useRef<NodeJS.Timeout>(undefined) 131 131 const {currentlyRunning, isUpdatePending} = useUpdates() 132 132 const currentChannel = currentlyRunning?.channel 133 133
+1 -1
src/lib/merge-refs.ts
··· 13 13 * returns a ref callback function that can be used to merge multiple refs into a single ref. 14 14 */ 15 15 export function mergeRefs<T = any>( 16 - refs: Array<React.MutableRefObject<T> | React.LegacyRef<T>>, 16 + refs: Array<React.MutableRefObject<T> | React.Ref<T>>, 17 17 ): React.RefCallback<T> { 18 18 return value => { 19 19 refs.forEach(ref => {
+1 -1
src/screens/Signup/StepCaptcha/CaptchaWebView.tsx
··· 31 31 onError: (error: unknown) => void 32 32 }) { 33 33 const startedAt = useRef(Date.now()) 34 - const successTo = useRef<NodeJS.Timeout>() 34 + const successTo = useRef<NodeJS.Timeout>(undefined) 35 35 36 36 useEffect(() => { 37 37 return () => {
+1 -1
src/screens/Signup/StepInfo/Policies.tsx
··· 72 72 ) 73 73 } 74 74 75 - let els: ReactElement 75 + let els: ReactElement<any> 76 76 if (tos && pp) { 77 77 els = ( 78 78 <Trans>
+1 -1
src/screens/Signup/StepInfo/index.tsx
··· 60 60 61 61 const [hasWarnedEmail, setHasWarnedEmail] = React.useState<boolean>(false) 62 62 63 - const tldtsRef = React.useRef<typeof tldts>() 63 + const tldtsRef = React.useRef<typeof tldts>(undefined) 64 64 React.useEffect(() => { 65 65 // @ts-expect-error - valid path 66 66 import('tldts/dist/index.cjs.min.js').then(tldts => {
+1 -1
src/state/queries/postgate/index.ts
··· 173 173 const agent = useAgent() 174 174 const queryClient = useQueryClient() 175 175 const getPosts = useGetPosts() 176 - const prevEmbed = React.useRef<AppBskyFeedDefs.PostView['embed']>() 176 + const prevEmbed = React.useRef<AppBskyFeedDefs.PostView['embed']>(undefined) 177 177 178 178 return useMutation({ 179 179 mutationFn: async ({
-2
src/state/shell/index.tsx
··· 1 - import type React from 'react' 2 - 3 1 import {Provider as ColorModeProvider} from './color-mode' 4 2 import {Provider as DrawerOpenProvider} from './drawer-open' 5 3 import {Provider as DrawerSwipableProvider} from './drawer-swipe-disabled'
+1 -1
src/view/com/composer/Composer.tsx
··· 174 174 videoUri: initVideoUri, 175 175 cancelRef, 176 176 }: Props & { 177 - cancelRef?: React.RefObject<CancelRef> 177 + cancelRef?: React.RefObject<CancelRef | null> 178 178 }) => { 179 179 const {currentAccount} = useSession() 180 180 const agent = useAgent()
-2
src/view/com/composer/photos/EditImageDialog.tsx
··· 1 - import type React from 'react' 2 - 3 1 import {type ComposerImage} from '#/state/gallery' 4 2 import type * as Dialog from '#/components/Dialog' 5 3
+1 -1
src/view/com/composer/photos/EditImageDialog.web.tsx
··· 112 112 aspectRatio, 113 113 }: Required<Pick<EditImageDialogProps, 'image'>> & 114 114 Omit<EditImageDialogProps, 'control' | 'image'> & { 115 - saveRef: React.RefObject<{save: () => Promise<void>}> 115 + saveRef: React.RefObject<{save: () => Promise<void>} | null> 116 116 }) { 117 117 const t = useTheme() 118 118 const [isDragging, setIsDragging] = useState(false)
+8 -1
src/view/com/feeds/FeedPage.tsx
··· 1 - import {useCallback, useEffect, useMemo, useRef, useState} from 'react' 1 + import { 2 + type JSX, 3 + useCallback, 4 + useEffect, 5 + useMemo, 6 + useRef, 7 + useState, 8 + } from 'react' 2 9 import {View} from 'react-native' 3 10 import {type AppBskyActorDefs, AppBskyFeedDefs} from '@atproto/api' 4 11 import {msg} from '@lingui/macro'
+2 -1
src/view/com/home/HomeHeaderLayout.web.tsx
··· 1 - import React from 'react' 1 + import {type JSX} from 'react' 2 2 import {View} from 'react-native' 3 3 import {msg} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 + import type React from 'react' 5 6 6 7 import {useKawaiiMode} from '#/state/preferences/kawaii' 7 8 import {useSession} from '#/state/session'
+1
src/view/com/home/HomeHeaderLayoutMobile.tsx
··· 1 + import {type JSX} from 'react' 1 2 import {View} from 'react-native' 2 3 import Animated from 'react-native-reanimated' 3 4 import {msg} from '@lingui/macro'
+1 -1
src/view/com/lists/ListMembers.tsx
··· 1 - import React, {useCallback} from 'react' 1 + import React, {type JSX, useCallback} from 'react' 2 2 import { 3 3 Dimensions, 4 4 type GestureResponderEvent,
+5 -5
src/view/com/lists/MyLists.tsx
··· 1 - import React from 'react' 1 + import React, {type JSX} from 'react' 2 2 import { 3 3 ActivityIndicator, 4 4 FlatList as RNFlatList, 5 5 RefreshControl, 6 - StyleProp, 6 + type StyleProp, 7 7 View, 8 - ViewStyle, 8 + type ViewStyle, 9 9 } from 'react-native' 10 - import {AppBskyGraphDefs as GraphDefs} from '@atproto/api' 10 + import {type AppBskyGraphDefs as GraphDefs} from '@atproto/api' 11 11 import {msg} from '@lingui/macro' 12 12 import {useLingui} from '@lingui/react' 13 13 ··· 16 16 import {s} from '#/lib/styles' 17 17 import {logger} from '#/logger' 18 18 import {useModerationOpts} from '#/state/preferences/moderation-opts' 19 - import {MyListsFilter, useMyListsQuery} from '#/state/queries/my-lists' 19 + import {type MyListsFilter, useMyListsQuery} from '#/state/queries/my-lists' 20 20 import {atoms as a, useTheme} from '#/alf' 21 21 import {BulletList_Stroke2_Corner0_Rounded as ListIcon} from '#/components/icons/BulletList' 22 22 import * as ListCard from '#/components/ListCard'
+1 -1
src/view/com/notifications/NotificationFeedItem.tsx
··· 248 248 : '' 249 249 250 250 let a11yLabel = '' 251 - let notificationContent: ReactElement 251 + let notificationContent: ReactElement<any> 252 252 let icon = ( 253 253 <HeartIconFilled 254 254 size="xl"
+1
src/view/com/pager/Pager.tsx
··· 1 1 import { 2 + type JSX, 2 3 memo, 3 4 useCallback, 4 5 useContext,
+1
src/view/com/pager/Pager.web.tsx
··· 1 1 import { 2 2 Children, 3 + type JSX, 3 4 useCallback, 4 5 useImperativeHandle, 5 6 useRef,
+1 -1
src/view/com/pager/PagerWithHeader.tsx
··· 1 - import {memo, useCallback, useEffect, useRef, useState} from 'react' 1 + import {type JSX, memo, useCallback, useEffect, useRef, useState} from 'react' 2 2 import { 3 3 type LayoutChangeEvent, 4 4 type NativeScrollEvent,
+8 -3
src/view/com/pager/PagerWithHeader.web.tsx
··· 1 1 import * as React from 'react' 2 - import {ScrollView, View} from 'react-native' 2 + import {type JSX} from 'react' 3 + import {type ScrollView, View} from 'react-native' 3 4 import {useAnimatedRef} from 'react-native-reanimated' 4 5 5 - import {Pager, PagerRef, RenderTabBarFnProps} from '#/view/com/pager/Pager' 6 + import { 7 + Pager, 8 + type PagerRef, 9 + type RenderTabBarFnProps, 10 + } from '#/view/com/pager/Pager' 6 11 import {atoms as a, web} from '#/alf' 7 12 import * as Layout from '#/components/Layout' 8 - import {ListMethods} from '../util/List' 13 + import {type ListMethods} from '../util/List' 9 14 import {TabBar} from './TabBar' 10 15 11 16 export interface PagerWithHeaderChildParams {
+3 -1
src/view/com/pager/TabBar.web.tsx
··· 106 106 <PressableWithHover 107 107 testID={`${testID}-selector-${i}`} 108 108 key={`${item}-${i}`} 109 - ref={node => (itemRefs.current[i] = node as any)} 109 + ref={node => { 110 + itemRefs.current[i] = node as any 111 + }} 110 112 style={styles.item} 111 113 hoverStyle={t.atoms.bg_contrast_25} 112 114 onPress={() => onPressItem(i)}
+9 -1
src/view/com/posts/PostFeed.tsx
··· 1 - import {memo, useCallback, useEffect, useMemo, useRef, useState} from 'react' 1 + import { 2 + type JSX, 3 + memo, 4 + useCallback, 5 + useEffect, 6 + useMemo, 7 + useRef, 8 + useState, 9 + } from 'react' 2 10 import { 3 11 ActivityIndicator, 4 12 AppState,
-1
src/view/com/util/EventStopper.tsx
··· 1 1 import {View, type ViewStyle} from 'react-native' 2 - import type React from 'react' 3 2 4 3 /** 5 4 * This utility function captures events and stops
+1 -1
src/view/com/util/Link.tsx
··· 1 - import {memo, useCallback, useMemo} from 'react' 1 + import {type JSX, memo, useCallback, useMemo} from 'react' 2 2 import { 3 3 type GestureResponderEvent, 4 4 Platform,
+1 -1
src/view/com/util/List.tsx
··· 57 57 ...props 58 58 }, 59 59 ref, 60 - ): React.ReactElement => { 60 + ): React.ReactElement<any> => { 61 61 const isScrolledDown = useSharedValue(false) 62 62 const t = useTheme() 63 63 const dedupe = useDedupe(400)
+13 -6
src/view/com/util/List.web.tsx
··· 1 - import React, {isValidElement, memo, startTransition, useRef} from 'react' 1 + import React, { 2 + isValidElement, 3 + type JSX, 4 + memo, 5 + startTransition, 6 + useRef, 7 + } from 'react' 2 8 import { 3 9 type FlatListProps, 4 10 StyleSheet, ··· 202 208 behavior: animated ? 'smooth' : 'instant', 203 209 }) 204 210 }, 211 + 205 212 scrollToEnd({animated = true}: {animated?: boolean}) { 206 213 const element = getScrollableNode() 207 214 element?.scrollTo({ ··· 382 389 containerRef, 383 390 onVisibleChange, 384 391 }: { 385 - root?: React.RefObject<HTMLDivElement> | null 392 + root?: React.RefObject<HTMLDivElement | null> | null 386 393 topMargin?: string 387 394 bottomMargin?: string 388 - containerRef: React.RefObject<Element> 395 + containerRef: React.RefObject<Element | null> 389 396 onVisibleChange: (isVisible: boolean) => void 390 397 }) { 391 398 const [containerHeight, setContainerHeight] = React.useState(0) ··· 404 411 } 405 412 406 413 function useResizeObserver( 407 - ref: React.RefObject<Element>, 414 + ref: React.RefObject<Element | null>, 408 415 onResize: undefined | ((w: number, h: number) => void), 409 416 ) { 410 417 const handleResize = useNonReactiveCallback(onResize ?? (() => {})) ··· 509 516 onVisibleChange, 510 517 style, 511 518 }: { 512 - root?: React.RefObject<HTMLDivElement> | null 519 + root?: React.RefObject<HTMLDivElement | null> | null 513 520 topMargin?: string 514 521 bottomMargin?: string 515 522 onVisibleChange: (isVisible: boolean) => void ··· 551 558 552 559 export const List = memo(React.forwardRef(ListImpl)) as <ItemT>( 553 560 props: ListProps<ItemT> & {ref?: React.Ref<ListMethods>}, 554 - ) => React.ReactElement 561 + ) => React.ReactElement<any> 555 562 556 563 // https://stackoverflow.com/questions/7944460/detect-safari-browser 557 564
-1
src/view/com/util/PostMeta.tsx
··· 4 4 import {msg} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 6 import {useQueryClient} from '@tanstack/react-query' 7 - import type React from 'react' 8 7 9 8 import {useActorStatus} from '#/lib/actor-status' 10 9 import {makeProfileLink} from '#/lib/routes/links'
+2 -2
src/view/com/util/TimeElapsed.tsx
··· 1 - import React from 'react' 2 - import {I18n} from '@lingui/core' 1 + import React, {type JSX} from 'react' 2 + import {type I18n} from '@lingui/core' 3 3 import {useLingui} from '@lingui/react' 4 4 5 5 import {useGetTimeAgo} from '#/lib/hooks/useTimeAgo'
+2
src/view/com/util/ViewHeader.tsx
··· 1 + import {type JSX} from 'react' 2 + 1 3 import {Header} from '#/components/Layout' 2 4 3 5 /**
+4 -4
src/view/com/util/ViewSelector.tsx
··· 1 - import React, {useEffect, useState} from 'react' 1 + import React, {type JSX, useEffect, useState} from 'react' 2 2 import { 3 - NativeScrollEvent, 4 - NativeSyntheticEvent, 3 + type NativeScrollEvent, 4 + type NativeSyntheticEvent, 5 5 Pressable, 6 6 RefreshControl, 7 7 ScrollView, ··· 36 36 renderItem: (item: any) => JSX.Element 37 37 ListFooterComponent?: 38 38 | React.ComponentType<any> 39 - | React.ReactElement 39 + | React.ReactElement<any> 40 40 | null 41 41 | undefined 42 42 onSelectView?: (viewIndex: number) => void
+2 -2
src/view/com/util/fab/FABInner.tsx
··· 1 - import {ComponentProps} from 'react' 2 - import {StyleSheet, TouchableWithoutFeedback} from 'react-native' 1 + import {type ComponentProps, type JSX} from 'react' 2 + import {StyleSheet, type TouchableWithoutFeedback} from 'react-native' 3 3 import Animated from 'react-native-reanimated' 4 4 import {useSafeAreaInsets} from 'react-native-safe-area-context' 5 5 import {LinearGradient} from 'expo-linear-gradient'
+1 -1
src/view/com/util/forms/NativeDropdown.web.tsx
··· 161 161 menuRef, 162 162 }: { 163 163 items: DropdownItem[] 164 - menuRef: React.RefObject<HTMLDivElement> 164 + menuRef: React.RefObject<HTMLDivElement | null> 165 165 }) { 166 166 const pal = usePalette('default') 167 167 const theme = useTheme()
-1
src/view/com/util/images/Gallery.tsx
··· 4 4 import {type AppBskyEmbedImages} from '@atproto/api' 5 5 import {msg} from '@lingui/macro' 6 6 import {useLingui} from '@lingui/react' 7 - import type React from 'react' 8 7 9 8 import {type Dimensions} from '#/lib/media/types' 10 9 import {useLargeAltBadgeEnabled} from '#/state/preferences/large-alt-badge'
+1 -1
src/view/screens/Storybook/Dialogs.tsx
··· 22 22 React.useState<boolean>() 23 23 const [shouldRenderUnmountTest, setShouldRenderUnmountTest] = 24 24 React.useState(false) 25 - const unmountTestInterval = React.useRef<number>() 25 + const unmountTestInterval = React.useRef<number>(undefined) 26 26 27 27 const onUnmountTestStartPressWithClose = () => { 28 28 setShouldRenderUnmountTest(true)
+1 -1
src/view/shell/Drawer.tsx
··· 1 - import React, {type ComponentProps} from 'react' 1 + import React, {type ComponentProps, type JSX} from 'react' 2 2 import {Linking, ScrollView, TouchableOpacity, View} from 'react-native' 3 3 import {useSafeAreaInsets} from 'react-native-safe-area-context' 4 4 import {msg, Plural, plural, Trans} from '@lingui/macro'
+1 -1
src/view/shell/bottom-bar/BottomBar.tsx
··· 1 - import {useCallback} from 'react' 1 + import {type JSX, useCallback} from 'react' 2 2 import {type GestureResponderEvent, View} from 'react-native' 3 3 import Animated from 'react-native-reanimated' 4 4 import {useSafeAreaInsets} from 'react-native-safe-area-context'
+1 -1
src/view/shell/bottom-bar/BottomBarWeb.tsx
··· 230 230 } 231 231 232 232 const NavItem: React.FC<{ 233 - children: (props: {isActive: boolean}) => React.ReactChild 233 + children: (props: {isActive: boolean}) => React.ReactNode 234 234 href: string 235 235 routeName: string 236 236 hasNew?: boolean
+1 -1
src/view/shell/desktop/LeftNav.tsx
··· 1 - import {useCallback, useMemo, useState} from 'react' 1 + import {type JSX, useCallback, useMemo, useState} from 'react' 2 2 import {StyleSheet, View} from 'react-native' 3 3 import {type AppBskyActorDefs} from '@atproto/api' 4 4 import {msg, plural, Trans} from '@lingui/macro'
+22 -41
yarn.lock
··· 7589 7589 resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" 7590 7590 integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== 7591 7591 7592 - "@types/prop-types@*": 7593 - version "15.7.5" 7594 - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" 7595 - integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== 7596 - 7597 7592 "@types/psl@^1.1.1": 7598 7593 version "1.1.1" 7599 7594 resolved "https://registry.yarnpkg.com/@types/psl/-/psl-1.1.1.tgz#3ba9e6d4bd2a32652a639fd5df7e539151d0a3b2" ··· 7609 7604 resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" 7610 7605 integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== 7611 7606 7612 - "@types/react-dom@^19.1.2": 7613 - version "19.1.3" 7614 - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.1.3.tgz#3f0c60804441bf34d19f8dd0d44405c0c0e21bfa" 7615 - integrity sha512-rJXC08OG0h3W6wDMFxQrZF00Kq6qQvw0djHRdzl3U5DnIERz0MRce3WVc7IS6JYBwtaP/DwYtRRjVlvivNveKg== 7607 + "@types/react-dom@^19.1.8": 7608 + version "19.1.9" 7609 + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.1.9.tgz#5ab695fce1e804184767932365ae6569c11b4b4b" 7610 + integrity sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ== 7616 7611 7617 - "@types/react-responsive@^8.0.5": 7618 - version "8.0.5" 7619 - resolved "https://registry.yarnpkg.com/@types/react-responsive/-/react-responsive-8.0.5.tgz#77769862d2a0711434feb972be08e3e6c334440a" 7620 - integrity sha512-k3gQJgI87oP5IrVZe//3LKJFnAeFaqqWmmtl5eoYL2H3HqFcIhUaE30kRK1CsW3DHdojZxcVj4ZNc2ClsEu2PA== 7612 + "@types/react@^19.1.12": 7613 + version "19.1.12" 7614 + resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.12.tgz#7bfaa76aabbb0b4fe0493c21a3a7a93d33e8937b" 7615 + integrity sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w== 7621 7616 dependencies: 7622 - "@types/react" "*" 7623 - 7624 - "@types/react@*", "@types/react@^18": 7625 - version "18.2.20" 7626 - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.20.tgz#1605557a83df5c8a2cc4eeb743b3dfc0eb6aaeb2" 7627 - integrity sha512-WKNtmsLWJM/3D5mG4U84cysVY31ivmyw85dE84fOCk5Hx78wezB/XEjVPWl2JTZ5FkEeaTJf+VgUAUn3PE7Isw== 7628 - dependencies: 7629 - "@types/prop-types" "*" 7630 - "@types/scheduler" "*" 7631 7617 csstype "^3.0.2" 7632 7618 7633 7619 "@types/retry@0.12.0": 7634 7620 version "0.12.0" 7635 7621 resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" 7636 7622 integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== 7637 - 7638 - "@types/scheduler@*": 7639 - version "0.16.3" 7640 - resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5" 7641 - integrity sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ== 7642 7623 7643 7624 "@types/semver@^7.3.12": 7644 7625 version "7.5.0" ··· 14515 14496 resolved "https://registry.yarnpkg.com/marky/-/marky-1.2.5.tgz#55796b688cbd72390d2d399eaaf1832c9413e3c0" 14516 14497 integrity sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q== 14517 14498 14518 - matchmediaquery@^0.3.0: 14519 - version "0.3.1" 14520 - resolved "https://registry.yarnpkg.com/matchmediaquery/-/matchmediaquery-0.3.1.tgz#8247edc47e499ebb7c58f62a9ff9ccf5b815c6d7" 14521 - integrity sha512-Hlk20WQHRIm9EE9luN1kjRjYXAQToHOIAHPJn9buxBwuhfTHoKUcX+lXBbxc85DVQfXYbEQ4HcwQdd128E3qHQ== 14499 + matchmediaquery@^0.4.2: 14500 + version "0.4.2" 14501 + resolved "https://registry.yarnpkg.com/matchmediaquery/-/matchmediaquery-0.4.2.tgz#22582bd4ae63ad9f54c53001bba80cbed0f7eafa" 14502 + integrity sha512-wrZpoT50ehYOudhDjt/YvUJc6eUzcdFPdmbizfgvswCKNHD1/OBOHYJpHie+HXpu6bSkEGieFMYk6VuutaiRfA== 14522 14503 dependencies: 14523 14504 css-mediaquery "^0.1.2" 14524 14505 ··· 17124 17105 use-callback-ref "^1.3.3" 17125 17106 use-sidecar "^1.1.3" 17126 17107 17127 - react-responsive@^9.0.2: 17128 - version "9.0.2" 17129 - resolved "https://registry.yarnpkg.com/react-responsive/-/react-responsive-9.0.2.tgz#34531ca77a61e7a8775714016d21241df7e4205c" 17130 - integrity sha512-+4CCab7z8G8glgJoRjAwocsgsv6VA2w7JPxFWHRc7kvz8mec1/K5LutNC2MG28Mn8mu6+bu04XZxHv5gyfT7xQ== 17108 + react-responsive@^10.0.1: 17109 + version "10.0.1" 17110 + resolved "https://registry.yarnpkg.com/react-responsive/-/react-responsive-10.0.1.tgz#293d4d2562da93409861216f0110d146c5676eb3" 17111 + integrity sha512-OM5/cRvbtUWEX8le8RCT8scA8y2OPtb0Q/IViEyCEM5FBN8lRrkUOZnu87I88A6njxDldvxG+rLBxWiA7/UM9g== 17131 17112 dependencies: 17132 17113 hyphenate-style-name "^1.0.0" 17133 - matchmediaquery "^0.3.0" 17114 + matchmediaquery "^0.4.2" 17134 17115 prop-types "^15.6.1" 17135 - shallow-equal "^1.2.1" 17116 + shallow-equal "^3.1.0" 17136 17117 17137 17118 react-server-dom-webpack@~19.0.0: 17138 17119 version "19.0.0" ··· 17985 17966 resolved "https://registry.yarnpkg.com/sf-symbols-typescript/-/sf-symbols-typescript-1.0.0.tgz#94e9210bf27e7583f9749a0d07bd4f4937ea488f" 17986 17967 integrity sha512-DkS7q3nN68dEMb4E18HFPDAvyrjDZK9YAQQF2QxeFu9gp2xRDXFMF8qLJ1EmQ/qeEGQmop4lmMM1WtYJTIcCMw== 17987 17968 17988 - shallow-equal@^1.2.1: 17989 - version "1.2.1" 17990 - resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-1.2.1.tgz#4c16abfa56043aa20d050324efa68940b0da79da" 17991 - integrity sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA== 17969 + shallow-equal@^3.1.0: 17970 + version "3.1.0" 17971 + resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-3.1.0.tgz#e7a54bac629c7f248eff6c2f5b63122ba4320bec" 17972 + integrity sha512-pfVOw8QZIXpMbhBWvzBISicvToTiM5WBF1EeAUZDDSb5Dt29yl4AYbyywbJFSEsRUMr7gJaxqCdr4L3tQf9wVg== 17992 17973 17993 17974 sharp@^0.33.5: 17994 17975 version "0.33.5"