Skip to content

Commit

Permalink
feat: adds ListView Higher Order Component
Browse files Browse the repository at this point in the history
Displays a FlashList or FlatList depending on language RTL features. Needs a little more work on the `ref` passing.
  • Loading branch information
markrickert committed Oct 10, 2023
1 parent 2630214 commit 1e85d88
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 10 deletions.
33 changes: 33 additions & 0 deletions boilerplate/app/components/ListView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { forwardRef, PropsWithoutRef } from "react"
import { FlatList } from "react-native"
import { isRTL } from "app/i18n"
import { FlashList, FlashListProps } from "@shopify/flash-list"

export interface ListViewProps<T> extends PropsWithoutRef<FlashListProps<T>> {}

/**
* This is a Higher Order Component meant to ease the pain of using @shopify/flash-list
* when there is a chance that a user would have their device language set to an
* RTL language like Arabic or Punjabi. This component will use react-native's
* FlatList if the user's language is RTL or FlashList if the user's language is LTR.
*
* Because FlashList's props are a superset of FlatList's, you must pass estimatedItemSize
* to this component if you want to use it.
*
* This is a temporary workaround until the FlashList component supports RTL at
* which point this component can be removed and we will default to using FlashList everywhere.
*
* @see {@link https://github.com/Shopify/flash-list/issues/544|RTL Bug Android}
* @see {@link https://github.com/Shopify/flash-list/issues/840|Flashlist Not Support RTL}
*
* @param props - FlashListProps
* @param forwardRef - React.ForwardedRef<FlashList<T>>
* @returns JSX.Element
*/
export const ListView = forwardRef(
<T,>(props: ListViewProps<T>, forwardRef: React.ForwardedRef<FlashList<T>>) => {
const ListComponentWrapper = isRTL ? FlatList : FlashList

return <ListComponentWrapper {...props} ref={forwardRef} />
},
) as <T>(props: ListViewProps<T>, ref: React.ForwardedRef<FlashList<T>>) => JSX.Element
1 change: 1 addition & 0 deletions boilerplate/app/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * from "./Card"
export * from "./Header"
export * from "./Icon"
export * from "./ListItem"
export * from "./ListView"
export * from "./Screen"
export * from "./Text"
export * from "./TextField"
Expand Down
6 changes: 3 additions & 3 deletions boilerplate/app/screens/DemoPodcastListScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ import {
View,
ViewStyle,
} from "react-native"
import { FlashList, type ContentStyle } from "@shopify/flash-list"
import { type ContentStyle } from "@shopify/flash-list"
import Animated, {
Extrapolate,
interpolate,
useAnimatedStyle,
useSharedValue,
withSpring,
} from "react-native-reanimated"
import { Button, Card, EmptyState, Icon, Screen, Text, Toggle } from "../components"
import { Button, Card, EmptyState, Icon, ListView, Screen, Text, Toggle } from "../components"
import { isRTL, translate } from "../i18n"
import { useStores } from "../models"
import { Episode } from "../models/Episode"
Expand Down Expand Up @@ -64,7 +64,7 @@ export const DemoPodcastListScreen: FC<DemoTabScreenProps<"DemoPodcastList">> =
safeAreaEdges={["top"]}
contentContainerStyle={$screenContentContainer}
>
<FlashList<Episode>
<ListView<Episode>
contentContainerStyle={$listContentContainer}
data={episodeStore.episodesForList.slice()}
extraData={episodeStore.favorites.length + episodeStore.episodes.length}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import {
View,
ViewStyle,
} from "react-native"
import { FlashList, type ContentStyle } from "@shopify/flash-list"
import { type ContentStyle } from "@shopify/flash-list"
import { DrawerLayout, DrawerState } from "react-native-gesture-handler"
import { useSharedValue, withTiming } from "react-native-reanimated"
import { ListItem, Screen, Text } from "../../components"
import { ListItem, ListView, Screen, Text } from "../../components"
import { isRTL } from "../../i18n"
import { DemoTabParamList, DemoTabScreenProps } from "../../navigators/DemoNavigator"
import { colors, spacing } from "../../theme"
Expand Down Expand Up @@ -88,7 +88,7 @@ export const DemoShowroomScreen: FC<DemoTabScreenProps<"DemoShowroom">> =
const timeout = useRef<ReturnType<typeof setTimeout>>()
const drawerRef = useRef<DrawerLayout>(null)
const listRef = useRef<SectionList>(null)
const menuRef = useRef<FlashList<{ name: string; useCases: string[] }>>(null)
const menuRef = useRef<typeof ListView<{ name: string; useCases: string[] }>>(null)
const progress = useSharedValue(0)
const route = useRoute<RouteProp<DemoTabParamList, "DemoShowroom">>()
const params = route.params
Expand Down Expand Up @@ -181,7 +181,7 @@ export const DemoShowroomScreen: FC<DemoTabScreenProps<"DemoShowroom">> =
<Image source={logo} style={$logoImage} />
</View>

<FlashList<{ name: string; useCases: string[] }>
<ListView<{ name: string; useCases: string[] }>
ref={menuRef}
contentContainerStyle={$listContentContainer}
estimatedItemSize={250}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
/* eslint-disable react/jsx-key, react-native/no-inline-styles */
import React from "react"
import { TextStyle, View, ViewStyle } from "react-native"
import { FlashList } from "@shopify/flash-list"
import { Icon, ListItem, Text } from "../../../components"
import { Icon, ListItem, ListView, Text } from "../../../components"
import { colors, spacing } from "../../../theme"
import { Demo } from "../DemoShowroomScreen"
import { DemoDivider } from "../DemoDivider"
Expand Down Expand Up @@ -148,7 +147,7 @@ export const DemoListItem: Demo = {
description="The component can be easily integrated with your favorite list interface."
>
<View style={$listStyle}>
<FlashList<string>
<ListView<string>
data={listData}
renderItem={({ item, index }) => (
<ListItem
Expand Down
13 changes: 13 additions & 0 deletions docs/Components-ListView.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# ListView Component

The `ListView` component is a Higher Order Component that uses [Shopify's FlashList](https://shopify.github.io/flash-list/) component to display a list unless the user's preferred language is RTL (right-to-left). This is because FlashList has [known](https://github.com/Shopify/flash-list/issues/544) [issues](https://github.com/Shopify/flash-list/issues/840) with RTL support. Once these issues with FlashList are resolved, this component will be deprecated and FlashList will be used directly.

## Props

The `ListView` component uses props from `FlashList` because they are a superset of `FlatList` and only require one extra prop to work for both component types.

> [Please see the FlashList documentation for more information on the props that are available.](https://shopify.github.io/flash-list/docs/usage)
### `estimatedItemSize`

> [Please see the FlashList documentation for more information on this prop.](https://shopify.github.io/flash-list/docs/estimated-item-size)
1 change: 1 addition & 0 deletions docs/Folder-Structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ This is where your components will live, the reusable building blocks to create
- [Header](./Components-Header.md)
- [Icon](./Components-Icon.md)
- [ListItem](./Components-ListItem.md)
- [ListView](./Components-ListView.md)
- [Screen](./Components-Screen.md)
- [Text](./Components-Text.md)
- [TextField](./Components-TextField.md)
Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Check out this list of topics:
- [Header](./Components-Header.md)
- [Icon](./Components-Icon.md)
- [ListItem](./Components-ListItem.md)
- [ListView](./Components-ListView.md)
- [Screen](./Components-Screen.md)
- [Text](./Components-Text.md)
- [TextField](./Components-TextField.md)
Expand Down

0 comments on commit 1e85d88

Please sign in to comment.