UNPKG

3.9 kBJavaScriptView Raw
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { View, TouchableHighlight } from 'react-native';
4import Collapsible from './Collapsible';
5import { ViewPropTypes } from './config';
6
7const COLLAPSIBLE_PROPS = Object.keys(Collapsible.propTypes);
8const VIEW_PROPS = Object.keys(ViewPropTypes);
9
10export default class Accordion extends Component {
11 static propTypes = {
12 sections: PropTypes.array.isRequired,
13 renderHeader: PropTypes.func.isRequired,
14 renderContent: PropTypes.func.isRequired,
15 renderSectionTitle: PropTypes.func,
16 onChange: PropTypes.func,
17 align: PropTypes.oneOf(['top', 'center', 'bottom']),
18 duration: PropTypes.number,
19 easing: PropTypes.string,
20 initiallyActiveSection: PropTypes.number,
21 activeSection: PropTypes.oneOfType([
22 PropTypes.bool, // if false, closes all sections
23 PropTypes.number, // sets index of section to open
24 ]),
25 underlayColor: PropTypes.string,
26 touchableComponent: PropTypes.func,
27 touchableProps: PropTypes.object,
28 disabled: PropTypes.bool,
29 expandFromBottom: PropTypes.bool,
30 };
31
32 static defaultProps = {
33 underlayColor: 'black',
34 disabled: false,
35 expandFromBottom: false,
36 touchableComponent: TouchableHighlight,
37 renderSectionTitle: () => null,
38 };
39
40 constructor(props) {
41 super(props);
42
43 // if activeSection not specified, default to initiallyActiveSection
44 this.state = {
45 activeSection:
46 props.activeSection !== undefined
47 ? props.activeSection
48 : props.initiallyActiveSection,
49 };
50 }
51
52 componentWillReceiveProps(nextProps) {
53 if (nextProps.activeSection !== undefined) {
54 this.setState({
55 activeSection: nextProps.activeSection,
56 });
57 }
58 }
59
60 _toggleSection(section) {
61 if (!this.props.disabled) {
62 const activeSection =
63 this.state.activeSection === section ? false : section;
64
65 if (this.props.activeSection === undefined) {
66 this.setState({ activeSection });
67 }
68 if (this.props.onChange) {
69 this.props.onChange(activeSection);
70 }
71 }
72 }
73
74 handleErrors = () => {
75 if (!Array.isArray(this.props.sections)) {
76 throw new Error('Sections should be an array');
77 }
78 };
79
80 render() {
81 let viewProps = {};
82 let collapsibleProps = {};
83 Object.keys(this.props).forEach(key => {
84 if (COLLAPSIBLE_PROPS.indexOf(key) !== -1) {
85 collapsibleProps[key] = this.props[key];
86 } else if (VIEW_PROPS.indexOf(key) !== -1) {
87 viewProps[key] = this.props[key];
88 }
89 });
90
91 this.handleErrors();
92
93 const Touchable = this.props.touchableComponent;
94
95 const renderCollapsible = (section, key) => (
96 <Collapsible
97 collapsed={this.state.activeSection !== key}
98 {...collapsibleProps}
99 >
100 {this.props.renderContent(
101 section,
102 key,
103 this.state.activeSection === key,
104 this.props.sections
105 )}
106 </Collapsible>
107 );
108
109 return (
110 <View {...viewProps}>
111 {this.props.sections.map((section, key) => (
112 <View key={key}>
113 {this.props.renderSectionTitle(
114 section,
115 key,
116 this.state.activeSection === key
117 )}
118
119 {this.props.expandFromBottom && renderCollapsible(section, key)}
120
121 <Touchable
122 onPress={() => this._toggleSection(key)}
123 underlayColor={this.props.underlayColor}
124 {...this.props.touchableProps}
125 >
126 {this.props.renderHeader(
127 section,
128 key,
129 this.state.activeSection === key,
130 this.props.sections
131 )}
132 </Touchable>
133
134 {!this.props.expandFromBottom && renderCollapsible(section, key)}
135 </View>
136 ))}
137 </View>
138 );
139 }
140}