From bb733dc0850c061ad9811ec6f4f19df37dc92ca1 Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Fri, 16 May 2025 16:22:41 -0700 Subject: [PATCH] upgrade @types/react to 19 + run codemod --- package.json | 2 +- patches/@discord+bottom-sheet+4.6.1.patch | 13 +++++++++ src/Navigation.tsx | 2 +- src/components/Button.tsx | 4 +-- src/components/ContextMenu/index.tsx | 3 ++- src/components/Dialog/types.ts | 22 +++++++-------- src/components/Portal.tsx | 2 +- src/components/ProfileHoverCard/types.ts | 2 +- src/components/ProgressGuide/FollowDialog.tsx | 6 ++--- src/components/ProgressGuide/Toast.tsx | 4 +-- src/components/Select/types.ts | 2 +- src/components/dialogs/GifSelect.tsx | 8 +++--- .../dialogs/SearchablePeopleList.tsx | 2 +- src/components/forms/InputGroup.tsx | 9 ++++--- src/components/forms/TextField.tsx | 16 +++++------ src/components/forms/ToggleButton.tsx | 4 +-- src/components/hooks/useFullscreen.ts | 2 +- src/lib/hooks/useAnimatedValue.ts | 2 +- src/lib/hooks/useOTAUpdates.ts | 4 +-- src/lib/merge-refs.ts | 2 +- src/screens/Signup/StepInfo/Policies.tsx | 6 ++--- src/screens/Signup/StepInfo/index.tsx | 2 +- src/state/queries/postgate/index.ts | 6 ++--- src/view/com/composer/Composer.tsx | 2 +- .../composer/photos/EditImageDialog.web.tsx | 2 +- src/view/com/home/HomeHeaderLayout.web.tsx | 2 +- src/view/com/home/HomeHeaderLayoutMobile.tsx | 2 +- src/view/com/lists/ListMembers.tsx | 2 +- src/view/com/lists/MyLists.tsx | 10 +++---- .../com/notifications/NotificationFeed.tsx | 2 +- .../notifications/NotificationFeedItem.tsx | 2 +- src/view/com/pager/Pager.tsx | 12 ++++----- src/view/com/pager/Pager.web.tsx | 2 +- src/view/com/pager/PagerWithHeader.tsx | 24 ++++++++++------- src/view/com/pager/PagerWithHeader.web.tsx | 22 ++++++++------- src/view/com/pager/TabBar.web.tsx | 4 ++- src/view/com/util/List.tsx | 6 ++--- src/view/com/util/List.web.tsx | 27 +++++++++++++------ src/view/com/util/TimeElapsed.tsx | 4 +-- src/view/com/util/Toast.tsx | 2 +- src/view/com/util/ViewHeader.tsx | 2 ++ src/view/com/util/ViewSelector.tsx | 8 +++--- src/view/com/util/fab/FABInner.tsx | 4 +-- .../com/util/forms/NativeDropdown.web.tsx | 2 +- .../com/util/post-embeds/VideoEmbed.web.tsx | 7 ++--- .../VideoEmbedInner/VideoEmbedInnerWeb.tsx | 2 +- .../web-controls/VideoControls.tsx | 13 ++++----- .../VideoEmbedInner/web-controls/utils.tsx | 5 ++-- src/view/screens/Storybook/Dialogs.tsx | 2 +- src/view/shell/Drawer.tsx | 2 +- src/view/shell/bottom-bar/BottomBarWeb.tsx | 4 +-- yarn.lock | 20 +++----------- 52 files changed, 177 insertions(+), 146 deletions(-) create mode 100644 patches/@discord+bottom-sheet+4.6.1.patch diff --git a/package.json b/package.json index ac2171a220..d7d908b259 100644 --- a/package.json +++ b/package.json @@ -277,7 +277,7 @@ "@expo/image-utils": "0.6.3", "@react-native/babel-preset": "0.79.2", "@react-native/normalize-colors": "0.79.2", - "@types/react": "^18", + "@types/react": "^19", "**/expo-constants": "17.0.3", "**/expo-device": "7.0.1", "**/zod": "3.23.8", diff --git a/patches/@discord+bottom-sheet+4.6.1.patch b/patches/@discord+bottom-sheet+4.6.1.patch new file mode 100644 index 0000000000..e3837d84d0 --- /dev/null +++ b/patches/@discord+bottom-sheet+4.6.1.patch @@ -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(); ++ const callbackRef = useRef(undefined); + const memoCallback = useCallback( + (...args: any) => callbackRef.current && callbackRef.current(...args), + [] diff --git a/src/Navigation.tsx b/src/Navigation.tsx index 2f26c09711..f1eaca6c8d 100644 --- a/src/Navigation.tsx +++ b/src/Navigation.tsx @@ -485,7 +485,7 @@ function commonScreens(Stack: typeof Flat, unreadCountLabel?: string) { */ function TabsNavigator() { const tabBar = React.useCallback( - (props: JSX.IntrinsicAttributes & BottomTabBarProps) => ( + (props: React.JSX.IntrinsicAttributes & BottomTabBarProps) => ( ), [], diff --git a/src/components/Button.tsx b/src/components/Button.tsx index 42eb648443..47771de621 100644 --- a/src/components/Button.tsx +++ b/src/components/Button.tsx @@ -65,8 +65,8 @@ export type ButtonState = { export type ButtonContext = VariantProps & ButtonState type NonTextElements = - | React.ReactElement - | Iterable + | React.ReactElement + | Iterable | null | undefined | boolean> export type ButtonProps = Pick< PressableProps, diff --git a/src/components/ContextMenu/index.tsx b/src/components/ContextMenu/index.tsx index 4a0814dfe3..3deb1ea569 100644 --- a/src/components/ContextMenu/index.tsx +++ b/src/components/ContextMenu/index.tsx @@ -119,7 +119,8 @@ export function Root({children}: {children: React.ReactNode}) { const hoverablesSV = useSharedValue< Record >({}) - const syncHoverablesThrottleRef = useRef>() + const syncHoverablesThrottleRef = + useRef>(undefined) const [hoveredMenuItem, setHoveredMenuItem] = useState(null) const onHoverableTouchUp = useCallback((id: string) => { diff --git a/src/components/Dialog/types.ts b/src/components/Dialog/types.ts index 3ca64a3214..d9b339a27b 100644 --- a/src/components/Dialog/types.ts +++ b/src/components/Dialog/types.ts @@ -1,15 +1,15 @@ -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 type React from 'react' -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 @@ -34,7 +34,7 @@ export type DialogControlRefProps = { */ export type DialogControlProps = DialogControlRefProps & { id: string - ref: React.RefObject + ref: React.RefObject isOpen?: boolean } diff --git a/src/components/Portal.tsx b/src/components/Portal.tsx index 4e03d6b089..dcde35800b 100644 --- a/src/components/Portal.tsx +++ b/src/components/Portal.tsx @@ -10,7 +10,7 @@ import { useState, } from 'react' -type Component = React.ReactElement +type Component = React.ReactElement type ContextType = { outlet: Component | null diff --git a/src/components/ProfileHoverCard/types.ts b/src/components/ProfileHoverCard/types.ts index 37087dc95a..5450adf5b3 100644 --- a/src/components/ProfileHoverCard/types.ts +++ b/src/components/ProfileHoverCard/types.ts @@ -1,7 +1,7 @@ import type React from 'react' export type ProfileHoverCardProps = { - children: React.ReactElement + children: React.ReactElement did: string inline?: boolean disable?: boolean diff --git a/src/components/ProgressGuide/FollowDialog.tsx b/src/components/ProgressGuide/FollowDialog.tsx index a8c64935ad..9dffb8f0ba 100644 --- a/src/components/ProgressGuide/FollowDialog.tsx +++ b/src/components/ProgressGuide/FollowDialog.tsx @@ -301,8 +301,8 @@ let Header = ({ interestsDisplayNames, }: { guide: Follow10ProgressGuide - inputRef: React.RefObject - listRef: React.RefObject + inputRef: React.RefObject + listRef: React.RefObject 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 + inputRef: React.RefObject defaultValue: string }) { const t = useTheme() diff --git a/src/components/ProgressGuide/Toast.tsx b/src/components/ProgressGuide/Toast.tsx index b26c718f87..d4ac771b25 100644 --- a/src/components/ProgressGuide/Toast.tsx +++ b/src/components/ProgressGuide/Toast.tsx @@ -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(null) - const timeoutRef = React.useRef() + const timeoutRef = React.useRef(undefined) const winDim = useWindowDimensions() /** diff --git a/src/components/Select/types.ts b/src/components/Select/types.ts index 661621a603..0e58c197be 100644 --- a/src/components/Select/types.ts +++ b/src/components/Select/types.ts @@ -160,7 +160,7 @@ export type ContentProps = { item: T, index: number, selectedValue?: string | null, - ) => React.ReactElement + ) => React.ReactElement /* * Extracts the value from an item. Defaults to `item => item.value` */ diff --git a/src/components/dialogs/GifSelect.tsx b/src/components/dialogs/GifSelect.tsx index 8ced355e47..a4296674d5 100644 --- a/src/components/dialogs/GifSelect.tsx +++ b/src/components/dialogs/GifSelect.tsx @@ -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 }) { diff --git a/src/components/dialogs/SearchablePeopleList.tsx b/src/components/dialogs/SearchablePeopleList.tsx index 26e20db57c..ab4dc2389b 100644 --- a/src/components/dialogs/SearchablePeopleList.tsx +++ b/src/components/dialogs/SearchablePeopleList.tsx @@ -483,7 +483,7 @@ function SearchInput({ value: string onChangeText: (text: string) => void onEscape: () => void - inputRef: React.RefObject + inputRef: React.RefObject }) { const t = useTheme() const {_} = useLingui() diff --git a/src/components/forms/InputGroup.tsx b/src/components/forms/InputGroup.tsx index 6908d4df8e..428f67ef61 100644 --- a/src/components/forms/InputGroup.tsx +++ b/src/components/forms/InputGroup.tsx @@ -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, diff --git a/src/components/forms/TextField.tsx b/src/components/forms/TextField.tsx index e5fb338497..8cee2bcf0c 100644 --- a/src/components/forms/TextField.tsx +++ b/src/components/forms/TextField.tsx @@ -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 | null + inputRef: React.RefObject | null isInvalid: boolean hovered: boolean onHoverIn: () => void @@ -140,7 +140,7 @@ export type InputProps = Omit & { value?: string onChangeText?: (value: string) => void isInvalid?: boolean - inputRef?: React.RefObject | React.ForwardedRef + inputRef?: React.RefObject | React.ForwardedRef } export function createInput(Component: typeof TextInput) { diff --git a/src/components/forms/ToggleButton.tsx b/src/components/forms/ToggleButton.tsx index 8e08665fde..504f1a5ca1 100644 --- a/src/components/forms/ToggleButton.tsx +++ b/src/components/forms/ToggleButton.tsx @@ -1,5 +1,5 @@ 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 +7,7 @@ import {Text} from '#/components/Typography' type ItemProps = Omit & AccessibilityProps & { - children: React.ReactElement + children: React.ReactElement testID?: string } diff --git a/src/components/hooks/useFullscreen.ts b/src/components/hooks/useFullscreen.ts index 498f22223c..cbe3e581c2 100644 --- a/src/components/hooks/useFullscreen.ts +++ b/src/components/hooks/useFullscreen.ts @@ -14,7 +14,7 @@ function fullscreenSubscribe(onChange: () => void) { return () => document.removeEventListener('fullscreenchange', onChange) } -export function useFullscreen(ref?: React.RefObject) { +export function useFullscreen(ref?: React.RefObject) { if (!isWeb) throw new Error("'useFullscreen' is a web-only hook") const isFullscreen = useSyncExternalStore(fullscreenSubscribe, () => Boolean(document.fullscreenElement), diff --git a/src/lib/hooks/useAnimatedValue.ts b/src/lib/hooks/useAnimatedValue.ts index 1307ef9522..9ae14dab62 100644 --- a/src/lib/hooks/useAnimatedValue.ts +++ b/src/lib/hooks/useAnimatedValue.ts @@ -2,7 +2,7 @@ import * as React from 'react' import {Animated} from 'react-native' export function useAnimatedValue(initialValue: number) { - const lazyRef = React.useRef() + const lazyRef = React.useRef(undefined) if (lazyRef.current === undefined) { lazyRef.current = new Animated.Value(initialValue) diff --git a/src/lib/hooks/useOTAUpdates.ts b/src/lib/hooks/useOTAUpdates.ts index 731406dcec..46e9f2d9a6 100644 --- a/src/lib/hooks/useOTAUpdates.ts +++ b/src/lib/hooks/useOTAUpdates.ts @@ -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('active') const lastMinimize = React.useRef(0) const ranInitialCheck = React.useRef(false) - const timeout = React.useRef() + const timeout = React.useRef(undefined) const {isUpdatePending} = useUpdates() const setCheckTimeout = React.useCallback(() => { diff --git a/src/lib/merge-refs.ts b/src/lib/merge-refs.ts index 4617b5260d..b038995473 100644 --- a/src/lib/merge-refs.ts +++ b/src/lib/merge-refs.ts @@ -13,7 +13,7 @@ * returns a ref callback function that can be used to merge multiple refs into a single ref. */ export function mergeRefs( - refs: Array | React.LegacyRef>, + refs: Array | React.Ref>, ): React.RefCallback { return value => { refs.forEach(ref => { diff --git a/src/screens/Signup/StepInfo/Policies.tsx b/src/screens/Signup/StepInfo/Policies.tsx index 81533c58e7..ffb052334d 100644 --- a/src/screens/Signup/StepInfo/Policies.tsx +++ b/src/screens/Signup/StepInfo/Policies.tsx @@ -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 if (tos && pp) { els = ( diff --git a/src/screens/Signup/StepInfo/index.tsx b/src/screens/Signup/StepInfo/index.tsx index f24cd0e45d..9c909eeeec 100644 --- a/src/screens/Signup/StepInfo/index.tsx +++ b/src/screens/Signup/StepInfo/index.tsx @@ -57,7 +57,7 @@ export function StepInfo({ const [hasWarnedEmail, setHasWarnedEmail] = React.useState(false) - const tldtsRef = React.useRef() + const tldtsRef = React.useRef(undefined) React.useEffect(() => { // @ts-expect-error - valid path import('tldts/dist/index.cjs.min.js').then(tldts => { diff --git a/src/state/queries/postgate/index.ts b/src/state/queries/postgate/index.ts index 346e7bfe29..fac60fc29d 100644 --- a/src/state/queries/postgate/index.ts +++ b/src/state/queries/postgate/index.ts @@ -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() + const prevEmbed = React.useRef(undefined) return useMutation({ mutationFn: async ({ diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index 42f057803f..9e9198bf2d 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -160,7 +160,7 @@ export const ComposePost = ({ videoUri: initVideoUri, cancelRef, }: Props & { - cancelRef?: React.RefObject + cancelRef?: React.RefObject }) => { const {currentAccount} = useSession() const agent = useAgent() diff --git a/src/view/com/composer/photos/EditImageDialog.web.tsx b/src/view/com/composer/photos/EditImageDialog.web.tsx index 9a170736a3..cda4e9ecfa 100644 --- a/src/view/com/composer/photos/EditImageDialog.web.tsx +++ b/src/view/com/composer/photos/EditImageDialog.web.tsx @@ -112,7 +112,7 @@ function EditImageInner({ aspectRatio, }: Required> & Omit & { - saveRef: React.RefObject<{save: () => Promise}> + saveRef: React.RefObject<{save: () => Promise} | null> }) { const t = useTheme() const [isDragging, setIsDragging] = useState(false) diff --git a/src/view/com/home/HomeHeaderLayout.web.tsx b/src/view/com/home/HomeHeaderLayout.web.tsx index d8bbe19e68..a1943ea3b0 100644 --- a/src/view/com/home/HomeHeaderLayout.web.tsx +++ b/src/view/com/home/HomeHeaderLayout.web.tsx @@ -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' diff --git a/src/view/com/home/HomeHeaderLayoutMobile.tsx b/src/view/com/home/HomeHeaderLayoutMobile.tsx index e48c2cc893..f9f082ff57 100644 --- a/src/view/com/home/HomeHeaderLayoutMobile.tsx +++ b/src/view/com/home/HomeHeaderLayoutMobile.tsx @@ -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' diff --git a/src/view/com/lists/ListMembers.tsx b/src/view/com/lists/ListMembers.tsx index dc18cbe5db..d56bcb7a08 100644 --- a/src/view/com/lists/ListMembers.tsx +++ b/src/view/com/lists/ListMembers.tsx @@ -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' diff --git a/src/view/com/lists/MyLists.tsx b/src/view/com/lists/MyLists.tsx index 5f94946e8b..18110b8bac 100644 --- a/src/view/com/lists/MyLists.tsx +++ b/src/view/com/lists/MyLists.tsx @@ -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' diff --git a/src/view/com/notifications/NotificationFeed.tsx b/src/view/com/notifications/NotificationFeed.tsx index 1f87b3186f..5cbc0586a3 100644 --- a/src/view/com/notifications/NotificationFeed.tsx +++ b/src/view/com/notifications/NotificationFeed.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, {type JSX} from 'react' import { ActivityIndicator, type ListRenderItemInfo, diff --git a/src/view/com/notifications/NotificationFeedItem.tsx b/src/view/com/notifications/NotificationFeedItem.tsx index 0a460e77b6..315ac98d00 100644 --- a/src/view/com/notifications/NotificationFeedItem.tsx +++ b/src/view/com/notifications/NotificationFeedItem.tsx @@ -230,7 +230,7 @@ let NotificationFeedItem = ({ : '' let a11yLabel = '' - let notificationContent: ReactElement + let notificationContent: ReactElement let icon = ( JSX.Element) | null)[] - | ((props: PagerWithHeaderChildParams) => JSX.Element) + | (((props: PagerWithHeaderChildParams) => React.JSX.Element) | null)[] + | ((props: PagerWithHeaderChildParams) => React.JSX.Element) items: string[] isHeaderReady: boolean renderHeader?: ({ setMinimumHeight, }: { setMinimumHeight: (height: number) => void - }) => JSX.Element + }) => React.JSX.Element initialPage?: number onPageSelected?: (index: number) => void onCurrentPageSelected?: (index: number) => void diff --git a/src/view/com/pager/PagerWithHeader.web.tsx b/src/view/com/pager/PagerWithHeader.web.tsx index 3e530358a3..001192a73b 100644 --- a/src/view/com/pager/PagerWithHeader.web.tsx +++ b/src/view/com/pager/PagerWithHeader.web.tsx @@ -1,11 +1,15 @@ import * as React from 'react' -import {ScrollView, View} from 'react-native' +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 { @@ -17,15 +21,15 @@ export interface PagerWithHeaderChildParams { export interface PagerWithHeaderProps { testID?: string children: - | (((props: PagerWithHeaderChildParams) => JSX.Element) | null)[] - | ((props: PagerWithHeaderChildParams) => JSX.Element) + | (((props: PagerWithHeaderChildParams) => React.JSX.Element) | null)[] + | ((props: PagerWithHeaderChildParams) => React.JSX.Element) items: string[] isHeaderReady: boolean renderHeader?: ({ setMinimumHeight, }: { setMinimumHeight: () => void - }) => JSX.Element + }) => React.JSX.Element initialPage?: number onPageSelected?: (index: number) => void onCurrentPageSelected?: (index: number) => void @@ -123,11 +127,11 @@ let PagerTabBar = ({ setMinimumHeight, }: { setMinimumHeight: () => void - }) => JSX.Element + }) => React.JSX.Element isHeaderReady: boolean onCurrentPageSelected?: (index: number) => void onSelect?: (index: number) => void - tabBarAnchor?: JSX.Element | null | undefined + tabBarAnchor?: React.JSX.Element | null | undefined }): React.ReactNode => { return ( <> @@ -164,7 +168,7 @@ function PagerItem({ renderTab, }: { isFocused: boolean - renderTab: ((props: PagerWithHeaderChildParams) => JSX.Element) | null + renderTab: ((props: PagerWithHeaderChildParams) => React.JSX.Element) | null }) { const scrollElRef = useAnimatedRef() if (renderTab == null) { diff --git a/src/view/com/pager/TabBar.web.tsx b/src/view/com/pager/TabBar.web.tsx index 8afea00196..d226505352 100644 --- a/src/view/com/pager/TabBar.web.tsx +++ b/src/view/com/pager/TabBar.web.tsx @@ -106,7 +106,9 @@ export function TabBar({ (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)} diff --git a/src/view/com/util/List.tsx b/src/view/com/util/List.tsx index 28f21d0392..3b92d786f0 100644 --- a/src/view/com/util/List.tsx +++ b/src/view/com/util/List.tsx @@ -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( ...props }, ref, - ): React.ReactElement => { + ): React.ReactElement => { const isScrolledDown = useSharedValue(false) const t = useTheme() const dedupe = useDedupe(400) diff --git a/src/view/com/util/List.web.tsx b/src/view/com/util/List.web.tsx index 18f7d6fa7e..fb5bbc822f 100644 --- a/src/view/com/util/List.web.tsx +++ b/src/view/com/util/List.web.tsx @@ -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 | null + root?: React.RefObject | null topMargin?: string bottomMargin?: string - containerRef: React.RefObject + containerRef: React.RefObject onVisibleChange: (isVisible: boolean) => void }) { const [containerHeight, setContainerHeight] = React.useState(0) @@ -399,7 +410,7 @@ function EdgeVisibility({ } function useResizeObserver( - ref: React.RefObject, + ref: React.RefObject, onResize: undefined | ((w: number, h: number) => void), ) { const handleResize = useNonReactiveCallback(onResize ?? (() => {})) @@ -504,7 +515,7 @@ let Visibility = ({ onVisibleChange, style, }: { - root?: React.RefObject | null + root?: React.RefObject | 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 ( props: ListProps & {ref?: React.Ref}, -) => React.ReactElement +) => React.ReactElement // https://stackoverflow.com/questions/7944460/detect-safari-browser diff --git a/src/view/com/util/TimeElapsed.tsx b/src/view/com/util/TimeElapsed.tsx index 70fed222f2..146b0d523a 100644 --- a/src/view/com/util/TimeElapsed.tsx +++ b/src/view/com/util/TimeElapsed.tsx @@ -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' diff --git a/src/view/com/util/Toast.tsx b/src/view/com/util/Toast.tsx index 56c6780ad3..4f1b3edb32 100644 --- a/src/view/com/util/Toast.tsx +++ b/src/view/com/util/Toast.tsx @@ -68,7 +68,7 @@ function Toast({ }, 1e3) } - const destroyTimeoutRef = useRef>() + const destroyTimeoutRef = useRef>(undefined) const hideAndDestroyAfterTimeout = useNonReactiveCallback(() => { clearTimeout(destroyTimeoutRef.current) destroyTimeoutRef.current = setTimeout(hideAndDestroyImmediately, TIMEOUT) diff --git a/src/view/com/util/ViewHeader.tsx b/src/view/com/util/ViewHeader.tsx index 2d413f7825..209374f08b 100644 --- a/src/view/com/util/ViewHeader.tsx +++ b/src/view/com/util/ViewHeader.tsx @@ -1,3 +1,5 @@ +import {type JSX} from 'react' + import {Header} from '#/components/Layout' /** diff --git a/src/view/com/util/ViewSelector.tsx b/src/view/com/util/ViewSelector.tsx index b5075707a2..fb0e4b1552 100644 --- a/src/view/com/util/ViewSelector.tsx +++ b/src/view/com/util/ViewSelector.tsx @@ -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 - | React.ReactElement + | React.ReactElement | null | undefined onSelectView?: (viewIndex: number) => void diff --git a/src/view/com/util/fab/FABInner.tsx b/src/view/com/util/fab/FABInner.tsx index 77e283625c..c2d64411a1 100644 --- a/src/view/com/util/fab/FABInner.tsx +++ b/src/view/com/util/fab/FABInner.tsx @@ -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' diff --git a/src/view/com/util/forms/NativeDropdown.web.tsx b/src/view/com/util/forms/NativeDropdown.web.tsx index cab7bac510..1276e9f634 100644 --- a/src/view/com/util/forms/NativeDropdown.web.tsx +++ b/src/view/com/util/forms/NativeDropdown.web.tsx @@ -158,7 +158,7 @@ function DropdownContent({ menuRef, }: { items: DropdownItem[] - menuRef: React.RefObject + menuRef: React.RefObject }) { const pal = usePalette('default') const theme = useTheme() diff --git a/src/view/com/util/post-embeds/VideoEmbed.web.tsx b/src/view/com/util/post-embeds/VideoEmbed.web.tsx index b0ded67548..ec0478b1bd 100644 --- a/src/view/com/util/post-embeds/VideoEmbed.web.tsx +++ b/src/view/com/util/post-embeds/VideoEmbed.web.tsx @@ -1,8 +1,9 @@ -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' +import type React from 'react'; import {isFirefox} from '#/lib/browser' import {ConstrainedImage} from '#/view/com/util/images/AutoSizedImage' @@ -30,7 +31,7 @@ export function VideoEmbed({ useActiveVideoWeb() const [onScreen, setOnScreen] = useState(false) const [isFullscreen] = useFullscreen() - const lastKnownTime = useRef() + const lastKnownTime = useRef(undefined) useEffect(() => { if (!ref.current) return diff --git a/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerWeb.tsx b/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerWeb.tsx index 77f6cd0a6c..e565d1d8fd 100644 --- a/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerWeb.tsx +++ b/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerWeb.tsx @@ -139,7 +139,7 @@ function useHLS({ playlist: string setHasSubtitleTrack: (v: boolean) => void setError: (v: Error | null) => void - videoRef: React.RefObject + videoRef: React.RefObject setHlsLoading: (v: boolean) => void }) { const [Hls, setHls] = useState( diff --git a/src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VideoControls.tsx b/src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VideoControls.tsx index 8e134d2217..a5f9180d55 100644 --- a/src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VideoControls.tsx +++ b/src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VideoControls.tsx @@ -1,8 +1,9 @@ -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' import type Hls from 'hls.js' +import type React from 'react'; import {isTouchDevice} from '#/lib/browser' import {clamp} from '#/lib/numbers' @@ -46,14 +47,14 @@ export function Controls({ hlsLoading, hasSubtitleTrack, }: { - videoRef: React.RefObject - hlsRef: React.RefObject + videoRef: React.RefObject + hlsRef: React.RefObject active: boolean setActive: () => void focused: boolean setFocused: (focused: boolean) => void onScreen: boolean - fullscreenRef: React.RefObject + fullscreenRef: React.RefObject hlsLoading: boolean hasSubtitleTrack: boolean }) { @@ -232,7 +233,7 @@ export function Controls({ }, [onSeek, videoRef]) const [showCursor, setShowCursor] = useState(true) - const cursorTimeoutRef = useRef>() + const cursorTimeoutRef = useRef>(undefined) const onPointerMoveEmptySpace = useCallback(() => { setShowCursor(true) if (cursorTimeoutRef.current) { @@ -264,7 +265,7 @@ export function Controls({ [hovered], ) - const timeoutRef = useRef>() + const timeoutRef = useRef>(undefined) const onHoverWithTimeout = useCallback(() => { onHover() diff --git a/src/view/com/util/post-embeds/VideoEmbedInner/web-controls/utils.tsx b/src/view/com/util/post-embeds/VideoEmbedInner/web-controls/utils.tsx index 108814ea2b..681023a525 100644 --- a/src/view/com/util/post-embeds/VideoEmbedInner/web-controls/utils.tsx +++ b/src/view/com/util/post-embeds/VideoEmbedInner/web-controls/utils.tsx @@ -1,9 +1,10 @@ -import React, {useCallback, useEffect, useRef, useState} from 'react' +import {useCallback, useEffect, useRef, useState} from 'react' +import type React from 'react'; import {isSafari} from '#/lib/browser' import {useVideoVolumeState} from '../../VideoVolumeContext' -export function useVideoElement(ref: React.RefObject) { +export function useVideoElement(ref: React.RefObject) { const [playing, setPlaying] = useState(false) const [muted, setMuted] = useState(true) const [currentTime, setCurrentTime] = useState(0) diff --git a/src/view/screens/Storybook/Dialogs.tsx b/src/view/screens/Storybook/Dialogs.tsx index 4b4d4191f9..3c1d4f20b4 100644 --- a/src/view/screens/Storybook/Dialogs.tsx +++ b/src/view/screens/Storybook/Dialogs.tsx @@ -22,7 +22,7 @@ export function Dialogs() { React.useState() const [shouldRenderUnmountTest, setShouldRenderUnmountTest] = React.useState(false) - const unmountTestInterval = React.useRef() + const unmountTestInterval = React.useRef(undefined) const onUnmountTestStartPressWithClose = () => { setShouldRenderUnmountTest(true) diff --git a/src/view/shell/Drawer.tsx b/src/view/shell/Drawer.tsx index 79d8a21aef..fad1a482b4 100644 --- a/src/view/shell/Drawer.tsx +++ b/src/view/shell/Drawer.tsx @@ -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' diff --git a/src/view/shell/bottom-bar/BottomBarWeb.tsx b/src/view/shell/bottom-bar/BottomBarWeb.tsx index 7a320cb438..330922fa33 100644 --- a/src/view/shell/bottom-bar/BottomBarWeb.tsx +++ b/src/view/shell/bottom-bar/BottomBarWeb.tsx @@ -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 diff --git a/yarn.lock b/yarn.lock index d299bede55..93330c9083 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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" @@ -7574,13 +7569,11 @@ 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== +"@types/react@*", "@types/react@^19": + version "19.1.4" + resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.4.tgz#4d125f014d6ac26b4759775698db118701e314fe" + integrity sha512-EB1yiiYdvySuIITtD5lhW4yPyJ31RkJkkDw794LaQYrxCSaQV/47y5o1FMC4zF9ZyjUjzJMZwbovEnT5yHTW6g== dependencies: - "@types/prop-types" "*" - "@types/scheduler" "*" csstype "^3.0.2" "@types/retry@0.12.0": @@ -7588,11 +7581,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"