UNPKG

@wix/design-system

Version:

@wix/design-system

141 lines 5.51 kB
import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import { st, classes } from './Accordion.st.css.js'; import AccordionItem from './components/AccordionItem'; import { horizontalPaddings, skins } from './constants'; import SectionHeader from '../SectionHeader'; export class Accordion extends PureComponent { constructor(props) { super(props); this._findOpenIndexes = (items = [], initial = false) => { return items .map((item, index) => (initial && item.initiallyOpen) || item.open ? index : null) .filter(index => index !== null) .flatMap(index => (!!index || index === 0 ? [index] : [])); }; this._compareOpenItems = (currentItems = [], prevItems = []) => { if (prevItems.length !== currentItems.length) { return false; } for (let i = 0; i < prevItems.length; i++) { if (prevItems[i].open !== currentItems[i].open) { return false; } } return true; }; this.componentDidUpdate = (prevProps) => { if (!this._compareOpenItems(this.props.items, prevProps.items)) { this.setState({ openIndexes: this._findOpenIndexes(this.props.items), }); } }; this._toggle = (index) => () => this.setState(({ openIndexes }) => ({ openIndexes: openIndexes.includes(index) ? openIndexes.filter(i => i !== index) : this.props.multiple ? [...openIndexes, index] : [index], })); this.state = { openIndexes: this._findOpenIndexes(this.props.items, true), }; } render() { const { openIndexes } = this.state; const { dataHook, items, skin, hideShadow, size, horizontalPadding, contentPadding, transitionSpeed, onAnimationEnter, onAnimationExit, titleSize, } = this.props; return (React.createElement("div", { "data-hook": dataHook, className: classes.accordion, "data-transition-speed": transitionSpeed, "data-horizontal-padding": horizontalPadding, "data-content-padding": contentPadding, "data-skin": skin }, items?.map((item, index, allItems) => { const uncontrolledProps = { onToggle: this._toggle(index), open: openIndexes.includes(index), onAnimationEnter, onAnimationExit, }; const last = index === allItems.length - 1; const internalProps = { className: st(classes.item, { last }), key: item.key || index, skin, hideShadow, size, horizontalPadding, contentPadding, last, transitionSpeed, titleSize, }; if (typeof item.render === 'function') { return item.render(uncontrolledProps, internalProps); } else { return (React.createElement(AccordionItem, { ...uncontrolledProps, ...item, ...internalProps })); } }))); } } Accordion.displayName = 'Accordion'; Accordion.propTypes = { dataHook: PropTypes.string, multiple: PropTypes.bool, skin: PropTypes.oneOf(['standard', 'light', 'neutral']), hideShadow: PropTypes.bool, size: PropTypes.oneOf(['tiny', 'small', 'medium', 'large']), horizontalPadding: PropTypes.oneOf([ 'none', 'tiny', 'small', 'medium', 'large', ]), contentPadding: PropTypes.oneOf(['none']), titleSize: PropTypes.oneOf(['small', 'medium']), transitionSpeed: PropTypes.oneOf(['slow', 'medium', 'fast']), onAnimationEnter: PropTypes.func, onAnimationExit: PropTypes.func, items: PropTypes.oneOfType([ PropTypes.arrayOf(PropTypes.shape({ render: PropTypes.func, })), PropTypes.arrayOf(PropTypes.shape({ title: PropTypes.node, subtitle: PropTypes.node, icon: PropTypes.node, children: PropTypes.node, expandLabel: PropTypes.node, collapseLabel: PropTypes.node, showLabel: PropTypes.oneOf(['hover', 'always']), buttonType: PropTypes.oneOf(['textButton', 'button', 'node']), disabled: PropTypes.bool, onToggle: PropTypes.func, onMouseEnter: PropTypes.func, onMouseleave: PropTypes.func, open: PropTypes.bool, initiallyOpen: PropTypes.bool, })), ]), }; Accordion.defaultProps = { items: [], multiple: false, skin: skins.standard, horizontalPadding: horizontalPaddings.large, hideShadow: false, transitionSpeed: 'medium', size: 'small', titleSize: 'medium', }; export const accordionItemBuilder = (item) => { return { ...item, render: (uncontrolledProps, internalProps) => React.createElement(AccordionItem, { ...uncontrolledProps, ...item, ...internalProps }), }; }; export const accordionSectionItemBuilder = (item) => { return { ...item, render: (_, internalProps) => (React.createElement(SectionHeader, { title: item.title ?? internalProps.title, skin: "neutral" })), }; }; export default Accordion; //# sourceMappingURL=Accordion.js.map