Skip to content

Commit

Permalink
Added New Sub Component: ListItem Accordion (react-native-elements#2953)
Browse files Browse the repository at this point in the history
* Added Accordion

* Improved

* Added Docs

* Added Prop

* Fixed

* Fixed
  • Loading branch information
arpitBhalla authored Apr 12, 2021
1 parent d76f602 commit 19566ea
Show file tree
Hide file tree
Showing 6 changed files with 233 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Button, { ButtonProps } from './buttons/Button';
import Input, { InputProps } from './input/Input';
import Icon, { IconProps } from './icons/Icon';
import ListItem, { ListItemProps } from './list/ListItem';
import { ListItemAccordionProps } from './list/ListItemAccordion';
import SocialIcon, { SocialIconProps } from './social/SocialIcon';
import Overlay, { OverlayProps } from './overlay/Overlay';

Expand Down Expand Up @@ -145,4 +146,5 @@ export type {
SpeedDialActionProps,
SpeedDialProps,
ThemeProps,
ListItemAccordionProps,
};
3 changes: 3 additions & 0 deletions src/list/ListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import ListItemCheckBox from './ListItemCheckBox';
import ListItemButtonGroup from './ListItemButtonGroup';
import ListItemTitle from './ListItemTitle';
import ListItemSubtitle from './ListItemSubtitle';
import ListItemAccordion from './ListItemAccordion';
import { RneFunctionComponent } from '../helpers';

export type ListItemProps = TouchableHighlightProps & {
Expand All @@ -33,6 +34,7 @@ export type ListItemProps = TouchableHighlightProps & {
};

interface ListItem extends RneFunctionComponent<ListItemProps> {
Accordion: typeof ListItemAccordion;
Chevron: typeof ListItemChevron;
Content: typeof ListItemContent;
Input: typeof ListItemInput;
Expand Down Expand Up @@ -144,6 +146,7 @@ class PadView extends React.Component<PadViewProps> {
export { ListItem };

const ThemedListItem = Object.assign(withTheme(ListItem, 'ListItem'), {
Accordion: ListItemAccordion,
Chevron: ListItemChevron,
Content: ListItemContent,
Input: ListItemInput,
Expand Down
103 changes: 103 additions & 0 deletions src/list/ListItemAccordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import React from 'react';
import { Animated } from 'react-native';
import { ListItem, ListItemProps } from './ListItem';
import { withTheme } from '../config';
import { Icon, IconNode, IconProps } from '../icons/Icon';
import { RneFunctionComponent } from '../helpers';

export type ListItemAccordionProps = ListItemProps & {
isExpanded?: boolean;
icon?: IconNode;
expandIcon?: IconNode;
content?: React.ReactNode;
noAnimation?: boolean;
noRotation?: boolean;
noIcon?: boolean;
animationDuration?: number;
};

const Accordion: RneFunctionComponent<ListItemAccordionProps> = ({
children,
isExpanded,
icon,
expandIcon,
content,
noAnimation,
noRotation,
noIcon,
animationDuration = 350,
...props
}) => {
const { current: animation } = React.useRef(new Animated.Value(0));

const startAnimation = React.useCallback(() => {
Animated.timing(animation, {
toValue: Number(isExpanded),
useNativeDriver: false,
duration: animationDuration,
}).start();
}, [isExpanded, animation, animationDuration]);

React.useEffect(() => {
if (noAnimation) {
return;
}
startAnimation();
}, [isExpanded, startAnimation, noAnimation]);

const rotate = noRotation
? '0deg'
: animation.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '-180deg'],
});

return (
<>
<ListItem {...props}>
{React.isValidElement(content) ? content : <ListItem.Content />}
{!noIcon && (
<Animated.View
style={{
transform: [
{
rotate,
},
],
}}
>
{icon ? (
<Icon
{...((expandIcon
? isExpanded
? expandIcon
: icon
: icon) as IconProps)}
/>
) : (
<Icon name={'chevron-down'} type="material-community" />
)}
</Animated.View>
)}
</ListItem>
<Animated.View
style={[
{
maxHeight: animation.interpolate({
inputRange: [0, 1],
outputRange: ['0%', '100%'],
}),
opacity: animation,
},
noAnimation && {
maxHeight: isExpanded ? '100%' : '0%',
},
]}
>
{children}
</Animated.View>
</>
);
};

export default withTheme(Accordion, 'ListItem.Accordion');
32 changes: 32 additions & 0 deletions website/docs/listitem.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,38 @@ import LinearGradient from 'react-native-linear-gradient'; // Only if no expo
</ListItem>;
```

### ListItem Accordion

<img src="/img/accorsion.gif" width="500" />

```js
<ListItem.Accordion
content={
<>
<Icon name="place" size={30} />
<ListItem.Content>
<ListItem.Title>List Accordion</ListItem.Title>
</ListItem.Content>
</>
}
isExpanded={expanded}
onPress={() => {
setExpanded(!expanded);
}}
>
{list2.map((l, i) => (
<ListItem key={i} onPress={log} bottomDivider>
<Avatar title={l.name[0]} source={{ uri: l.avatar_url }} />
<ListItem.Content>
<ListItem.Title>{l.name}</ListItem.Title>
<ListItem.Subtitle>{l.subtitle}</ListItem.Subtitle>
</ListItem.Content>
<ListItem.Chevron />
</ListItem>
))}
</ListItem.Accordion>
```

---

<Props />
Expand Down
93 changes: 93 additions & 0 deletions website/docs/props/listitem.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,19 @@

> Receives all [Text](text.md#props) props.
### ListItem.Accordion

- [`isExpanded`](#isexpanded)
- [`icon`](#icon)
- [`expandIcon`](#expandicon)
- [`content`](#content)
- [`noAnimation`](#noanimation)
- [`noIcon`](#noicon)
- [`noRotation`](#norotation)
- [`animationDuration`](#animationduration)

> Also Receives all [ListItem](#props) props.
---

## Reference
Expand Down Expand Up @@ -150,3 +163,83 @@ Container for linear gradient (for non-expo user)
| component | View |

---

### `isExpanded`

Accordion Expanded

| Type | Default |
| :-----: | :-----: |
| booleon | false |

---

### `icon`

Icon for unexpanded Accordion

| Type | Default |
| :------: | :----------: |
| IocnNode | chevron-down |

---

### `expandIcon`

Icon when Accordion is expanded, if not provided `icon` will be rotated 180deg (optional)

| Type | Default |
| :------: | :-----: |
| IconNode | none |

---

### `content`

Similar to ListItem's child

| Type | Default |
| :-------: | :--------------------: |
| ReactNode | Empty ListItem.Content |

---

### `noAnimation`

Don't show animations to be played or not

| Type | Default |
| :-----: | :-----: |
| boolean | false |

---

### `noIcon`

Don't show accordion icon

| Type | Default |
| :-----: | :-----: |
| boolean | false |

---

### `noRotation`

Don't rotate when Accordion is expanded

| Type | Default |
| :-----: | :-----: |
| boolean | false |

---

### `animationDuration`

Duration of accordion expansion

| Type | Default |
| :----: | :-----: |
| number | 350 |

---
Binary file added website/static/img/accorsion.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 19566ea

Please sign in to comment.