├── ListView ├── ListItems.js ├── Recursive.js └── index.js ├── ReadMe.md ├── index.js └── package.json /ListView/ListItems.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { View, Image, Text, TouchableOpacity, StyleSheet } from "react-native"; 3 | 4 | export default ListItem = props => { 5 | const { 6 | listItemStyle, 7 | onPress, 8 | leftImageStyle, 9 | leftImage, 10 | text, 11 | textStyle, 12 | rightImage, 13 | rightImageStyle, 14 | rightImageWrapperStyle 15 | } = props; 16 | return ( 17 | 22 | {leftImage && ( 23 | 28 | )} 29 | {text} 30 | {rightImage && ( 31 | 32 | 37 | 38 | )} 39 | 40 | ); 41 | }; 42 | 43 | const styles = StyleSheet.create({ 44 | container: { 45 | flex: 1, 46 | flexDirection: "row", 47 | paddingVertical: 10, 48 | alignItems: "center" 49 | }, 50 | text: { 51 | fontSize: 17, 52 | fontWeight: "500", 53 | color: "#000", 54 | marginLeft: 10, 55 | marginRight: 10 56 | }, 57 | rightImageWrapperStyle: { 58 | alignItems: "flex-end", 59 | flex: 1, 60 | paddingRight: 10 61 | } 62 | }); 63 | -------------------------------------------------------------------------------- /ListView/Recursive.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { 3 | View, 4 | ScrollView, 5 | UIManager, 6 | LayoutAnimation, 7 | StyleSheet, 8 | } from 'react-native'; 9 | import ListItems from './ListItems'; 10 | import PropTypes from 'prop-types'; 11 | 12 | export default Apps = props => { 13 | const [selectedOptions, setSelectedOptions] = useState({}); 14 | 15 | UIManager.setLayoutAnimationEnabledExperimental && 16 | UIManager.setLayoutAnimationEnabledExperimental(true); 17 | 18 | const { 19 | containerStyle, 20 | listContainerStyle, 21 | listItemStyle, 22 | data, 23 | displayNodeName, 24 | childrenNodeName, 25 | ...rest 26 | } = props; 27 | let dNN = displayNodeName ? displayNodeName : 'name'; 28 | let cNN = childrenNodeName ? childrenNodeName : 'items'; 29 | 30 | const selectAccountFunc = (selectedOptions, option) => { 31 | if (option[cNN]) { 32 | LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); 33 | setSelectedOptions({ ...selectedOptions }); 34 | } else { 35 | props.onClick && props.onClick(option); 36 | } 37 | }; 38 | 39 | let checkType = data ? (data instanceof Array ? data : []) : []; 40 | return ( 41 | 42 | 52 | 53 | ); 54 | }; 55 | 56 | // Recursive component 57 | const OptionsList = ({ 58 | options, 59 | selectedOptions, 60 | onChange, 61 | listContainerStyle, 62 | ...rest 63 | }) => { 64 | const { displayNodeName, childrenNodeName } = rest; 65 | const handleParentClicked = option => { 66 | if (selectedOptions[option.value]) { 67 | delete selectedOptions[option.value]; 68 | } else { 69 | selectedOptions[option.value] = {}; 70 | } 71 | onChange(selectedOptions, option); 72 | }; 73 | 74 | const handleSubOptionsListChange = (subSelections, option) => { 75 | selectedOptions[option.value] = subSelections; 76 | onChange(selectedOptions, option); 77 | }; 78 | 79 | return ( 80 | 81 | {options.map((option, k) => ( 82 | 83 | { 89 | handleParentClicked(option); 90 | }} 91 | {...rest} 92 | /> 93 | 94 | {/* Recursive Case */} 95 | {option[childrenNodeName] && 96 | option[childrenNodeName].length > 0 && 97 | selectedOptions[option.value] && ( 98 | 102 | { 106 | handleSubOptionsListChange(subSelections, opt); 107 | }} 108 | listContainerStyle={{ 109 | ...listContainerStyle, 110 | }} 111 | {...rest} 112 | /> 113 | 114 | )} 115 | 116 | ))} 117 | 118 | ); 119 | }; 120 | 121 | // Dumb List component, completly controlled by parent 122 | const List = ({ 123 | selected, 124 | label, 125 | onChange, 126 | items, 127 | value, 128 | listContainerStyle, 129 | rightImage, 130 | rightImageStyle, 131 | rightImageWrapperStyle, 132 | leftImageStyle, 133 | leftImage, 134 | listItemStyle, 135 | textStyle, 136 | }) => { 137 | return ( 138 | 139 | onChange(!selected, label, value, items)} 146 | text={label} 147 | rightImageStyle={rightImageStyle} 148 | rightImageWrapperStyle={rightImageWrapperStyle} 149 | leftImageStyle={leftImageStyle} 150 | listItemStyle={{ ...listItemStyle }} 151 | textStyle={textStyle} 152 | rightImage={ 153 | items && 154 | (rightImage || { 155 | uri: 'http://www.pngmart.com/files/3/Down-Arrow-PNG-HD.png', 156 | }) 157 | } 158 | /> 159 | 160 | ); 161 | }; 162 | 163 | const styles = StyleSheet.create({ 164 | containerStyle: { 165 | paddingHorizontal: 10, 166 | paddingVertical: 5, 167 | }, 168 | listItemStyle: { 169 | flex: 1, 170 | flexDirection: 'row', 171 | paddingVertical: 10, 172 | alignItems: 'center', 173 | }, 174 | listContainerStyle: { 175 | borderTopColor: 'gray', 176 | borderTopWidth: 1, 177 | flex: 1, 178 | }, 179 | }); 180 | 181 | Apps.propTypes = { 182 | data: PropTypes.arrayOf(PropTypes.any).isRequired, 183 | }; 184 | -------------------------------------------------------------------------------- /ListView/index.js: -------------------------------------------------------------------------------- 1 | import Recursive from "./Recursive"; 2 | export default Recursive; 3 | -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | # react-native-animated-tree-view 2 | 3 | A React Native animated tree view component 4 | 5 | ![platforms](https://img.shields.io/badge/platforms-Android%20%7C%20iOS-brightgreen.svg?style=flat-square) 6 | [![github release](https://img.shields.io/github/v/release/shariqahmed1/react-native-animated-tree-view.svg?style=flat-square)](https://www.github.com/shariqahmed1/react-native-animated-tree-view/releases) 7 | 8 | ## Table of contents 9 | 10 | 1. [Show](#show) 11 | 1. [Usage](#usage) 12 | 1. [Props](#props) 13 | 14 | ## Show 15 | 16 | ![react-native-animated-tree-view](https://media.giphy.com/media/kgZdimnRjNLVdbXhUI/giphy.gif) 17 | 18 | ## Installation 19 | 20 | ``` 21 | yarn add react-native-animated-tree-view 22 | ``` 23 | 24 | ## Usage 25 | 26 | Firstly, you have to define your data. Example: 27 | 28 | ```javascript 29 | const data = [ 30 | { 31 | name: "Cheese", 32 | value: "cheese-value" 33 | }, 34 | { 35 | name: "Cheese", 36 | value: "cheese-value", 37 | items: [ 38 | { 39 | name: "Spicy", 40 | value: "spicy-value" 41 | }, 42 | { 43 | name: "Cheese", 44 | value: "cheese-value", 45 | items: [ 46 | { 47 | name: "Spicy", 48 | value: "spicy-value" 49 | }, 50 | { 51 | name: "Spicy", 52 | value: "spicy-value" 53 | } 54 | ] 55 | } 56 | ] 57 | } 58 | ]; 59 | ``` 60 | 61 | It is required that each node on the tree have its own value key which name should be "value". The tree nodes are defined in the items key. They are an array of objects, following the same structure as the parent. 62 | 63 | After defining data, mount the component. Example: 64 | 65 | ```javascript 66 | import TreeView from "react-native-animated-tree-view"; 67 | 68 | export default App = () => { 69 | return ; 70 | }; 71 | ``` 72 | 73 | ## Props 74 | 75 | ### ListView 76 | 77 | | Prop | Description | Type | Default | 78 | | -------------------- | ------------------------------------------------------------------------------------------------ | -------- | ------------ | 79 | | **data** | Array of nested items | Array | **Required** | 80 | | **onClick** | Return clicked item | Function | Not Require | 81 | | **displayNodeName** | Takes a node to render a display text | String | name | 82 | | **childrenNodeName** | Node to determine in a node where are the children, by default it will try to find them in items | String | items | 83 | | **leftImage** | Left side image | | Not Require | 84 | | **rightImage** | Right side image | | Not Require | 85 | 86 | ### Style Props 87 | 88 | | Prop | Description | Type | 89 | | -------------------------- | ------------------------------ | ------ | 90 | | **containerStyle** | Container Style | Object | 91 | | **listContainerStyle** | List Container Style | Object | 92 | | **listItemStyle** | List Item Style | Object | 93 | | **textStyle** | List Item Text Style | Object | 94 | | **leftImageStyle** | Left side image style | Object | 95 | | **rightImageWrapperStyle** | Right side image wrapper style | Object | 96 | | **rightImageStyle** | Right side image style | Object | 97 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import TreeView from "./ListView"; 2 | export default TreeView; 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-animated-tree-view", 3 | "version": "0.1.4", 4 | "description": "A react native tree view component", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/shariqahmed1/react-native-animated-tree-view.git" 12 | }, 13 | "keywords": [ 14 | "react", 15 | "react-native", 16 | "react-native-tree-view", 17 | "react-native-sublist", 18 | "react-native-sublist-view", 19 | "react-native-nested-list-view", 20 | "react-native-animated-list-view", 21 | "react-native-recursive-list" 22 | ], 23 | "author": "Shariq Ahmed ", 24 | "license": "ISC", 25 | "bugs": { 26 | "url": "https://github.com/shariqahmed1/react-native-animated-tree-view/issues" 27 | }, 28 | "homepage": "https://github.com/shariqahmed1/react-native-animated-tree-view#readme" 29 | } 30 | --------------------------------------------------------------------------------