···2323import {atoms as a, native} from '#/alf'
2424import {ScreenTransition} from '#/components/ScreenTransition'
2525import {useAnalytics} from '#/analytics'
2626-import {IS_WEB} from '#/env'
2726import {ChooseAccountForm} from './ChooseAccountForm'
2827import * as AuthLayout from './components/AuthLayout'
2928import {AuthLayoutNavigationContext} from './components/AuthLayout/context'
+2-2
src/screens/PostThread/index.tsx
···7373 * One query to rule them all
7474 */
7575 const thread = usePostThread({anchor: uri})
7676- const {anchor, hasParents} = useMemo(() => {
7676+ const {anchor, hasParents} = (() => {
7777 let hasParents = false
7878 for (const item of thread.data.items) {
7979 if (item.type === 'threadPost' && item.depth === 0) {
···8282 hasParents = true
8383 }
8484 return {hasParents}
8585- }, [thread.data.items])
8585+ })()
86868787 // Track post:view event when anchor post is viewed
8888 const seenPostUriRef = useRef<string | null>(null)
+8-3
src/state/gallery.ts
···1313} from 'expo-image-manipulator'
1414import {type BlobRef} from '@atproto/api'
1515import {transformExif} from '@uwx/exif-be-gone-web'
1616-import {toByteArray, fromByteArray} from 'base64-js'
1616+import {fromByteArray, toByteArray} from 'base64-js'
1717import {nanoid} from 'nanoid/non-secure'
18181919import {POST_IMG_MAX} from '#/lib/constants'
···437437 })
438438}
439439440440-function arrayBufferToDataUri(buffer: Uint8Array | ArrayBufferLike, mime: string): string {
441441- const base64 = fromByteArray(buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer))
440440+function arrayBufferToDataUri(
441441+ buffer: Uint8Array | ArrayBufferLike,
442442+ mime: string,
443443+): string {
444444+ const base64 = fromByteArray(
445445+ buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer),
446446+ )
442447 return `data:${mime};base64,${base64}`
443448}
444449
+2-1
src/state/preferences/alt-text-required.tsx
···55 useEffect,
66 useState,
77} from 'react'
88+import type {PropsWithChildren} from 'react'
89910import * as persisted from '#/state/persisted'
1011···2021)
2122setContext.displayName = 'AltTextRequiredSetContext'
22232323-export function Provider({children}: React.PropsWithChildren<{}>) {
2424+export function Provider({children}: PropsWithChildren<{}>) {
2425 const [state, setState] = useState(persisted.get('requireAltTextEnabled'))
25262627 const setStateWrapped = useCallback(
+2-1
src/state/preferences/auto-like-on-repost.tsx
···55 useEffect,
66 useState,
77} from 'react'
88+import type {PropsWithChildren} from 'react'
89910import * as persisted from '#/state/persisted'
1011···2021)
2122setContext.displayName = 'AutoLikeOnRepostStateContext'
22232323-export function Provider({children}: React.PropsWithChildren<{}>) {
2424+export function Provider({children}: PropsWithChildren<{}>) {
2425 const [state, setState] = useState(persisted.get('autoLikeOnRepost'))
25262627 const setStateWrapped = useCallback(
+2-1
src/state/preferences/autoplay.tsx
···55 useEffect,
66 useState,
77} from 'react'
88+import type {PropsWithChildren} from 'react'
89910import * as persisted from '#/state/persisted'
1011···1819const setContext = createContext<SetContext>((_: boolean) => {})
1920setContext.displayName = 'AutoplaySetContext'
20212121-export function Provider({children}: {children: React.ReactNode}) {
2222+export function Provider({children}: PropsWithChildren<{}>) {
2223 const [state, setState] = useState(Boolean(persisted.get('disableAutoplay')))
23242425 const setStateWrapped = useCallback(
···55 useEffect,
66 useState,
77} from 'react'
88+import type {PropsWithChildren} from 'react'
89910import * as persisted from '#/state/persisted'
1011···2021)
2122setContext.displayName = 'InAppBrowserSetContext'
22232323-export function Provider({children}: React.PropsWithChildren<{}>) {
2424+export function Provider({children}: PropsWithChildren<{}>) {
2425 const [state, setState] = useState(persisted.get('useInAppBrowser'))
25262627 const setStateWrapped = useCallback(
+3-1
src/state/preferences/index.tsx
···11+import type {PropsWithChildren} from 'react'
22+13import {Provider as AltTextRequiredProvider} from './alt-text-required'
24import {Provider as AutoLikeOnRepostProvider} from './auto-like-on-repost'
35import {Provider as AutoplayProvider} from './autoplay'
···9799 useTranslationServicePreference,
98100} from './translation-service-preference'
99101100100-export function Provider({children}: React.PropsWithChildren<{}>) {
102102+export function Provider({children}: PropsWithChildren<{}>) {
101103 return (
102104 <LanguagesProvider>
103105 <AltTextRequiredProvider>
+2-1
src/state/preferences/label-defs.tsx
···33 type AppBskyLabelerDefs,
44 type InterpretedLabelValueDefinition,
55} from '@atproto/api'
66+import type {PropsWithChildren} from 'react'
6778import {useLabelDefinitionsQuery} from '../queries/preferences'
89···1718})
1819stateContext.displayName = 'LabelDefsStateContext'
19202020-export function Provider({children}: React.PropsWithChildren<{}>) {
2121+export function Provider({children}: PropsWithChildren<{}>) {
2122 const state = useLabelDefinitionsQuery()
2223 return <stateContext.Provider value={state}>{children}</stateContext.Provider>
2324}
+2-1
src/state/preferences/languages.tsx
···66 useMemo,
77 useState,
88} from 'react'
99+import type {PropsWithChildren} from 'react'
9101011import {type AppLanguage} from '#/locale/languages'
1112import * as persisted from '#/state/persisted'
···3637})
3738apiContext.displayName = 'LanguagePrefsApiContext'
38393939-export function Provider({children}: React.PropsWithChildren<{}>) {
4040+export function Provider({children}: PropsWithChildren<{}>) {
4041 const [state, setState] = useState(() => persisted.get('languagePrefs'))
41424243 const setStateWrapped = useCallback(
+2-1
src/state/preferences/large-alt-badge.tsx
···55 useEffect,
66 useState,
77} from 'react'
88+import type {PropsWithChildren} from 'react'
89910import * as persisted from '#/state/persisted'
1011···2021)
2122setContext.displayName = 'LargeAltBadgeSetContext'
22232323-export function Provider({children}: React.PropsWithChildren<{}>) {
2424+export function Provider({children}: PropsWithChildren<{}>) {
2425 const [state, setState] = useState(persisted.get('largeAltBadgeEnabled'))
25262627 const setStateWrapped = useCallback(
+2-1
src/state/preferences/moderation-opts.tsx
···11import {createContext, useContext, useMemo} from 'react'
22+import {type PropsWithChildren} from 'react'
23import {BskyAgent, type ModerationOpts} from '@atproto/api'
3445import {useHiddenPosts, useLabelDefinitions} from '#/state/preferences'
···2122 return useContext(moderationOptsContext)
2223}
23242424-export function Provider({children}: React.PropsWithChildren<{}>) {
2525+export function Provider({children}: PropsWithChildren<{}>) {
2526 const override = useContext(moderationOptsOverrideContext)
2627 const {currentAccount} = useSession()
2728 const prefs = usePreferencesQuery()
···11import {createContext, useContext, useEffect, useState} from 'react'
22+import type {ReactNode} from 'react'
2334import * as persisted from '#/state/persisted'
45···1011const setContext = createContext<SetContext>((_: boolean) => {})
1112setContext.displayName = 'UsedStarterPacksSetContext'
12131313-export function Provider({children}: {children: React.ReactNode}) {
1414+export function Provider({children}: {children: ReactNode}) {
1415 const [state, setState] = useState<StateContext>(() =>
1516 persisted.get('hasCheckedForStarterPack'),
1617 )
+1-1
src/state/session/index.tsx
···88 useState,
99 useSyncExternalStore,
1010} from 'react'
1111-import {type Agent, type AtpAgent, type AtpSessionEvent} from '@atproto/api'
1111+import {type AtpAgent, type AtpSessionEvent} from '@atproto/api'
12121313import * as persisted from '#/state/persisted'
1414import {useCloseAllActiveElements} from '#/state/util'
+1
src/state/session/oauth-native-client.ts
···11import {ExpoOAuthClient} from '@atproto/oauth-client-expo'
22+23import {createIdentityResolver} from './identity-resolver'
3445const OAUTH_BASE_URL: string =
···11-import {
22- Children,
33- type JSX,
44- useCallback,
55- useImperativeHandle,
66- useRef,
77- useState,
88-} from 'react'
11+import {Children, type JSX, useImperativeHandle, useRef, useState} from 'react'
92import {View} from 'react-native'
103import {flushSync} from 'react-dom'
114···4740 },
4841 }))
49425050- const onTabBarSelect = useCallback(
5151- (index: number) => {
5252- const scrollY = window.scrollY
5353- // We want to determine if the tabbar is already "sticking" at the top (in which
5454- // case we should preserve and restore scroll), or if it is somewhere below in the
5555- // viewport (in which case a scroll jump would be jarring). We determine this by
5656- // measuring where the "anchor" element is (which we place just above the tabbar).
5757- let anchorTop = anchorRef.current
5858- ? (anchorRef.current as Element).getBoundingClientRect().top
5959- : -scrollY // If there's no anchor, treat the top of the page as one.
6060- const isSticking = anchorTop <= 5 // This would be 0 if browser scrollTo() was reliable.
4343+ const onTabBarSelect = (index: number) => {
4444+ const scrollY = window.scrollY
4545+ // We want to determine if the tabbar is already "sticking" at the top (in which
4646+ // case we should preserve and restore scroll), or if it is somewhere below in the
4747+ // viewport (in which case a scroll jump would be jarring). We determine this by
4848+ // measuring where the "anchor" element is (which we place just above the tabbar).
4949+ let anchorTop = anchorRef.current
5050+ ? (anchorRef.current as Element).getBoundingClientRect().top
5151+ : -scrollY // If there's no anchor, treat the top of the page as one.
5252+ const isSticking = anchorTop <= 5 // This would be 0 if browser scrollTo() was reliable.
61536262- if (isSticking) {
6363- scrollYs.current[selectedPage] = window.scrollY
5454+ if (isSticking) {
5555+ scrollYs.current[selectedPage] = window.scrollY
5656+ } else {
5757+ scrollYs.current[selectedPage] = null
5858+ }
5959+ flushSync(() => {
6060+ setSelectedPage(index)
6161+ onPageSelected?.(index)
6262+ })
6363+ if (isSticking) {
6464+ const restoredScrollY = scrollYs.current[index]
6565+ if (restoredScrollY != null) {
6666+ window.scrollTo(0, restoredScrollY)
6467 } else {
6565- scrollYs.current[selectedPage] = null
6868+ window.scrollTo(0, scrollY + anchorTop)
6669 }
6767- flushSync(() => {
6868- setSelectedPage(index)
6969- onPageSelected?.(index)
7070- })
7171- if (isSticking) {
7272- const restoredScrollY = scrollYs.current[index]
7373- if (restoredScrollY != null) {
7474- window.scrollTo(0, restoredScrollY)
7575- } else {
7676- window.scrollTo(0, scrollY + anchorTop)
7777- }
7878- }
7979- },
8080- [selectedPage, setSelectedPage, onPageSelected],
8181- )
7070+ }
7171+ }
82728373 return (
8474 <View style={s.hContentRegion}>