1 | import React, { Component } from 'react';
|
2 | import PropTypes from 'prop-types';
|
3 | import { View, TouchableHighlight } from 'react-native';
|
4 | import Collapsible from './Collapsible';
|
5 | import { ViewPropTypes } from './config';
|
6 |
|
7 | const COLLAPSIBLE_PROPS = Object.keys(Collapsible.propTypes);
|
8 | const VIEW_PROPS = Object.keys(ViewPropTypes);
|
9 |
|
10 | export 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,
|
23 | PropTypes.number,
|
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 |
|
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 | }
|