Give explicit names to MobX observer components (#1413)

* Consider observer(...) as components

* Add display names to MobX observers

* Temporarily suppress nested components

* Suppress new false positives for react/prop-types
zio/stable
dan 2023-09-08 01:36:08 +01:00 committed by GitHub
parent 69209c988f
commit 8a93321fb1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
72 changed files with 2868 additions and 2836 deletions

View File

@ -26,4 +26,7 @@ module.exports = {
'*.html', '*.html',
'bskyweb', 'bskyweb',
], ],
settings: {
componentWrapperFunctions: ['observer'],
},
} }

View File

@ -19,7 +19,7 @@ import {handleLink} from './Navigation'
SplashScreen.preventAutoHideAsync() SplashScreen.preventAutoHideAsync()
const App = observer(() => { const App = observer(function AppImpl() {
const [rootStore, setRootStore] = useState<RootStoreModel | undefined>( const [rootStore, setRootStore] = useState<RootStoreModel | undefined>(
undefined, undefined,
) )

View File

@ -10,7 +10,7 @@ import {ToastContainer} from './view/com/util/Toast.web'
import {ThemeProvider} from 'lib/ThemeContext' import {ThemeProvider} from 'lib/ThemeContext'
import {observer} from 'mobx-react-lite' import {observer} from 'mobx-react-lite'
const App = observer(() => { const App = observer(function AppImpl() {
const [rootStore, setRootStore] = useState<RootStoreModel | undefined>( const [rootStore, setRootStore] = useState<RootStoreModel | undefined>(
undefined, undefined,
) )

View File

@ -330,7 +330,7 @@ function NotificationsTabNavigator() {
) )
} }
const MyProfileTabNavigator = observer(() => { const MyProfileTabNavigator = observer(function MyProfileTabNavigatorImpl() {
const contentStyle = useColorSchemeStyle(styles.bgLight, styles.bgDark) const contentStyle = useColorSchemeStyle(styles.bgLight, styles.bgDark)
const store = useStores() const store = useStores()
return ( return (
@ -360,7 +360,7 @@ const MyProfileTabNavigator = observer(() => {
* The FlatNavigator is used by Web to represent the routes * The FlatNavigator is used by Web to represent the routes
* in a single ("flat") stack. * in a single ("flat") stack.
*/ */
const FlatNavigator = observer(() => { const FlatNavigator = observer(function FlatNavigatorImpl() {
const pal = usePalette('default') const pal = usePalette('default')
const unreadCountLabel = useStores().me.notifications.unreadCountLabel const unreadCountLabel = useStores().me.notifications.unreadCountLabel
const title = (page: string) => bskyTitle(page, unreadCountLabel) const title = (page: string) => bskyTitle(page, unreadCountLabel)

View File

@ -16,7 +16,7 @@ enum ScreenState {
S_CreateAccount, S_CreateAccount,
} }
export const LoggedOut = observer(() => { export const LoggedOut = observer(function LoggedOutImpl() {
const pal = usePalette('default') const pal = usePalette('default')
const store = useStores() const store = useStores()
const {screen} = useAnalytics() const {screen} = useAnalytics()

View File

@ -8,7 +8,7 @@ import {useStores} from 'state/index'
import {Welcome} from './onboarding/Welcome' import {Welcome} from './onboarding/Welcome'
import {RecommendedFeeds} from './onboarding/RecommendedFeeds' import {RecommendedFeeds} from './onboarding/RecommendedFeeds'
export const Onboarding = observer(() => { export const Onboarding = observer(function OnboardingImpl() {
const pal = usePalette('default') const pal = usePalette('default')
const store = useStores() const store = useStores()

View File

@ -20,8 +20,11 @@ import {Step1} from './Step1'
import {Step2} from './Step2' import {Step2} from './Step2'
import {Step3} from './Step3' import {Step3} from './Step3'
export const CreateAccount = observer( export const CreateAccount = observer(function CreateAccountImpl({
({onPressBack}: {onPressBack: () => void}) => { onPressBack,
}: {
onPressBack: () => void
}) {
const {track, screen} = useAnalytics() const {track, screen} = useAnalytics()
const pal = usePalette('default') const pal = usePalette('default')
const store = useStores() const store = useStores()
@ -126,8 +129,7 @@ export const CreateAccount = observer(
</ScrollView> </ScrollView>
</LoggedOutLayout> </LoggedOutLayout>
) )
}, })
)
const styles = StyleSheet.create({ const styles = StyleSheet.create({
stepContainer: { stepContainer: {

View File

@ -20,7 +20,11 @@ import {LOGIN_INCLUDE_DEV_SERVERS} from 'lib/build-flags'
* @field Bluesky (default) * @field Bluesky (default)
* @field Other (staging, local dev, your own PDS, etc.) * @field Other (staging, local dev, your own PDS, etc.)
*/ */
export const Step1 = observer(({model}: {model: CreateAccountModel}) => { export const Step1 = observer(function Step1Impl({
model,
}: {
model: CreateAccountModel
}) {
const pal = usePalette('default') const pal = usePalette('default')
const [isDefaultSelected, setIsDefaultSelected] = React.useState(true) const [isDefaultSelected, setIsDefaultSelected] = React.useState(true)

View File

@ -21,7 +21,11 @@ import {useStores} from 'state/index'
* @field Birth date * @field Birth date
* @readonly Terms of service & privacy policy * @readonly Terms of service & privacy policy
*/ */
export const Step2 = observer(({model}: {model: CreateAccountModel}) => { export const Step2 = observer(function Step2Impl({
model,
}: {
model: CreateAccountModel
}) {
const pal = usePalette('default') const pal = usePalette('default')
const store = useStores() const store = useStores()

View File

@ -13,7 +13,11 @@ import {ErrorMessage} from 'view/com/util/error/ErrorMessage'
/** STEP 3: Your user handle /** STEP 3: Your user handle
* @field User handle * @field User handle
*/ */
export const Step3 = observer(({model}: {model: CreateAccountModel}) => { export const Step3 = observer(function Step3Impl({
model,
}: {
model: CreateAccountModel
}) {
const pal = usePalette('default') const pal = usePalette('default')
return ( return (
<View> <View>

View File

@ -15,7 +15,9 @@ import {RECOMMENDED_FEEDS} from 'lib/constants'
type Props = { type Props = {
next: () => void next: () => void
} }
export const RecommendedFeeds = observer(({next}: Props) => { export const RecommendedFeeds = observer(function RecommendedFeedsImpl({
next,
}: Props) {
const pal = usePalette('default') const pal = usePalette('default')
const {isTabletOrMobile} = useWebMediaQueries() const {isTabletOrMobile} = useWebMediaQueries()

View File

@ -13,8 +13,13 @@ import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {makeRecordUri} from 'lib/strings/url-helpers' import {makeRecordUri} from 'lib/strings/url-helpers'
import {sanitizeHandle} from 'lib/strings/handles' import {sanitizeHandle} from 'lib/strings/handles'
export const RecommendedFeedsItem = observer( export const RecommendedFeedsItem = observer(function RecommendedFeedsItemImpl({
({did, rkey}: {did: string; rkey: string}) => { did,
rkey,
}: {
did: string
rkey: string
}) {
const {isMobile} = useWebMediaQueries() const {isMobile} = useWebMediaQueries()
const pal = usePalette('default') const pal = usePalette('default')
const uri = makeRecordUri(did, 'app.bsky.feed.generator', rkey) const uri = makeRecordUri(did, 'app.bsky.feed.generator', rkey)
@ -138,5 +143,4 @@ export const RecommendedFeedsItem = observer(
</View> </View>
</View> </View>
) )
}, })
)

View File

@ -14,7 +14,9 @@ type Props = {
skip: () => void skip: () => void
} }
export const WelcomeDesktop = observer(({next}: Props) => { export const WelcomeDesktop = observer(function WelcomeDesktopImpl({
next,
}: Props) {
const pal = usePalette('default') const pal = usePalette('default')
const horizontal = useMediaQuery({minWidth: 1300}) const horizontal = useMediaQuery({minWidth: 1300})
const title = ( const title = (

View File

@ -13,7 +13,10 @@ type Props = {
skip: () => void skip: () => void
} }
export const WelcomeMobile = observer(({next, skip}: Props) => { export const WelcomeMobile = observer(function WelcomeMobileImpl({
next,
skip,
}: Props) {
const pal = usePalette('default') const pal = usePalette('default')
return ( return (

View File

@ -17,7 +17,7 @@ import {STATUS_PAGE_URL} from 'lib/constants'
export const withAuthRequired = <P extends object>( export const withAuthRequired = <P extends object>(
Component: React.ComponentType<P>, Component: React.ComponentType<P>,
): React.FC<P> => ): React.FC<P> =>
observer((props: P) => { observer(function AuthRequired(props: P) {
const store = useStores() const store = useStores()
if (store.session.isResumingSession) { if (store.session.isResumingSession) {
return <Loading /> return <Loading />

View File

@ -16,7 +16,7 @@ interface Props {
gallery: GalleryModel gallery: GalleryModel
} }
export const Gallery = observer(function ({gallery}: Props) { export const Gallery = observer(function GalleryImpl({gallery}: Props) {
const store = useStores() const store = useStores()
const pal = usePalette('default') const pal = usePalette('default')
const {isMobile} = useWebMediaQueries() const {isMobile} = useWebMediaQueries()

View File

@ -8,14 +8,13 @@ import {Text} from 'view/com/util/text/Text'
import {UserAvatar} from 'view/com/util/UserAvatar' import {UserAvatar} from 'view/com/util/UserAvatar'
import {useGrapheme} from '../hooks/useGrapheme' import {useGrapheme} from '../hooks/useGrapheme'
export const Autocomplete = observer( export const Autocomplete = observer(function AutocompleteImpl({
({
view, view,
onSelect, onSelect,
}: { }: {
view: UserAutocompleteModel view: UserAutocompleteModel
onSelect: (item: string) => void onSelect: (item: string) => void
}) => { }) {
const pal = usePalette('default') const pal = usePalette('default')
const positionInterp = useAnimatedValue(0) const positionInterp = useAnimatedValue(0)
const {getGraphemeString} = useGrapheme() const {getGraphemeString} = useGrapheme()
@ -90,8 +89,7 @@ export const Autocomplete = observer(
) : null} ) : null}
</Animated.View> </Animated.View>
) )
}, })
)
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {

View File

@ -15,20 +15,19 @@ import {AtUri} from '@atproto/api'
import * as Toast from 'view/com/util/Toast' import * as Toast from 'view/com/util/Toast'
import {sanitizeHandle} from 'lib/strings/handles' import {sanitizeHandle} from 'lib/strings/handles'
export const CustomFeed = observer( export const CustomFeed = observer(function CustomFeedImpl({
({
item, item,
style, style,
showSaveBtn = false, showSaveBtn = false,
showDescription = false, showDescription = false,
showLikes = false, showLikes = false,
}: { }: {
item: CustomFeedModel item: CustomFeedModel
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
showSaveBtn?: boolean showSaveBtn?: boolean
showDescription?: boolean showDescription?: boolean
showLikes?: boolean showLikes?: boolean
}) => { }) {
const store = useStores() const store = useStores()
const pal = usePalette('default') const pal = usePalette('default')
const navigation = useNavigation<NavigationProp>() const navigation = useNavigation<NavigationProp>()
@ -127,8 +126,7 @@ export const CustomFeed = observer(
) : null} ) : null}
</Pressable> </Pressable>
) )
}, })
)
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {

View File

@ -35,8 +35,7 @@ const EMPTY_ITEM = {_reactKey: '__empty__'}
const ERROR_ITEM = {_reactKey: '__error__'} const ERROR_ITEM = {_reactKey: '__error__'}
const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'} const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'}
export const ListItems = observer( export const ListItems = observer(function ListItemsImpl({
({
list, list,
style, style,
scrollElRef, scrollElRef,
@ -49,7 +48,7 @@ export const ListItems = observer(
renderEmptyState, renderEmptyState,
testID, testID,
headerOffset = 0, headerOffset = 0,
}: { }: {
list: ListModel list: ListModel
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
scrollElRef?: MutableRefObject<FlatList<any> | null> scrollElRef?: MutableRefObject<FlatList<any> | null>
@ -62,7 +61,7 @@ export const ListItems = observer(
renderEmptyState?: () => JSX.Element renderEmptyState?: () => JSX.Element
testID?: string testID?: string
headerOffset?: number headerOffset?: number
}) => { }) {
const pal = usePalette('default') const pal = usePalette('default')
const store = useStores() const store = useStores()
const {track} = useAnalytics() const {track} = useAnalytics()
@ -260,11 +259,9 @@ export const ListItems = observer(
)} )}
</View> </View>
) )
}, })
)
const ListHeader = observer( const ListHeader = observer(function ListHeaderImpl({
({
list, list,
isOwner, isOwner,
onToggleSubscribed, onToggleSubscribed,
@ -272,7 +269,7 @@ const ListHeader = observer(
onPressDeleteList, onPressDeleteList,
onPressShareList, onPressShareList,
onPressReportList, onPressReportList,
}: { }: {
list: AppBskyGraphDefs.ListView list: AppBskyGraphDefs.ListView
isOwner: boolean isOwner: boolean
onToggleSubscribed: () => void onToggleSubscribed: () => void
@ -280,7 +277,7 @@ const ListHeader = observer(
onPressDeleteList: () => void onPressDeleteList: () => void
onPressShareList: () => void onPressShareList: () => void
onPressReportList: () => void onPressReportList: () => void
}) => { }) {
const pal = usePalette('default') const pal = usePalette('default')
const store = useStores() const store = useStores()
const {isDesktop} = useWebMediaQueries() const {isDesktop} = useWebMediaQueries()
@ -337,8 +334,7 @@ const ListHeader = observer(
</View> </View>
<View <View
style={{flexDirection: 'row', paddingHorizontal: isDesktop ? 16 : 6}}> style={{flexDirection: 'row', paddingHorizontal: isDesktop ? 16 : 6}}>
<View <View style={[styles.fakeSelectorItem, {borderColor: pal.colors.link}]}>
style={[styles.fakeSelectorItem, {borderColor: pal.colors.link}]}>
<Text type="md-medium" style={[pal.text]}> <Text type="md-medium" style={[pal.text]}>
Muted users Muted users
</Text> </Text>
@ -346,8 +342,7 @@ const ListHeader = observer(
</View> </View>
</> </>
) )
}, })
)
const styles = StyleSheet.create({ const styles = StyleSheet.create({
header: { header: {

View File

@ -30,8 +30,7 @@ const EMPTY_ITEM = {_reactKey: '__empty__'}
const ERROR_ITEM = {_reactKey: '__error__'} const ERROR_ITEM = {_reactKey: '__error__'}
const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'} const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'}
export const ListsList = observer( export const ListsList = observer(function ListsListImpl({
({
listsList, listsList,
showAddBtns, showAddBtns,
style, style,
@ -42,7 +41,7 @@ export const ListsList = observer(
renderEmptyState, renderEmptyState,
testID, testID,
headerOffset = 0, headerOffset = 0,
}: { }: {
listsList: ListsListModel listsList: ListsListModel
showAddBtns?: boolean showAddBtns?: boolean
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
@ -53,7 +52,7 @@ export const ListsList = observer(
renderEmptyState?: () => JSX.Element renderEmptyState?: () => JSX.Element
testID?: string testID?: string
headerOffset?: number headerOffset?: number
}) => { }) {
const pal = usePalette('default') const pal = usePalette('default')
const {track} = useAnalytics() const {track} = useAnalytics()
const [isRefreshing, setIsRefreshing] = React.useState(false) const [isRefreshing, setIsRefreshing] = React.useState(false)
@ -195,8 +194,7 @@ export const ListsList = observer(
)} )}
</View> </View>
) )
}, })
)
function CreateNewItem({onPress}: {onPress: () => void}) { function CreateNewItem({onPress}: {onPress: () => void}) {
const pal = usePalette('default') const pal = usePalette('default')

View File

@ -17,7 +17,8 @@ import * as Toast from '../util/Toast'
export const snapPoints = ['90%'] export const snapPoints = ['90%']
export const Component = observer(({}: {}) => { export const Component = observer(
function ContentFilteringSettingsImpl({}: {}) {
const store = useStores() const store = useStores()
const {isMobile} = useWebMediaQueries() const {isMobile} = useWebMediaQueries()
const pal = usePalette('default') const pal = usePalette('default')
@ -35,7 +36,9 @@ export const Component = observer(({}: {}) => {
!store.preferences.adultContentEnabled, !store.preferences.adultContentEnabled,
) )
} catch (e) { } catch (e) {
Toast.show('There was an issue syncing your preferences with the server') Toast.show(
'There was an issue syncing your preferences with the server',
)
store.log.error('Failed to update preferences with server', {e}) store.log.error('Failed to update preferences with server', {e})
} }
}, [store]) }, [store])
@ -115,17 +118,17 @@ export const Component = observer(({}: {}) => {
</View> </View>
</View> </View>
) )
}) },
)
// TODO: Refactor this component to pass labels down to each tab // TODO: Refactor this component to pass labels down to each tab
const ContentLabelPref = observer( const ContentLabelPref = observer(function ContentLabelPrefImpl({
({
group, group,
disabled, disabled,
}: { }: {
group: keyof typeof CONFIGURABLE_LABEL_GROUPS group: keyof typeof CONFIGURABLE_LABEL_GROUPS
disabled?: boolean disabled?: boolean
}) => { }) {
const store = useStores() const store = useStores()
const pal = usePalette('default') const pal = usePalette('default')
@ -168,8 +171,7 @@ const ContentLabelPref = observer(
)} )}
</View> </View>
) )
}, })
)
interface SelectGroupProps { interface SelectGroupProps {
current: LabelPreference current: LabelPreference

View File

@ -46,7 +46,10 @@ interface Props {
gallery: GalleryModel gallery: GalleryModel
} }
export const Component = observer(function ({image, gallery}: Props) { export const Component = observer(function EditImageImpl({
image,
gallery,
}: Props) {
const pal = usePalette('default') const pal = usePalette('default')
const theme = useTheme() const theme = useTheme()
const store = useStores() const store = useStores()

View File

@ -79,8 +79,15 @@ export function Component({}: {}) {
) )
} }
const InviteCode = observer( const InviteCode = observer(function InviteCodeImpl({
({testID, code, used}: {testID: string; code: string; used?: boolean}) => { testID,
code,
used,
}: {
testID: string
code: string
used?: boolean
}) {
const pal = usePalette('default') const pal = usePalette('default')
const store = useStores() const store = useStores()
const {invitesAvailable} = store.me const {invitesAvailable} = store.me
@ -121,8 +128,7 @@ const InviteCode = observer(
)} )}
</TouchableOpacity> </TouchableOpacity>
) )
}, })
)
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {

View File

@ -24,23 +24,22 @@ import isEqual from 'lodash.isequal'
export const snapPoints = ['fullscreen'] export const snapPoints = ['fullscreen']
export const Component = observer( export const Component = observer(function ListAddRemoveUserImpl({
({
subject, subject,
displayName, displayName,
onUpdate, onUpdate,
}: { }: {
subject: string subject: string
displayName: string displayName: string
onUpdate?: () => void onUpdate?: () => void
}) => { }) {
const store = useStores() const store = useStores()
const pal = usePalette('default') const pal = usePalette('default')
const palPrimary = usePalette('primary') const palPrimary = usePalette('primary')
const palInverted = usePalette('inverted') const palInverted = usePalette('inverted')
const [originalSelections, setOriginalSelections] = React.useState< const [originalSelections, setOriginalSelections] = React.useState<string[]>(
string[] [],
>([]) )
const [selected, setSelected] = React.useState<string[]>([]) const [selected, setSelected] = React.useState<string[]>([])
const [membershipsLoaded, setMembershipsLoaded] = React.useState(false) const [membershipsLoaded, setMembershipsLoaded] = React.useState(false)
@ -132,8 +131,7 @@ export const Component = observer(
{sanitizeDisplayName(list.name)} {sanitizeDisplayName(list.name)}
</Text> </Text>
<Text type="md" style={[pal.textLight]} numberOfLines={1}> <Text type="md" style={[pal.textLight]} numberOfLines={1}>
{list.purpose === 'app.bsky.graph.defs#modlist' && 'Mute list'}{' '} {list.purpose === 'app.bsky.graph.defs#modlist' && 'Mute list'} by{' '}
by{' '}
{list.creator.did === store.me.did {list.creator.did === store.me.did
? 'you' ? 'you'
: sanitizeHandle(list.creator.handle, '@')} : sanitizeHandle(list.creator.handle, '@')}
@ -226,8 +224,7 @@ export const Component = observer(
</View> </View>
</View> </View>
) )
}, })
)
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {

View File

@ -14,7 +14,11 @@ import {s} from 'lib/styles'
export const snapPoints = [520, '100%'] export const snapPoints = [520, '100%']
export const Component = observer(({did}: {did: string}) => { export const Component = observer(function ProfilePreviewImpl({
did,
}: {
did: string
}) {
const store = useStores() const store = useStores()
const pal = usePalette('default') const pal = usePalette('default')
const [model] = useState(new ProfileModel(store, {actor: did})) const [model] = useState(new ProfileModel(store, {actor: did}))

View File

@ -5,18 +5,17 @@ import {observer} from 'mobx-react-lite'
import {ToggleButton} from 'view/com/util/forms/ToggleButton' import {ToggleButton} from 'view/com/util/forms/ToggleButton'
import {useStores} from 'state/index' import {useStores} from 'state/index'
export const LanguageToggle = observer( export const LanguageToggle = observer(function LanguageToggleImpl({
({
code2, code2,
name, name,
onPress, onPress,
langType, langType,
}: { }: {
code2: string code2: string
name: string name: string
onPress: () => void onPress: () => void
langType: 'contentLanguages' | 'postLanguages' langType: 'contentLanguages' | 'postLanguages'
}) => { }) {
const pal = usePalette('default') const pal = usePalette('default')
const store = useStores() const store = useStores()
@ -40,8 +39,7 @@ export const LanguageToggle = observer(
style={[pal.border, styles.languageToggle, isDisabled && styles.dimmed]} style={[pal.border, styles.languageToggle, isDisabled && styles.dimmed]}
/> />
) )
}, })
)
const styles = StyleSheet.create({ const styles = StyleSheet.create({
languageToggle: { languageToggle: {

View File

@ -13,7 +13,7 @@ import {ToggleButton} from 'view/com/util/forms/ToggleButton'
export const snapPoints = ['100%'] export const snapPoints = ['100%']
export const Component = observer(() => { export const Component = observer(function PostLanguagesSettingsImpl() {
const store = useStores() const store = useStores()
const pal = usePalette('default') const pal = usePalette('default')
const {isMobile} = useWebMediaQueries() const {isMobile} = useWebMediaQueries()

View File

@ -52,7 +52,7 @@ interface Author {
moderation: ProfileModeration moderation: ProfileModeration
} }
export const FeedItem = observer(function ({ export const FeedItem = observer(function FeedItemImpl({
item, item,
}: { }: {
item: NotificationsFeedItemModel item: NotificationsFeedItemModel

View File

@ -18,7 +18,7 @@ import {s} from 'lib/styles'
import {sanitizeDisplayName} from 'lib/strings/display-names' import {sanitizeDisplayName} from 'lib/strings/display-names'
import {makeProfileLink} from 'lib/routes/links' import {makeProfileLink} from 'lib/routes/links'
export const InvitedUsers = observer(() => { export const InvitedUsers = observer(function InvitedUsersImpl() {
const store = useStores() const store = useStores()
return ( return (
<CenteredView> <CenteredView>

View File

@ -9,23 +9,20 @@ import {useAnimatedValue} from 'lib/hooks/useAnimatedValue'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {FeedsTabBar as FeedsTabBarMobile} from './FeedsTabBarMobile' import {FeedsTabBar as FeedsTabBarMobile} from './FeedsTabBarMobile'
export const FeedsTabBar = observer( export const FeedsTabBar = observer(function FeedsTabBarImpl(
(
props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void}, props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void},
) => { ) {
const {isMobile} = useWebMediaQueries() const {isMobile} = useWebMediaQueries()
if (isMobile) { if (isMobile) {
return <FeedsTabBarMobile {...props} /> return <FeedsTabBarMobile {...props} />
} else { } else {
return <FeedsTabBarDesktop {...props} /> return <FeedsTabBarDesktop {...props} />
} }
}, })
)
const FeedsTabBarDesktop = observer( const FeedsTabBarDesktop = observer(function FeedsTabBarDesktopImpl(
(
props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void}, props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void},
) => { ) {
const store = useStores() const store = useStores()
const items = useMemo( const items = useMemo(
() => ['Following', ...store.me.savedFeeds.pinnedFeedNames], () => ['Following', ...store.me.savedFeeds.pinnedFeedNames],
@ -60,8 +57,7 @@ const FeedsTabBarDesktop = observer(
/> />
</Animated.View> </Animated.View>
) )
}, })
)
const styles = StyleSheet.create({ const styles = StyleSheet.create({
tabBar: { tabBar: {

View File

@ -14,10 +14,9 @@ import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {s} from 'lib/styles' import {s} from 'lib/styles'
import {HITSLOP_10} from 'lib/constants' import {HITSLOP_10} from 'lib/constants'
export const FeedsTabBar = observer( export const FeedsTabBar = observer(function FeedsTabBarImpl(
(
props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void}, props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void},
) => { ) {
const store = useStores() const store = useStores()
const pal = usePalette('default') const pal = usePalette('default')
const interp = useAnimatedValue(0) const interp = useAnimatedValue(0)
@ -85,8 +84,7 @@ export const FeedsTabBar = observer(
/> />
</Animated.View> </Animated.View>
) )
}, })
)
const styles = StyleSheet.create({ const styles = StyleSheet.create({
tabBar: { tabBar: {

View File

@ -8,7 +8,11 @@ import {ProfileCardWithFollowBtn} from '../profile/ProfileCard'
import {useStores} from 'state/index' import {useStores} from 'state/index'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
export const PostLikedBy = observer(function ({uri}: {uri: string}) { export const PostLikedBy = observer(function PostLikedByImpl({
uri,
}: {
uri: string
}) {
const pal = usePalette('default') const pal = usePalette('default')
const store = useStores() const store = useStores()
const view = React.useMemo(() => new LikesModel(store, {uri}), [store, uri]) const view = React.useMemo(() => new LikesModel(store, {uri}), [store, uri])
@ -64,6 +68,8 @@ export const PostLikedBy = observer(function ({uri}: {uri: string}) {
onEndReached={onEndReached} onEndReached={onEndReached}
renderItem={renderItem} renderItem={renderItem}
initialNumToRender={15} initialNumToRender={15}
// FIXME(dan)
// eslint-disable-next-line react/no-unstable-nested-components
ListFooterComponent={() => ( ListFooterComponent={() => (
<View style={styles.footer}> <View style={styles.footer}>
{view.isLoading && <ActivityIndicator />} {view.isLoading && <ActivityIndicator />}

View File

@ -8,7 +8,7 @@ import {ErrorMessage} from '../util/error/ErrorMessage'
import {useStores} from 'state/index' import {useStores} from 'state/index'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
export const PostRepostedBy = observer(function PostRepostedBy({ export const PostRepostedBy = observer(function PostRepostedByImpl({
uri, uri,
}: { }: {
uri: string uri: string
@ -75,6 +75,8 @@ export const PostRepostedBy = observer(function PostRepostedBy({
onEndReached={onEndReached} onEndReached={onEndReached}
renderItem={renderItem} renderItem={renderItem}
initialNumToRender={15} initialNumToRender={15}
// FIXME(dan)
// eslint-disable-next-line react/no-unstable-nested-components
ListFooterComponent={() => ( ListFooterComponent={() => (
<View style={styles.footer}> <View style={styles.footer}>
{view.isLoading && <ActivityIndicator />} {view.isLoading && <ActivityIndicator />}

View File

@ -31,7 +31,7 @@ import {usePalette} from 'lib/hooks/usePalette'
import {getTranslatorLink, isPostInLanguage} from '../../../locale/helpers' import {getTranslatorLink, isPostInLanguage} from '../../../locale/helpers'
import {makeProfileLink} from 'lib/routes/links' import {makeProfileLink} from 'lib/routes/links'
export const Post = observer(function Post({ export const Post = observer(function PostImpl({
view, view,
showReplyLine, showReplyLine,
hideError, hideError,
@ -88,20 +88,19 @@ export const Post = observer(function Post({
) )
}) })
const PostLoaded = observer( const PostLoaded = observer(function PostLoadedImpl({
({
item, item,
record, record,
setDeleted, setDeleted,
showReplyLine, showReplyLine,
style, style,
}: { }: {
item: PostThreadItemModel item: PostThreadItemModel
record: FeedPost.Record record: FeedPost.Record
setDeleted: (v: boolean) => void setDeleted: (v: boolean) => void
showReplyLine?: boolean showReplyLine?: boolean
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
}) => { }) {
const pal = usePalette('default') const pal = usePalette('default')
const store = useStores() const store = useStores()
@ -294,8 +293,7 @@ const PostLoaded = observer(
</View> </View>
</Link> </Link>
) )
}, })
)
const styles = StyleSheet.create({ const styles = StyleSheet.create({
outer: { outer: {

View File

@ -30,7 +30,7 @@ import {getTranslatorLink, isPostInLanguage} from '../../../locale/helpers'
import {makeProfileLink} from 'lib/routes/links' import {makeProfileLink} from 'lib/routes/links'
import {isEmbedByEmbedder} from 'lib/embeds' import {isEmbedByEmbedder} from 'lib/embeds'
export const FeedItem = observer(function ({ export const FeedItem = observer(function FeedItemImpl({
item, item,
isThreadChild, isThreadChild,
isThreadLastChild, isThreadLastChild,

View File

@ -10,14 +10,13 @@ import {FeedItem} from './FeedItem'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {makeProfileLink} from 'lib/routes/links' import {makeProfileLink} from 'lib/routes/links'
export const FeedSlice = observer( export const FeedSlice = observer(function FeedSliceImpl({
({
slice, slice,
ignoreFilterFor, ignoreFilterFor,
}: { }: {
slice: PostsFeedSliceModel slice: PostsFeedSliceModel
ignoreFilterFor?: string ignoreFilterFor?: string
}) => { }) {
if (slice.shouldFilter(ignoreFilterFor)) { if (slice.shouldFilter(ignoreFilterFor)) {
return null return null
} }
@ -65,8 +64,7 @@ export const FeedSlice = observer(
))} ))}
</> </>
) )
}, })
)
function ViewFullThread({slice}: {slice: PostsFeedSliceModel}) { function ViewFullThread({slice}: {slice: PostsFeedSliceModel}) {
const pal = usePalette('default') const pal = usePalette('default')

View File

@ -6,18 +6,17 @@ import {useStores} from 'state/index'
import * as Toast from '../util/Toast' import * as Toast from '../util/Toast'
import {FollowState} from 'state/models/cache/my-follows' import {FollowState} from 'state/models/cache/my-follows'
export const FollowButton = observer( export const FollowButton = observer(function FollowButtonImpl({
({
unfollowedType = 'inverted', unfollowedType = 'inverted',
followedType = 'default', followedType = 'default',
did, did,
onToggleFollow, onToggleFollow,
}: { }: {
unfollowedType?: ButtonType unfollowedType?: ButtonType
followedType?: ButtonType followedType?: ButtonType
did: string did: string
onToggleFollow?: (v: boolean) => void onToggleFollow?: (v: boolean) => void
}) => { }) {
const store = useStores() const store = useStores()
const followState = store.me.follows.getFollowState(did) const followState = store.me.follows.getFollowState(did)
@ -57,5 +56,4 @@ export const FollowButton = observer(
label={followState === FollowState.Following ? 'Unfollow' : 'Follow'} label={followState === FollowState.Following ? 'Unfollow' : 'Follow'}
/> />
) )
}, })
)

View File

@ -22,31 +22,25 @@ import {
getModerationCauseKey, getModerationCauseKey,
} from 'lib/moderation' } from 'lib/moderation'
export const ProfileCard = observer( export const ProfileCard = observer(function ProfileCardImpl({
({
testID, testID,
profile, profile,
noBg, noBg,
noBorder, noBorder,
followers, followers,
renderButton, renderButton,
}: { }: {
testID?: string testID?: string
profile: AppBskyActorDefs.ProfileViewBasic profile: AppBskyActorDefs.ProfileViewBasic
noBg?: boolean noBg?: boolean
noBorder?: boolean noBorder?: boolean
followers?: AppBskyActorDefs.ProfileView[] | undefined followers?: AppBskyActorDefs.ProfileView[] | undefined
renderButton?: ( renderButton?: (profile: AppBskyActorDefs.ProfileViewBasic) => React.ReactNode
profile: AppBskyActorDefs.ProfileViewBasic, }) {
) => React.ReactNode
}) => {
const store = useStores() const store = useStores()
const pal = usePalette('default') const pal = usePalette('default')
const moderation = moderateProfile( const moderation = moderateProfile(profile, store.preferences.moderationOpts)
profile,
store.preferences.moderationOpts,
)
return ( return (
<Link <Link
@ -103,8 +97,7 @@ export const ProfileCard = observer(
<FollowersList followers={followers} /> <FollowersList followers={followers} />
</Link> </Link>
) )
}, })
)
function ProfileCardPills({ function ProfileCardPills({
followedBy, followedBy,
@ -146,8 +139,11 @@ function ProfileCardPills({
) )
} }
const FollowersList = observer( const FollowersList = observer(function FollowersListImpl({
({followers}: {followers?: AppBskyActorDefs.ProfileView[] | undefined}) => { followers,
}: {
followers?: AppBskyActorDefs.ProfileView[] | undefined
}) {
const store = useStores() const store = useStores()
const pal = usePalette('default') const pal = usePalette('default')
if (!followers?.length) { if (!followers?.length) {
@ -180,11 +176,10 @@ const FollowersList = observer(
))} ))}
</View> </View>
) )
}, })
)
export const ProfileCardWithFollowBtn = observer( export const ProfileCardWithFollowBtn = observer(
({ function ProfileCardWithFollowBtnImpl({
profile, profile,
noBg, noBg,
noBorder, noBorder,
@ -194,7 +189,7 @@ export const ProfileCardWithFollowBtn = observer(
noBg?: boolean noBg?: boolean
noBorder?: boolean noBorder?: boolean
followers?: AppBskyActorDefs.ProfileView[] | undefined followers?: AppBskyActorDefs.ProfileView[] | undefined
}) => { }) {
const store = useStores() const store = useStores()
const isMe = store.me.did === profile.did const isMe = store.me.did === profile.did

View File

@ -78,6 +78,8 @@ export const ProfileFollowers = observer(function ProfileFollowers({
onEndReached={onEndReached} onEndReached={onEndReached}
renderItem={renderItem} renderItem={renderItem}
initialNumToRender={15} initialNumToRender={15}
// FIXME(dan)
// eslint-disable-next-line react/no-unstable-nested-components
ListFooterComponent={() => ( ListFooterComponent={() => (
<View style={styles.footer}> <View style={styles.footer}>
{view.isLoading && <ActivityIndicator />} {view.isLoading && <ActivityIndicator />}

View File

@ -75,6 +75,8 @@ export const ProfileFollows = observer(function ProfileFollows({
onEndReached={onEndReached} onEndReached={onEndReached}
renderItem={renderItem} renderItem={renderItem}
initialNumToRender={15} initialNumToRender={15}
// FIXME(dan)
// eslint-disable-next-line react/no-unstable-nested-components
ListFooterComponent={() => ( ListFooterComponent={() => (
<View style={styles.footer}> <View style={styles.footer}>
{view.isLoading && <ActivityIndicator />} {view.isLoading && <ActivityIndicator />}

View File

@ -45,8 +45,11 @@ interface Props {
hideBackButton?: boolean hideBackButton?: boolean
} }
export const ProfileHeader = observer( export const ProfileHeader = observer(function ProfileHeaderImpl({
({view, onRefreshAll, hideBackButton = false}: Props) => { view,
onRefreshAll,
hideBackButton = false,
}: Props) {
const pal = usePalette('default') const pal = usePalette('default')
// loading // loading
@ -56,11 +59,7 @@ export const ProfileHeader = observer(
<View style={pal.view}> <View style={pal.view}>
<LoadingPlaceholder width="100%" height={120} /> <LoadingPlaceholder width="100%" height={120} />
<View <View
style={[ style={[pal.view, {borderColor: pal.colors.background}, styles.avi]}>
pal.view,
{borderColor: pal.colors.background},
styles.avi,
]}>
<LoadingPlaceholder width={80} height={80} style={styles.br40} /> <LoadingPlaceholder width={80} height={80} style={styles.br40} />
</View> </View>
<View style={styles.content}> <View style={styles.content}>
@ -98,11 +97,13 @@ export const ProfileHeader = observer(
hideBackButton={hideBackButton} hideBackButton={hideBackButton}
/> />
) )
}, })
)
const ProfileHeaderLoaded = observer( const ProfileHeaderLoaded = observer(function ProfileHeaderLoadedImpl({
({view, onRefreshAll, hideBackButton = false}: Props) => { view,
onRefreshAll,
hideBackButton = false,
}: Props) {
const pal = usePalette('default') const pal = usePalette('default')
const palInverted = usePalette('inverted') const palInverted = usePalette('inverted')
const store = useStores() const store = useStores()
@ -421,11 +422,7 @@ const ProfileHeaderLoaded = observer(
testID="profileHeaderDropdownBtn" testID="profileHeaderDropdownBtn"
items={dropdownItems}> items={dropdownItems}>
<View style={[styles.btn, styles.secondaryBtn, pal.btn]}> <View style={[styles.btn, styles.secondaryBtn, pal.btn]}>
<FontAwesomeIcon <FontAwesomeIcon icon="ellipsis" size={20} style={[pal.text]} />
icon="ellipsis"
size={20}
style={[pal.text]}
/>
</View> </View>
</NativeDropdown> </NativeDropdown>
) : undefined} ) : undefined}
@ -533,11 +530,7 @@ const ProfileHeaderLoaded = observer(
accessibilityLabel={`View ${view.handle}'s avatar`} accessibilityLabel={`View ${view.handle}'s avatar`}
accessibilityHint=""> accessibilityHint="">
<View <View
style={[ style={[pal.view, {borderColor: pal.colors.background}, styles.avi]}>
pal.view,
{borderColor: pal.colors.background},
styles.avi,
]}>
<UserAvatar <UserAvatar
size={80} size={80}
avatar={view.avatar} avatar={view.avatar}
@ -547,8 +540,7 @@ const ProfileHeaderLoaded = observer(
</TouchableWithoutFeedback> </TouchableWithoutFeedback>
</View> </View>
) )
}, })
)
const styles = StyleSheet.create({ const styles = StyleSheet.create({
banner: { banner: {

View File

@ -18,7 +18,11 @@ import {s} from 'lib/styles'
const SECTIONS = ['Posts', 'Users'] const SECTIONS = ['Posts', 'Users']
export const SearchResults = observer(({model}: {model: SearchUIModel}) => { export const SearchResults = observer(function SearchResultsImpl({
model,
}: {
model: SearchUIModel
}) {
const pal = usePalette('default') const pal = usePalette('default')
const {isMobile} = useWebMediaQueries() const {isMobile} = useWebMediaQueries()
@ -56,7 +60,11 @@ export const SearchResults = observer(({model}: {model: SearchUIModel}) => {
) )
}) })
const PostResults = observer(({model}: {model: SearchUIModel}) => { const PostResults = observer(function PostResultsImpl({
model,
}: {
model: SearchUIModel
}) {
const pal = usePalette('default') const pal = usePalette('default')
if (model.isPostsLoading) { if (model.isPostsLoading) {
return ( return (
@ -88,7 +96,11 @@ const PostResults = observer(({model}: {model: SearchUIModel}) => {
) )
}) })
const Profiles = observer(({model}: {model: SearchUIModel}) => { const Profiles = observer(function ProfilesImpl({
model,
}: {
model: SearchUIModel
}) {
const pal = usePalette('default') const pal = usePalette('default')
if (model.isProfilesLoading) { if (model.isProfilesLoading) {
return ( return (

View File

@ -38,6 +38,9 @@ interface ProfileView {
} }
type Item = Heading | RefWrapper | SuggestWrapper | ProfileView type Item = Heading | RefWrapper | SuggestWrapper | ProfileView
// FIXME(dan): Figure out why the false positives
/* eslint-disable react/prop-types */
export const Suggestions = observer( export const Suggestions = observer(
forwardRef(function SuggestionsImpl( forwardRef(function SuggestionsImpl(
{ {

View File

@ -25,7 +25,7 @@ interface PostMetaOpts {
timestamp: string timestamp: string
} }
export const PostMeta = observer(function (opts: PostMetaOpts) { export const PostMeta = observer(function PostMetaImpl(opts: PostMetaOpts) {
const pal = usePalette('default') const pal = usePalette('default')
const displayName = opts.author.displayName || opts.author.handle const displayName = opts.author.displayName || opts.author.handle
const handle = opts.author.handle const handle = opts.author.handle

View File

@ -3,6 +3,9 @@ import {observer} from 'mobx-react-lite'
import {ago} from 'lib/strings/time' import {ago} from 'lib/strings/time'
import {useStores} from 'state/index' import {useStores} from 'state/index'
// FIXME(dan): Figure out why the false positives
/* eslint-disable react/prop-types */
export const TimeElapsed = observer(function TimeElapsed({ export const TimeElapsed = observer(function TimeElapsed({
timestamp, timestamp,
children, children,

View File

@ -14,7 +14,7 @@ import {NavigationProp} from 'lib/routes/types'
const BACK_HITSLOP = {left: 20, top: 20, right: 50, bottom: 20} const BACK_HITSLOP = {left: 20, top: 20, right: 50, bottom: 20}
export const ViewHeader = observer(function ({ export const ViewHeader = observer(function ViewHeaderImpl({
title, title,
canGoBack, canGoBack,
showBackButton = true, showBackButton = true,
@ -140,16 +140,15 @@ function DesktopWebHeader({
) )
} }
const Container = observer( const Container = observer(function ContainerImpl({
({
children, children,
hideOnScroll, hideOnScroll,
showBorder, showBorder,
}: { }: {
children: React.ReactNode children: React.ReactNode
hideOnScroll: boolean hideOnScroll: boolean
showBorder?: boolean showBorder?: boolean
}) => { }) {
const store = useStores() const store = useStores()
const pal = usePalette('default') const pal = usePalette('default')
const interp = useAnimatedValue(0) const interp = useAnimatedValue(0)
@ -202,8 +201,7 @@ const Container = observer(
{children} {children}
</Animated.View> </Animated.View>
) )
}, })
)
const styles = StyleSheet.create({ const styles = StyleSheet.create({
header: { header: {

View File

@ -14,7 +14,11 @@ export interface FABProps
icon: JSX.Element icon: JSX.Element
} }
export const FABInner = observer(({testID, icon, ...props}: FABProps) => { export const FABInner = observer(function FABInnerImpl({
testID,
icon,
...props
}: FABProps) {
const {isTablet} = useWebMediaQueries() const {isTablet} = useWebMediaQueries()
const store = useStores() const store = useStores()
const interp = useAnimatedValue(0) const interp = useAnimatedValue(0)

View File

@ -9,17 +9,16 @@ import {usePalette} from 'lib/hooks/usePalette'
import {colors} from 'lib/styles' import {colors} from 'lib/styles'
import {HITSLOP_20} from 'lib/constants' import {HITSLOP_20} from 'lib/constants'
export const LoadLatestBtn = observer( export const LoadLatestBtn = observer(function LoadLatestBtnImpl({
({
onPress, onPress,
label, label,
showIndicator, showIndicator,
}: { }: {
onPress: () => void onPress: () => void
label: string label: string
showIndicator: boolean showIndicator: boolean
minimalShellMode?: boolean // NOTE not used on mobile -prf minimalShellMode?: boolean // NOTE not used on mobile -prf
}) => { }) {
const store = useStores() const store = useStores()
const pal = usePalette('default') const pal = usePalette('default')
const safeAreaInsets = useSafeAreaInsets() const safeAreaInsets = useSafeAreaInsets()
@ -42,8 +41,7 @@ export const LoadLatestBtn = observer(
{showIndicator && <View style={[styles.indicator, pal.borderDark]} />} {showIndicator && <View style={[styles.indicator, pal.borderDark]} />}
</TouchableOpacity> </TouchableOpacity>
) )
}, })
)
const styles = StyleSheet.create({ const styles = StyleSheet.create({
loadLatest: { loadLatest: {

View File

@ -6,14 +6,13 @@ import {ListCard} from 'view/com/lists/ListCard'
import {AppBskyGraphDefs} from '@atproto/api' import {AppBskyGraphDefs} from '@atproto/api'
import {s} from 'lib/styles' import {s} from 'lib/styles'
export const ListEmbed = observer( export const ListEmbed = observer(function ListEmbedImpl({
({
item, item,
style, style,
}: { }: {
item: AppBskyGraphDefs.ListView item: AppBskyGraphDefs.ListView
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
}) => { }) {
const pal = usePalette('default') const pal = usePalette('default')
return ( return (
@ -21,8 +20,7 @@ export const ListEmbed = observer(
<ListCard list={item} style={[style, styles.card]} /> <ListCard list={item} style={[style, styles.card]} />
</View> </View>
) )
}, })
)
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {

View File

@ -19,7 +19,7 @@ import {CenteredView} from 'view/com/util/Views'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'AppPasswords'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'AppPasswords'>
export const AppPasswords = withAuthRequired( export const AppPasswords = withAuthRequired(
observer(({}: Props) => { observer(function AppPasswordsImpl({}: Props) {
const pal = usePalette('default') const pal = usePalette('default')
const store = useStores() const store = useStores()
const {screen} = useAnalytics() const {screen} = useAnalytics()

View File

@ -42,7 +42,7 @@ import {NavigationProp} from 'lib/routes/types'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'CustomFeed'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'CustomFeed'>
export const CustomFeedScreen = withAuthRequired( export const CustomFeedScreen = withAuthRequired(
observer((props: Props) => { observer(function CustomFeedScreenImpl(props: Props) {
const pal = usePalette('default') const pal = usePalette('default')
const store = useStores() const store = useStores()
const navigation = useNavigation<NavigationProp>() const navigation = useNavigation<NavigationProp>()
@ -119,7 +119,10 @@ export const CustomFeedScreen = withAuthRequired(
) )
export const CustomFeedScreenInner = observer( export const CustomFeedScreenInner = observer(
({route, feedOwnerDid}: Props & {feedOwnerDid: string}) => { function CustomFeedScreenInnerImpl({
route,
feedOwnerDid,
}: Props & {feedOwnerDid: string}) {
const store = useStores() const store = useStores()
const pal = usePalette('default') const pal = usePalette('default')
const {isTabletOrDesktop} = useWebMediaQueries() const {isTabletOrDesktop} = useWebMediaQueries()

View File

@ -19,7 +19,7 @@ import debounce from 'lodash.debounce'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'DiscoverFeeds'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'DiscoverFeeds'>
export const DiscoverFeedsScreen = withAuthRequired( export const DiscoverFeedsScreen = withAuthRequired(
observer(({}: Props) => { observer(function DiscoverFeedsScreenImpl({}: Props) {
const store = useStores() const store = useStores()
const pal = usePalette('default') const pal = usePalette('default')
const feeds = React.useMemo(() => new FeedsDiscoveryModel(store), [store]) const feeds = React.useMemo(() => new FeedsDiscoveryModel(store), [store])

View File

@ -25,7 +25,7 @@ const MOBILE_HEADER_OFFSET = 40
type Props = NativeStackScreenProps<FeedsTabNavigatorParams, 'Feeds'> type Props = NativeStackScreenProps<FeedsTabNavigatorParams, 'Feeds'>
export const FeedsScreen = withAuthRequired( export const FeedsScreen = withAuthRequired(
observer<Props>(({}: Props) => { observer<Props>(function FeedsScreenImpl({}: Props) {
const pal = usePalette('default') const pal = usePalette('default')
const store = useStores() const store = useStores()
const {isMobile} = useWebMediaQueries() const {isMobile} = useWebMediaQueries()

View File

@ -28,7 +28,7 @@ const POLL_FREQ = 30e3 // 30sec
type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'> type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'>
export const HomeScreen = withAuthRequired( export const HomeScreen = withAuthRequired(
observer(({}: Props) => { observer(function HomeScreenImpl({}: Props) {
const store = useStores() const store = useStores()
const pagerRef = React.useRef<PagerRef>(null) const pagerRef = React.useRef<PagerRef>(null)
const [selectedPage, setSelectedPage] = React.useState(0) const [selectedPage, setSelectedPage] = React.useState(0)
@ -142,22 +142,20 @@ export const HomeScreen = withAuthRequired(
}), }),
) )
const FeedPage = observer( const FeedPage = observer(function FeedPageImpl({
({
testID, testID,
isPageFocused, isPageFocused,
feed, feed,
renderEmptyState, renderEmptyState,
}: { }: {
testID?: string testID?: string
feed: PostsFeedModel feed: PostsFeedModel
isPageFocused: boolean isPageFocused: boolean
renderEmptyState?: () => JSX.Element renderEmptyState?: () => JSX.Element
}) => { }) {
const store = useStores() const store = useStores()
const {isMobile} = useWebMediaQueries() const {isMobile} = useWebMediaQueries()
const [onMainScroll, isScrolledDown, resetMainScroll] = const [onMainScroll, isScrolledDown, resetMainScroll] = useOnMainScroll(store)
useOnMainScroll(store)
const {screen, track} = useAnalytics() const {screen, track} = useAnalytics()
const [headerOffset, setHeaderOffset] = React.useState( const [headerOffset, setHeaderOffset] = React.useState(
isMobile ? HEADER_OFFSET_MOBILE : HEADER_OFFSET_DESKTOP, isMobile ? HEADER_OFFSET_MOBILE : HEADER_OFFSET_DESKTOP,
@ -233,15 +231,7 @@ const FeedPage = observer(
softResetSub.remove() softResetSub.remove()
feedCleanup() feedCleanup()
} }
}, [ }, [store, doPoll, onSoftReset, screen, feed, isPageFocused, isScreenFocused])
store,
doPoll,
onSoftReset,
screen,
feed,
isPageFocused,
isScreenFocused,
])
const onPressCompose = React.useCallback(() => { const onPressCompose = React.useCallback(() => {
track('HomeScreen:PressCompose') track('HomeScreen:PressCompose')
@ -289,5 +279,4 @@ const FeedPage = observer(
/> />
</View> </View>
) )
}, })
)

View File

@ -27,7 +27,7 @@ type Props = NativeStackScreenProps<
'ModerationBlockedAccounts' 'ModerationBlockedAccounts'
> >
export const ModerationBlockedAccounts = withAuthRequired( export const ModerationBlockedAccounts = withAuthRequired(
observer(({}: Props) => { observer(function ModerationBlockedAccountsImpl({}: Props) {
const pal = usePalette('default') const pal = usePalette('default')
const store = useStores() const store = useStores()
const {isTabletOrDesktop} = useWebMediaQueries() const {isTabletOrDesktop} = useWebMediaQueries()
@ -116,6 +116,8 @@ export const ModerationBlockedAccounts = withAuthRequired(
onEndReached={onEndReached} onEndReached={onEndReached}
renderItem={renderItem} renderItem={renderItem}
initialNumToRender={15} initialNumToRender={15}
// FIXME(dan)
// eslint-disable-next-line react/no-unstable-nested-components
ListFooterComponent={() => ( ListFooterComponent={() => (
<View style={styles.footer}> <View style={styles.footer}>
{blockedAccounts.isLoading && <ActivityIndicator />} {blockedAccounts.isLoading && <ActivityIndicator />}

View File

@ -27,7 +27,7 @@ type Props = NativeStackScreenProps<
'ModerationMutedAccounts' 'ModerationMutedAccounts'
> >
export const ModerationMutedAccounts = withAuthRequired( export const ModerationMutedAccounts = withAuthRequired(
observer(({}: Props) => { observer(function ModerationMutedAccountsImpl({}: Props) {
const pal = usePalette('default') const pal = usePalette('default')
const store = useStores() const store = useStores()
const {isTabletOrDesktop} = useWebMediaQueries() const {isTabletOrDesktop} = useWebMediaQueries()
@ -112,6 +112,8 @@ export const ModerationMutedAccounts = withAuthRequired(
onEndReached={onEndReached} onEndReached={onEndReached}
renderItem={renderItem} renderItem={renderItem}
initialNumToRender={15} initialNumToRender={15}
// FIXME(dan)
// eslint-disable-next-line react/no-unstable-nested-components
ListFooterComponent={() => ( ListFooterComponent={() => (
<View style={styles.footer}> <View style={styles.footer}>
{mutedAccounts.isLoading && <ActivityIndicator />} {mutedAccounts.isLoading && <ActivityIndicator />}

View File

@ -24,7 +24,7 @@ type Props = NativeStackScreenProps<
'Notifications' 'Notifications'
> >
export const NotificationsScreen = withAuthRequired( export const NotificationsScreen = withAuthRequired(
observer(({}: Props) => { observer(function NotificationsScreenImpl({}: Props) {
const store = useStores() const store = useStores()
const [onMainScroll, isScrolledDown, resetMainScroll] = const [onMainScroll, isScrolledDown, resetMainScroll] =
useOnMainScroll(store) useOnMainScroll(store)

View File

@ -48,7 +48,9 @@ type Props = NativeStackScreenProps<
CommonNavigatorParams, CommonNavigatorParams,
'PreferencesHomeFeed' 'PreferencesHomeFeed'
> >
export const PreferencesHomeFeed = observer(({navigation}: Props) => { export const PreferencesHomeFeed = observer(function PreferencesHomeFeedImpl({
navigation,
}: Props) {
const pal = usePalette('default') const pal = usePalette('default')
const store = useStores() const store = useStores()
const {isTabletOrDesktop} = useWebMediaQueries() const {isTabletOrDesktop} = useWebMediaQueries()

View File

@ -32,7 +32,7 @@ import {combinedDisplayName} from 'lib/strings/display-names'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Profile'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'Profile'>
export const ProfileScreen = withAuthRequired( export const ProfileScreen = withAuthRequired(
observer(({route}: Props) => { observer(function ProfileScreenImpl({route}: Props) {
const store = useStores() const store = useStores()
const {screen, track} = useAnalytics() const {screen, track} = useAnalytics()
const viewSelectorRef = React.useRef<ViewSelectorHandle>(null) const viewSelectorRef = React.useRef<ViewSelectorHandle>(null)

View File

@ -23,7 +23,7 @@ import {s} from 'lib/styles'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileList'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileList'>
export const ProfileListScreen = withAuthRequired( export const ProfileListScreen = withAuthRequired(
observer(({route}: Props) => { observer(function ProfileListScreenImpl({route}: Props) {
const store = useStores() const store = useStores()
const navigation = useNavigation<NavigationProp>() const navigation = useNavigation<NavigationProp>()
const {isTabletOrDesktop} = useWebMediaQueries() const {isTabletOrDesktop} = useWebMediaQueries()

View File

@ -35,7 +35,7 @@ import {Link, TextLink} from 'view/com/util/Link'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'SavedFeeds'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'SavedFeeds'>
export const SavedFeeds = withAuthRequired( export const SavedFeeds = withAuthRequired(
observer(({}: Props) => { observer(function SavedFeedsImpl({}: Props) {
const pal = usePalette('default') const pal = usePalette('default')
const store = useStores() const store = useStores()
const {isMobile, isTabletOrDesktop} = useWebMediaQueries() const {isMobile, isTabletOrDesktop} = useWebMediaQueries()
@ -151,8 +151,13 @@ export const SavedFeeds = withAuthRequired(
}), }),
) )
const ListItem = observer( const ListItem = observer(function ListItemImpl({
({item, drag}: {item: CustomFeedModel; drag: () => void}) => { item,
drag,
}: {
item: CustomFeedModel
drag: () => void
}) {
const pal = usePalette('default') const pal = usePalette('default')
const store = useStores() const store = useStores()
const savedFeeds = useMemo(() => store.me.savedFeeds, [store]) const savedFeeds = useMemo(() => store.me.savedFeeds, [store])
@ -192,9 +197,7 @@ const ListItem = observer(
style={[styles.itemContainer, pal.border]}> style={[styles.itemContainer, pal.border]}>
{isPinned && isWeb ? ( {isPinned && isWeb ? (
<View style={styles.webArrowButtonsContainer}> <View style={styles.webArrowButtonsContainer}>
<TouchableOpacity <TouchableOpacity accessibilityRole="button" onPress={onPressUp}>
accessibilityRole="button"
onPress={onPressUp}>
<FontAwesomeIcon <FontAwesomeIcon
icon="arrow-up" icon="arrow-up"
size={12} size={12}
@ -239,8 +242,7 @@ const ListItem = observer(
</ShadowDecorator> </ShadowDecorator>
</ScaleDecorator> </ScaleDecorator>
) )
}, })
)
const styles = StyleSheet.create({ const styles = StyleSheet.create({
desktopContainer: { desktopContainer: {

View File

@ -18,7 +18,7 @@ import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
type Props = NativeStackScreenProps<SearchTabNavigatorParams, 'Search'> type Props = NativeStackScreenProps<SearchTabNavigatorParams, 'Search'>
export const SearchScreen = withAuthRequired( export const SearchScreen = withAuthRequired(
observer(({navigation, route}: Props) => { observer(function SearchScreenImpl({navigation, route}: Props) {
const store = useStores() const store = useStores()
const params = route.params || {} const params = route.params || {}
const foafs = React.useMemo<FoafsModel>( const foafs = React.useMemo<FoafsModel>(

View File

@ -30,7 +30,7 @@ import {isAndroid, isIOS} from 'platform/detection'
type Props = NativeStackScreenProps<SearchTabNavigatorParams, 'Search'> type Props = NativeStackScreenProps<SearchTabNavigatorParams, 'Search'>
export const SearchScreen = withAuthRequired( export const SearchScreen = withAuthRequired(
observer<Props>(({}: Props) => { observer<Props>(function SearchScreenImpl({}: Props) {
const pal = usePalette('default') const pal = usePalette('default')
const store = useStores() const store = useStores()
const scrollViewRef = React.useRef<ScrollView>(null) const scrollViewRef = React.useRef<ScrollView>(null)

View File

@ -6,8 +6,7 @@ import {ComposerOpts} from 'state/models/ui/shell'
import {useAnimatedValue} from 'lib/hooks/useAnimatedValue' import {useAnimatedValue} from 'lib/hooks/useAnimatedValue'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
export const Composer = observer( export const Composer = observer(function ComposerImpl({
({
active, active,
winHeight, winHeight,
replyTo, replyTo,
@ -15,7 +14,7 @@ export const Composer = observer(
onClose, onClose,
quote, quote,
mention, mention,
}: { }: {
active: boolean active: boolean
winHeight: number winHeight: number
replyTo?: ComposerOpts['replyTo'] replyTo?: ComposerOpts['replyTo']
@ -23,7 +22,7 @@ export const Composer = observer(
onClose: () => void onClose: () => void
quote?: ComposerOpts['quote'] quote?: ComposerOpts['quote']
mention?: ComposerOpts['mention'] mention?: ComposerOpts['mention']
}) => { }) {
const pal = usePalette('default') const pal = usePalette('default')
const initInterp = useAnimatedValue(0) const initInterp = useAnimatedValue(0)
@ -71,8 +70,7 @@ export const Composer = observer(
/> />
</Animated.View> </Animated.View>
) )
}, })
)
const styles = StyleSheet.create({ const styles = StyleSheet.create({
wrapper: { wrapper: {

View File

@ -8,15 +8,14 @@ import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
const BOTTOM_BAR_HEIGHT = 61 const BOTTOM_BAR_HEIGHT = 61
export const Composer = observer( export const Composer = observer(function ComposerImpl({
({
active, active,
replyTo, replyTo,
quote, quote,
onPost, onPost,
onClose, onClose,
mention, mention,
}: { }: {
active: boolean active: boolean
winHeight: number winHeight: number
replyTo?: ComposerOpts['replyTo'] replyTo?: ComposerOpts['replyTo']
@ -24,7 +23,7 @@ export const Composer = observer(
onPost?: ComposerOpts['onPost'] onPost?: ComposerOpts['onPost']
onClose: () => void onClose: () => void
mention?: ComposerOpts['mention'] mention?: ComposerOpts['mention']
}) => { }) {
const pal = usePalette('default') const pal = usePalette('default')
const {isMobile} = useWebMediaQueries() const {isMobile} = useWebMediaQueries()
@ -54,8 +53,7 @@ export const Composer = observer(
</View> </View>
</View> </View>
) )
}, })
)
const styles = StyleSheet.create({ const styles = StyleSheet.create({
mask: { mask: {

View File

@ -44,7 +44,7 @@ import {useNavigationTabState} from 'lib/hooks/useNavigationTabState'
import {isWeb} from 'platform/detection' import {isWeb} from 'platform/detection'
import {formatCount, formatCountShortOnly} from 'view/com/util/numeric/format' import {formatCount, formatCountShortOnly} from 'view/com/util/numeric/format'
export const DrawerContent = observer(() => { export const DrawerContent = observer(function DrawerContentImpl() {
const theme = useTheme() const theme = useTheme()
const pal = usePalette('default') const pal = usePalette('default')
const store = useStores() const store = useStores()
@ -400,7 +400,7 @@ function MenuItem({
) )
} }
const InviteCodes = observer(() => { const InviteCodes = observer(function InviteCodesImpl() {
const {track} = useAnalytics() const {track} = useAnalytics()
const store = useStores() const store = useStores()
const pal = usePalette('default') const pal = usePalette('default')

View File

@ -32,7 +32,9 @@ import {UserAvatar} from 'view/com/util/UserAvatar'
type TabOptions = 'Home' | 'Search' | 'Notifications' | 'MyProfile' | 'Feeds' type TabOptions = 'Home' | 'Search' | 'Notifications' | 'MyProfile' | 'Feeds'
export const BottomBar = observer(({navigation}: BottomTabBarProps) => { export const BottomBar = observer(function BottomBarImpl({
navigation,
}: BottomTabBarProps) {
const store = useStores() const store = useStores()
const pal = usePalette('default') const pal = usePalette('default')
const safeAreaInsets = useSafeAreaInsets() const safeAreaInsets = useSafeAreaInsets()

View File

@ -23,7 +23,7 @@ import {Link} from 'view/com/util/Link'
import {useMinimalShellMode} from 'lib/hooks/useMinimalShellMode' import {useMinimalShellMode} from 'lib/hooks/useMinimalShellMode'
import {makeProfileLink} from 'lib/routes/links' import {makeProfileLink} from 'lib/routes/links'
export const BottomBarWeb = observer(() => { export const BottomBarWeb = observer(function BottomBarWebImpl() {
const store = useStores() const store = useStores()
const pal = usePalette('default') const pal = usePalette('default')
const safeAreaInsets = useSafeAreaInsets() const safeAreaInsets = useSafeAreaInsets()

View File

@ -40,7 +40,7 @@ import {NavigationProp, CommonNavigatorParams} from 'lib/routes/types'
import {router} from '../../../routes' import {router} from '../../../routes'
import {makeProfileLink} from 'lib/routes/links' import {makeProfileLink} from 'lib/routes/links'
const ProfileCard = observer(() => { const ProfileCard = observer(function ProfileCardImpl() {
const store = useStores() const store = useStores()
const {isDesktop} = useWebMediaQueries() const {isDesktop} = useWebMediaQueries()
const size = isDesktop ? 64 : 48 const size = isDesktop ? 64 : 48
@ -103,8 +103,13 @@ interface NavItemProps {
iconFilled: JSX.Element iconFilled: JSX.Element
label: string label: string
} }
const NavItem = observer( const NavItem = observer(function NavItemImpl({
({count, href, icon, iconFilled, label}: NavItemProps) => { count,
href,
icon,
iconFilled,
label,
}: NavItemProps) {
const pal = usePalette('default') const pal = usePalette('default')
const store = useStores() const store = useStores()
const {isDesktop, isTablet} = useWebMediaQueries() const {isDesktop, isTablet} = useWebMediaQueries()
@ -173,8 +178,7 @@ const NavItem = observer(
)} )}
</PressableWithHover> </PressableWithHover>
) )
}, })
)
function ComposeBtn() { function ComposeBtn() {
const store = useStores() const store = useStores()

View File

@ -13,7 +13,7 @@ import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {pluralize} from 'lib/strings/helpers' import {pluralize} from 'lib/strings/helpers'
import {formatCount} from 'view/com/util/numeric/format' import {formatCount} from 'view/com/util/numeric/format'
export const DesktopRightNav = observer(function DesktopRightNav() { export const DesktopRightNav = observer(function DesktopRightNavImpl() {
const store = useStores() const store = useStores()
const pal = usePalette('default') const pal = usePalette('default')
const palError = usePalette('error') const palError = usePalette('error')
@ -78,7 +78,7 @@ export const DesktopRightNav = observer(function DesktopRightNav() {
) )
}) })
const InviteCodes = observer(() => { const InviteCodes = observer(function InviteCodesImpl() {
const store = useStores() const store = useStores()
const pal = usePalette('default') const pal = usePalette('default')

View File

@ -24,7 +24,7 @@ import {isStateAtTabRoot} from 'lib/routes/helpers'
import {SafeAreaProvider} from 'react-native-safe-area-context' import {SafeAreaProvider} from 'react-native-safe-area-context'
import {useOTAUpdate} from 'lib/hooks/useOTAUpdate' import {useOTAUpdate} from 'lib/hooks/useOTAUpdate'
const ShellInner = observer(() => { const ShellInner = observer(function ShellInnerImpl() {
const store = useStores() const store = useStores()
useOTAUpdate() // this hook polls for OTA updates every few seconds useOTAUpdate() // this hook polls for OTA updates every few seconds
const winDim = useWindowDimensions() const winDim = useWindowDimensions()
@ -81,7 +81,7 @@ const ShellInner = observer(() => {
) )
}) })
export const Shell: React.FC = observer(() => { export const Shell: React.FC = observer(function ShellImpl() {
const pal = usePalette('default') const pal = usePalette('default')
const theme = useTheme() const theme = useTheme()
return ( return (

View File

@ -17,7 +17,7 @@ import {BottomBarWeb} from './bottom-bar/BottomBarWeb'
import {useNavigation} from '@react-navigation/native' import {useNavigation} from '@react-navigation/native'
import {NavigationProp} from 'lib/routes/types' import {NavigationProp} from 'lib/routes/types'
const ShellInner = observer(() => { const ShellInner = observer(function ShellInnerImpl() {
const store = useStores() const store = useStores()
const {isDesktop, isMobile} = useWebMediaQueries() const {isDesktop, isMobile} = useWebMediaQueries()
const navigator = useNavigation<NavigationProp>() const navigator = useNavigation<NavigationProp>()
@ -71,7 +71,7 @@ const ShellInner = observer(() => {
) )
}) })
export const Shell: React.FC = observer(() => { export const Shell: React.FC = observer(function ShellImpl() {
const pageBg = useColorSchemeStyle(styles.bgLight, styles.bgDark) const pageBg = useColorSchemeStyle(styles.bgLight, styles.bgDark)
return ( return (
<View style={[s.hContentRegion, pageBg]}> <View style={[s.hContentRegion, pageBg]}>