Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to make collapse multiple #422

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 9 additions & 2 deletions Accordion.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,22 @@ export interface AccordionProps {
*/
expandFromBottom?: boolean;

/**
* Allow more than one section to be expanded at a time. Defaults to false for legacy behavior.
*
* @default false
*/
expandMultiple?: boolean;

/**
* Set which index in the sections array is initially open. Defaults to none.
*/
initiallyActiveSection?: number;

/**
* Control which index in the sections array is currently open. Defaults to none. If false, closes all sections.
* Control which indices in the sections array are currently open. Defaults to none. If empty, closes all sections.
*/
activeSection?: boolean | number;
activeSections?: Array<number | string>;

/**
* The color of the underlay that will show through when tapping on headers.
Expand Down
53 changes: 31 additions & 22 deletions Accordion.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,25 @@ export default class Accordion extends Component {
duration: PropTypes.number,
easing: PropTypes.string,
initiallyActiveSection: PropTypes.number,
activeSection: PropTypes.oneOfType([
PropTypes.bool, // if false, closes all sections
PropTypes.number, // sets index of section to open
]),
activeSections: PropTypes.oneOf(
PropTypes.arrayOf(PropTypes.number),
PropTypes.string
),
underlayColor: PropTypes.string,
touchableComponent: PropTypes.func,
touchableProps: PropTypes.object,
disabled: PropTypes.bool,
expandFromBottom: PropTypes.bool,
expandMultiple: PropTypes.bool,
onAnimationEnd: PropTypes.func,
};

static defaultProps = {
activeSections: [],
underlayColor: 'black',
disabled: false,
expandFromBottom: false,
expandMultiple: false,
touchableComponent: TouchableHighlight,
renderSectionTitle: () => null,
onAnimationEnd: () => null,
Expand All @@ -42,36 +45,42 @@ export default class Accordion extends Component {
constructor(props) {
super(props);

// if activeSection not specified, default to initiallyActiveSection
// if activeSections not specified, default to initiallyActiveSection
this.state = {
activeSection:
props.activeSection !== undefined
? props.activeSection
: props.initiallyActiveSection,
activeSections:
props.activeSections !== undefined
? props.activeSections
: [props.initiallyActiveSection],
};
}

componentDidUpdate(prevProps) {
if (
this.props.activeSection !== undefined &&
this.props.activeSection !== prevProps.activeSection
this.props.activeSections !== undefined &&
this.props.activeSections !== prevProps.activeSections
) {
this.setState({
activeSection: this.props.activeSection,
activeSections: this.props.activeSections,
});
}
}

_toggleSection(section) {
if (!this.props.disabled) {
const activeSection =
this.state.activeSection === section ? false : section;

if (this.props.activeSection === undefined) {
this.setState({ activeSection });
const baseSet = this.state.activeSections;
const pos = baseSet.indexOf(section);
const activeSections =
pos !== -1
? baseSet.slice(0, pos) + baseSet.slice(pos + 1, baseSet.length)
: this.props.expandMultiple
? this.state.activeSections + [section]
: [section];

if (this.props.activeSections === undefined) {
this.setState({ activeSections });
}
if (this.props.onChange) {
this.props.onChange(activeSection);
this.props.onChange(activeSections);
}
}
}
Expand Down Expand Up @@ -99,14 +108,14 @@ export default class Accordion extends Component {

const renderCollapsible = (section, key) => (
<Collapsible
collapsed={this.state.activeSection !== key}
collapsed={this.state.activeSections.indexOf(key) === -1}
{...collapsibleProps}
onAnimationEnd={() => this.props.onAnimationEnd(section, key)}
>
{this.props.renderContent(
section,
key,
this.state.activeSection === key,
this.state.activeSections.indexOf(key) !== -1,
this.props.sections
)}
</Collapsible>
Expand All @@ -119,7 +128,7 @@ export default class Accordion extends Component {
{this.props.renderSectionTitle(
section,
key,
this.state.activeSection === key
this.state.activeSections.indexOf(key) !== -1
)}

{this.props.expandFromBottom && renderCollapsible(section, key)}
Expand All @@ -132,7 +141,7 @@ export default class Accordion extends Component {
{this.props.renderHeader(
section,
key,
this.state.activeSection === key,
this.state.activeSections.indexOf(key) !== -1,
this.props.sections
)}
</Touchable>
Expand Down
15 changes: 8 additions & 7 deletions Example/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,16 @@ const SELECTORS = [

export default class App extends Component {
state = {
activeSection: false,
activeSections: [],
collapsed: true,
};

toggleExpanded = () => {
this.setState({ collapsed: !this.state.collapsed });
};

setSection = section => {
this.setState({ activeSection: section });
setSections = sections => {
this.setState({ activeSections: sections });
};

renderHeader = (section, _, isActive) => {
Expand Down Expand Up @@ -96,12 +96,12 @@ export default class App extends Component {
{SELECTORS.map(selector => (
<TouchableOpacity
key={selector.title}
onPress={() => this.setSection(selector.value)}
onPress={() => this.setSections([selector.value])}
>
<View style={styles.selector}>
<Text
style={
selector.value === this.state.activeSection &&
this.state.activeSections.indexOf(selector.value) !== -1 &&
styles.activeSelector
}
>
Expand All @@ -126,13 +126,14 @@ export default class App extends Component {
</View>
</Collapsible>
<Accordion
activeSection={this.state.activeSection}
activeSections={this.state.activeSections}
sections={CONTENT}
touchableComponent={TouchableOpacity}
expandMultiple={true}
renderHeader={this.renderHeader}
renderContent={this.renderContent}
duration={400}
onChange={this.setSection}
onChange={this.setSections}
/>
</View>
);
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ import Accordion from 'react-native-collapsible/Accordion';
| **`renderSectionTitle(content, index, isActive)`** | A function that should return a renderable representing the title of the section outside the touchable element |
| **`onChange(index)`** | An optional function that is called when currently active section is changed, `index === false` when collapsed |
| **`initiallyActiveSection`** | Set which index in the `sections` array is initially open. Defaults to none. |
| **`activeSection`** | Control which index in the `sections` array is currently open. Defaults to none. If false, closes all sections. |
| **`activeSections`** | Control which indices in the `sections` array are currently open. Defaults to empty array. If empty, closes all sections. |
| **`underlayColor`** | The color of the underlay that will show through when tapping on headers. Defaults to black. |
| **`touchableComponent`** | The touchable component used in the Accordion. Defaults to `TouchableHighlight` |
| **`touchableProps`** | Properties for the `touchableComponent` |
Expand All @@ -65,6 +65,7 @@ import Accordion from 'react-native-collapsible/Accordion';
| **`easing`** | See `Collapsible` |
| **`onAnimationEnd(key, index)`** | See `Collapsible`. |
| **`expandFromBottom`** | Expand content from the bottom instead of the top |
| **`expandMultiple`** | Allow more than one section to be expanded. Defaults to false.

## Demo

Expand Down