Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions apps/docs/pages/docs/v2/Components/Lists/list.en-US.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
searchable: true
---

import { CodeEditor } from '@components/code-editor';

# List

Wrapper around `FlatList` component from `react-native`.

`List` component accepts every props from react native `FlatList` component.

## Import

```js
import { List } from "@ficus-ui/native";
```

## Usage

<CodeEditor code={`<List
bg="gray.200"
p="xl"
data={[
{
id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba',
title: 'First Item',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd91aa97f63',
title: 'Second Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'Third Item',
},
]}
renderItem={({ item }) => (
<Box p="lg">
<Text>{item.title}</Text>
</Box>
)}
/>`} />

## Props

Extends every `Box` and `FlatList` props.
39 changes: 39 additions & 0 deletions apps/examples/app/components-v2/List.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Box, Flex, List, SafeAreaBox, Text } from '@ficus-ui/native';

const ListComponent = () => {
const DATA = [
{
id: "bd7acbea-c1b1-46c2-aed5-3ad53abb28ba",
title: "First Item",
},
{
id: "3ac68afc-c605-48d3-a4f8-fbd91aa97f63",
title: "Second Item",
},
{
id: "58694a0f-3da1-471f-bd96-145571e29d72",
title: "Third Item",
},
];
return (
<SafeAreaBox>
<Text mx="xl" fontSize="4xl">
List component
</Text>
<Flex mt="xl">
<List
bg="gray.200"
p="xl"
data={DATA}
renderItem={({ item }:any) => (
<Box p="lg">
<Text>{item?.title}</Text>
</Box>
)}
/>
</Flex>
</SafeAreaBox>
);
};

export default ListComponent;
2 changes: 2 additions & 0 deletions apps/examples/app/items-v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import DividerComponent from '@/app/components-v2/Divider';
import SpinnerComponent from '@/app/components-v2/Spinner';
import SliderComponent from '@/app/components-v2/Slider';
import IconComponent from '@/app/components-v2/Icon';
import ListComponent from '@/app/components-v2/List';

type ExampleComponentType = {
onScreenName: string;
Expand All @@ -41,4 +42,5 @@ export const components: ExampleComponentType[] = [
{ navigationPath: 'Pressable', onScreenName: 'Pressable', component: PressableComponent },
{ navigationPath: 'Slider', onScreenName: 'Slider', component: SliderComponent },
{ navigationPath: 'Icon', onScreenName: 'Icon', component: IconComponent },
{ navigationPath: 'List', onScreenName: 'List', component: ListComponent },
];
1 change: 1 addition & 0 deletions packages/components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ export * from './divider';
export * from './spinner';
export * from './slider';
export * from './icon';
export * from './list';

export { ThemeProvider } from '@ficus-ui/theme';
9 changes: 9 additions & 0 deletions packages/components/src/list/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { type NativeFicusProps, ficus } from '../system';

export interface ListProps extends NativeFicusProps<'Flatlist'> {}

export const List = ficus('Flatlist', {
baseStyle: {
flex: 1,
},
});
83 changes: 83 additions & 0 deletions packages/components/src/list/list.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React from 'react';

import { render } from '@testing-library/react-native';

import { List } from '.';
import { Text } from '../text';

jest.mock('react-native-toast-message', () => 'Toast');

describe('List component', () => {
const mockData = [
{ id: '1', title: 'First Item' },
{ id: '2', title: 'Second Item' },
{ id: '3', title: 'Third Item' },
];

it('should render without crashing', () => {
const { getByTestId } = render(
<List
testID="list-container"
data={mockData}
renderItem={({ item }: any) => <Text>{item?.title}</Text>}
/>
);

expect(getByTestId('list-container')).toBeTruthy();
});

it('should render the correct number of list items', () => {
const { getAllByTestId } = render(
<List
data={mockData}
renderItem={({ item }: any) => (
<Text testID="list-item">{item.title}</Text>
)}
/>
);

const items = getAllByTestId('list-item');
expect(items.length).toBe(mockData.length);
});

it('should display correct item text', () => {
const { getByText } = render(
<List
data={mockData}
renderItem={({ item }: any) => <Text>{item.title}</Text>}
/>
);

expect(getByText('First Item')).toBeTruthy();
expect(getByText('Second Item')).toBeTruthy();
expect(getByText('Third Item')).toBeTruthy();
});

it('should use the correct keyExtractor', () => {
const keyExtractor = jest.fn((item) => item.id);
render(
<List
data={mockData}
renderItem={({ item }: any) => <Text>{item.title}</Text>}
keyExtractor={keyExtractor}
/>
);

expect(keyExtractor).toHaveBeenCalledWith(mockData[0], 0);
expect(keyExtractor).toHaveBeenCalledWith(mockData[1], 1);
expect(keyExtractor).toHaveBeenCalledWith(mockData[2], 2);
});

it('should render empty list when no data is passed', () => {
const { queryAllByTestId } = render(
<List
data={[]}
renderItem={({ item }: any) => (
<Text testID="list-item">{item.title}</Text>
)}
/>
);

expect(queryAllByTestId('list-item').length).toBe(0);
});
});
2 changes: 2 additions & 0 deletions packages/components/src/system/base-elements.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import RNSlider from '@react-native-community/slider';
import {
ActivityIndicator as RNActivityIndicator,
FlatList as RNFlatList,
Image as RNImage,
Pressable as RNPressable,
SafeAreaView as RNSafeAreaView,
Expand All @@ -27,6 +28,7 @@ export const baseRNElements = {
Pressable: RNPressable,
ActivityIndicator: RNActivityIndicator,
Slider: RNSlider,
Flatlist: RNFlatList,
} as const;

export type BaseRNElements = keyof typeof baseRNElements;
Loading