Enable React Native strict TypeScript API (#11459)
This commit is contained in:
@@ -271,7 +271,6 @@ function HashtagScreenTab({
|
||||
onEndReached={onEndReached}
|
||||
onEndReachedThreshold={4}
|
||||
onItemSeen={trackPostView}
|
||||
// @ts-ignore web only -prf
|
||||
desktopFixedHeight
|
||||
ListFooterComponent={
|
||||
<ListFooter
|
||||
|
||||
@@ -78,8 +78,8 @@ export const LoginForm = ({
|
||||
const [identifier, setIdentifier] = useState(initialHandle || '')
|
||||
const [identifierFocused, setIdentifierFocused] = useState(false)
|
||||
const [authFactorToken, setAuthFactorToken] = useState('')
|
||||
const identifierRef = useRef<TextInput>(null)
|
||||
const passwordRef = useRef<TextInput>(null)
|
||||
const identifierRef = useRef<React.ComponentRef<typeof TextInput>>(null)
|
||||
const passwordRef = useRef<React.ComponentRef<typeof TextInput>>(null)
|
||||
const hasFocusedOnce = useRef(false)
|
||||
const [hasPassword, setHasPassword] = useState(false)
|
||||
const [revealPassword, setRevealPassword] = useState(false)
|
||||
|
||||
@@ -379,7 +379,7 @@ function JoinRequestsList({
|
||||
style={[a.flex_1, a.align_center, a.justify_center, a.py_4xl]}>
|
||||
<Loader size="xl" />
|
||||
</View>
|
||||
) : null
|
||||
) : undefined
|
||||
}
|
||||
contentContainerStyle={
|
||||
showFooter ? {paddingBottom: footerHeight} : undefined
|
||||
|
||||
@@ -189,7 +189,7 @@ export function MessageComposer({
|
||||
<View
|
||||
collapsable={false}
|
||||
ref={native(
|
||||
(node: View) =>
|
||||
(node: React.ComponentRef<typeof View>) =>
|
||||
void composerInternalApiRef.current?.setAutocompleteAnchor(node),
|
||||
)}>
|
||||
<GlassContainer
|
||||
@@ -209,7 +209,9 @@ export function MessageComposer({
|
||||
composerInternalApiRef.current?.insert(emoji.native)
|
||||
}
|
||||
nextFocusRef={() =>
|
||||
composerInternalApiRef.current?.input?.element
|
||||
composerInternalApiRef.current?.input
|
||||
?.element as unknown as
|
||||
{focus: () => void} | null | undefined
|
||||
}>
|
||||
<EmojiPicker.Trigger label={l`Open emoji picker`}>
|
||||
{({props, state, control}) => (
|
||||
|
||||
@@ -35,7 +35,7 @@ export function Layout({children}: React.PropsWithChildren<{}>) {
|
||||
const {gtMobile} = useBreakpoints()
|
||||
const onboardDispatch = useOnboardingDispatch()
|
||||
const {state, dispatch} = useOnboardingInternalState()
|
||||
const scrollview = useRef<ScrollView>(null)
|
||||
const scrollview = useRef<React.ComponentRef<typeof ScrollView>>(null)
|
||||
const prevActiveStep = useRef<string>(state.activeStep)
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {useRef, useState} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import PagerView from 'react-native-pager-view'
|
||||
import {type PagerViewOnPageSelectedEvent} from 'react-native-pager-view'
|
||||
import {Image} from 'expo-image'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
@@ -36,7 +37,7 @@ export function ValuePropositionPager({
|
||||
ref={ref}
|
||||
style={[a.flex_1]}
|
||||
initialPage={step}
|
||||
onPageSelected={evt => {
|
||||
onPageSelected={(evt: PagerViewOnPageSelectedEvent) => {
|
||||
const page = evt.nativeEvent.position as 0 | 1 | 2
|
||||
if (step !== page) {
|
||||
setActivePage(page)
|
||||
|
||||
@@ -52,7 +52,6 @@ export const PlaceholderCanvas = forwardRef<PlaceholderCanvasRef, {}>(
|
||||
<View style={styles.container}>
|
||||
<Suspense fallback={null}>
|
||||
<LazyViewShot
|
||||
// @ts-ignore this library doesn't have types
|
||||
ref={viewshotRef}
|
||||
options={{
|
||||
fileName: 'placeholderAvatar',
|
||||
|
||||
@@ -378,7 +378,7 @@ function SuggestedProfileCard({
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const ax = useAnalytics()
|
||||
const cardRef = useRef<View>(null)
|
||||
const cardRef = useRef<React.ComponentRef<typeof View>>(null)
|
||||
const hasTrackedRef = useRef(false)
|
||||
|
||||
useEffect(() => {
|
||||
@@ -396,7 +396,7 @@ function SuggestedProfileCard({
|
||||
},
|
||||
{threshold: 0.5},
|
||||
)
|
||||
// @ts-ignore - web only
|
||||
// @ts-expect-error - web only
|
||||
observer.observe(node)
|
||||
return () => observer.disconnect()
|
||||
} else {
|
||||
|
||||
@@ -160,8 +160,8 @@ export function PostThread({uri}: {uri: string}) {
|
||||
const totalParentCount = useRef(0) // recomputed below
|
||||
const totalChildrenCount = useRef(thread.data.items.length) // recomputed below
|
||||
const listRef = useRef<ListMethods>(null)
|
||||
const anchorRef = useRef<View | null>(null)
|
||||
const headerRef = useRef<View | null>(null)
|
||||
const anchorRef = useRef<React.ComponentRef<typeof View> | null>(null)
|
||||
const headerRef = useRef<React.ComponentRef<typeof View> | null>(null)
|
||||
|
||||
/*
|
||||
* On a cold load, parents are not prepended until the anchor post has
|
||||
|
||||
@@ -128,7 +128,6 @@ export const ProfileKnownFollowersScreen = ({route}: Props) => {
|
||||
onRetry={fetchNextPage}
|
||||
/>
|
||||
}
|
||||
// @ts-ignore our .web version only -prf
|
||||
desktopFixedHeight
|
||||
initialNumToRender={initialNumToRender}
|
||||
windowSize={11}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {useCallback, useMemo, useRef, useState} from 'react'
|
||||
import {View, type ViewabilityConfig} from 'react-native'
|
||||
import {View} from 'react-native'
|
||||
import {Trans, useLingui} from '@lingui/react/macro'
|
||||
import {type ViewabilityConfig} from '@react-native/virtualized-lists'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
import * as bcp47Match from 'bcp-47-match'
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ export function SearchScreenShell({
|
||||
const {gtMobile} = useBreakpoints()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const route = useRoute()
|
||||
const textInput = useRef<TextInput>(null)
|
||||
const textInput = useRef<React.ComponentRef<typeof TextInput>>(null)
|
||||
const {t: l} = useLingui()
|
||||
const {currentAccount} = useSession()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
@@ -28,7 +28,7 @@ export function ClearableInput({
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const {t: l} = useLingui()
|
||||
const inputRef = useRef<TextInput>(null)
|
||||
const inputRef = useRef<React.ComponentRef<typeof TextInput>>(null)
|
||||
const [showClear, setShowClear] = useState(defaultValue.length > 0)
|
||||
|
||||
return (
|
||||
|
||||
@@ -137,8 +137,8 @@ function DialogInner({
|
||||
const [dateUntilActive, setDateUntilActive] = useState(!!parsed.until)
|
||||
|
||||
const [filters, setFilters] = useState<AdvancedFilter[]>(parsed.filters)
|
||||
const scrollRef = useRef<ScrollView>(null)
|
||||
const filtersSectionRef = useRef<View>(null)
|
||||
const scrollRef = useRef<React.ComponentRef<typeof ScrollView>>(null)
|
||||
const filtersSectionRef = useRef<React.ComponentRef<typeof View>>(null)
|
||||
|
||||
function addFilter() {
|
||||
if (filters.length >= MAX_FILTERS) return
|
||||
|
||||
@@ -37,7 +37,7 @@ export function SearchAutocompleteInput({
|
||||
* keystroke while the input is still focused.
|
||||
*/
|
||||
const [dismissed, setDismissed] = useState(false)
|
||||
const inputRef = useRef<TextInput>(null)
|
||||
const inputRef = useRef<React.ComponentRef<typeof TextInput>>(null)
|
||||
|
||||
const sift = useSift({
|
||||
offset: a.p_sm.padding,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import {type ImageSourcePropType} from 'react-native'
|
||||
import {type ImageSource} from 'expo-image'
|
||||
import type * as DynamicAppIcon from '@bsky.app/expo-dynamic-app-icon'
|
||||
|
||||
export type AppIconSet = {
|
||||
id: DynamicAppIcon.IconName
|
||||
name: string
|
||||
iosImage: () => ImageSourcePropType
|
||||
androidImage: () => ImageSourcePropType
|
||||
iosImage: () => ImageSource
|
||||
androidImage: () => ImageSource
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ export function ActivityNotificationSettingsScreen({}: Props) {
|
||||
onEndReached={onEndReached}
|
||||
onEndReachedThreshold={4}
|
||||
ListEmptyComponent={
|
||||
error ? null : (
|
||||
error ? undefined : (
|
||||
<View style={[a.px_xl, a.py_md]}>
|
||||
{!isPending ? (
|
||||
<Admonition.Outer type="tip">
|
||||
|
||||
@@ -73,7 +73,7 @@ function DeleteAccountDialogInner({
|
||||
control: DialogOuterProps['control']
|
||||
deactivateDialogControl: DialogOuterProps['control']
|
||||
}) {
|
||||
const passwordRef = useRef<TextInput | null>(null)
|
||||
const passwordRef = useRef<React.ComponentRef<typeof TextInput> | null>(null)
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const cleanError = useCleanError()
|
||||
|
||||
@@ -3,7 +3,6 @@ import {StyleSheet} from 'react-native'
|
||||
|
||||
import {type CaptchaWebViewProps} from './CaptchaWebView.shared'
|
||||
|
||||
// @ts-ignore web only, we will always redirect to the app on web (CORS)
|
||||
const REDIRECT_HOST = new URL(window.location.href).host
|
||||
|
||||
export function CaptchaWebView({
|
||||
@@ -25,13 +24,11 @@ export function CaptchaWebView({
|
||||
}, [onError])
|
||||
|
||||
const onLoad = useCallback(() => {
|
||||
// @ts-ignore web
|
||||
const frame: HTMLIFrameElement = document.getElementById(
|
||||
'captcha-iframe',
|
||||
) as HTMLIFrameElement
|
||||
|
||||
try {
|
||||
// @ts-ignore web
|
||||
const href = frame?.contentWindow?.location.href
|
||||
if (!href) return
|
||||
const urlp = new URL(href)
|
||||
|
||||
@@ -68,8 +68,8 @@ export function StepInfo({
|
||||
const prevEmailValueRef = useRef<string>(state.email)
|
||||
const passwordValueRef = useRef<string>(state.password)
|
||||
|
||||
const emailInputRef = useRef<TextInput>(null)
|
||||
const passwordInputRef = useRef<TextInput>(null)
|
||||
const emailInputRef = useRef<React.ComponentRef<typeof TextInput>>(null)
|
||||
const passwordInputRef = useRef<React.ComponentRef<typeof TextInput>>(null)
|
||||
const birthdateInputRef = useRef<DateFieldRef>(null)
|
||||
|
||||
const aaRegionConfig = useAgeAssuranceRegionConfigWithFallback()
|
||||
|
||||
@@ -41,6 +41,7 @@ import {
|
||||
} from '#/state/shell/progress-guide'
|
||||
import {PagerWithHeader} from '#/view/com/pager/PagerWithHeader'
|
||||
import {ProfileSubpageHeader} from '#/view/com/profile/ProfileSubpageHeader'
|
||||
import {type ListRef} from '#/view/com/util/List'
|
||||
import {bulkWriteFollows} from '#/screens/Onboarding/util'
|
||||
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||
@@ -251,8 +252,7 @@ function StarterPackScreenLoaded({
|
||||
// Validated above
|
||||
listUri={starterPack.list!.uri}
|
||||
headerHeight={headerHeight}
|
||||
// @ts-expect-error
|
||||
scrollElRef={scrollElRef}
|
||||
scrollElRef={scrollElRef as ListRef}
|
||||
moderationOpts={moderationOpts}
|
||||
/>
|
||||
)
|
||||
@@ -260,11 +260,9 @@ function StarterPackScreenLoaded({
|
||||
{showFeedsTab
|
||||
? ({headerHeight, scrollElRef}) => (
|
||||
<FeedsList
|
||||
// @ts-expect-error ?
|
||||
feeds={starterPack?.feeds}
|
||||
feeds={starterPack.feeds!}
|
||||
headerHeight={headerHeight}
|
||||
// @ts-expect-error
|
||||
scrollElRef={scrollElRef}
|
||||
scrollElRef={scrollElRef as ListRef}
|
||||
/>
|
||||
)
|
||||
: null}
|
||||
@@ -274,9 +272,7 @@ function StarterPackScreenLoaded({
|
||||
// Validated above
|
||||
listUri={starterPack.list!.uri}
|
||||
headerHeight={headerHeight}
|
||||
// @ts-expect-error
|
||||
scrollElRef={scrollElRef}
|
||||
moderationOpts={moderationOpts}
|
||||
scrollElRef={scrollElRef as ListRef}
|
||||
/>
|
||||
)
|
||||
: null}
|
||||
|
||||
@@ -177,7 +177,6 @@ function TopicScreenTab({
|
||||
onEndReached={onEndReached}
|
||||
onEndReachedThreshold={4}
|
||||
onItemSeen={trackPostView}
|
||||
// @ts-ignore web only -prf
|
||||
desktopFixedHeight
|
||||
ListFooterComponent={
|
||||
<ListFooter
|
||||
|
||||
@@ -5,8 +5,6 @@ import {
|
||||
Pressable,
|
||||
ScrollView,
|
||||
View,
|
||||
type ViewabilityConfig,
|
||||
type ViewToken,
|
||||
} from 'react-native'
|
||||
import {
|
||||
Gesture,
|
||||
@@ -29,6 +27,10 @@ import {AtUri} from '@atproto/syntax'
|
||||
import {type ModerationDecision} from '@bsky/sdk/moderation'
|
||||
import {RichText as RichTextAPI} from '@bsky/sdk/richtext'
|
||||
import {Trans, useLingui} from '@lingui/react/macro'
|
||||
import {
|
||||
type ListViewToken as ViewToken,
|
||||
type ViewabilityConfig,
|
||||
} from '@react-native/virtualized-lists'
|
||||
import {
|
||||
type RouteProp,
|
||||
useFocusEffect,
|
||||
@@ -413,7 +415,7 @@ function Feed() {
|
||||
|
||||
const onViewableItemsChanged = useCallback(
|
||||
({viewableItems}: {viewableItems: ViewToken[]; changed: ViewToken[]}) => {
|
||||
if (viewableItems[0] && viewableItems[0].index !== null) {
|
||||
if (viewableItems[0]?.index != null) {
|
||||
const newIndex = viewableItems[0].index
|
||||
setCurrentIndex(newIndex)
|
||||
updateVideoState(newIndex)
|
||||
|
||||
Reference in New Issue
Block a user