@shopify/polaris
Version:
Shopify’s product component library
155 lines (132 loc) • 4.14 kB
JavaScript
import { objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
import React$1, { Component, createRef, createContext } from 'react';
import { classNames } from '../../utilities/css.js';
import styles from './Collapsible.scss.js';
var ParentCollapsibleExpandingContext = /*#__PURE__*/createContext(false);
class CollapsibleInner extends Component {
constructor(...args) {
super(...args);
this.context = void 0;
this.state = {
height: null,
animationState: 'idle',
// eslint-disable-next-line react/no-unused-state
open: this.props.open
};
this.node = /*#__PURE__*/createRef();
this.heightNode = /*#__PURE__*/createRef();
this.handleTransitionEnd = event => {
var {
target
} = event;
if (target === this.node.current) {
this.setState({
animationState: 'idle',
height: null
});
}
};
}
static getDerivedStateFromProps({
open: willOpen
}, {
open,
animationState: prevAnimationState
}) {
var nextAnimationState = prevAnimationState;
if (open !== willOpen) {
nextAnimationState = 'measuring';
}
return {
animationState: nextAnimationState,
open: willOpen
};
}
componentDidUpdate({
open: wasOpen
}) {
var {
animationState
} = this.state;
var parentCollapsibleExpanding = this.context;
if (parentCollapsibleExpanding && animationState !== 'idle') {
// eslint-disable-next-line react/no-did-update-set-state
this.setState({
animationState: 'idle'
});
return;
}
requestAnimationFrame(() => {
var heightNode = this.heightNode.current;
switch (animationState) {
case 'idle':
break;
case 'measuring':
this.setState({
animationState: wasOpen ? 'closingStart' : 'openingStart',
height: wasOpen && heightNode ? heightNode.scrollHeight : 0
});
break;
case 'closingStart':
this.setState({
animationState: 'closing',
height: 0
});
break;
case 'openingStart':
this.setState({
animationState: 'opening',
height: heightNode ? heightNode.scrollHeight : 0
});
}
});
}
render() {
var {
id,
expandOnPrint,
open,
children,
transition
} = this.props;
var {
animationState,
height
} = this.state;
var parentCollapsibleExpanding = this.context;
var animating = animationState !== 'idle';
var wrapperClassName = classNames(styles.Collapsible, open && styles.open, animating && styles.animating, !animating && open && styles.fullyOpen, expandOnPrint && styles.expandOnPrint);
var displayHeight = collapsibleHeight(open, animationState, height);
var content = animating || open || expandOnPrint ? children : null;
var transitionProperties = transition ? {
transitionDuration: "".concat(transition.duration),
transitionTimingFunction: "".concat(transition.timingFunction)
} : null;
return /*#__PURE__*/React$1.createElement(ParentCollapsibleExpandingContext.Provider, {
value: parentCollapsibleExpanding || open && animationState !== 'idle'
}, /*#__PURE__*/React$1.createElement("div", {
id: id,
"aria-hidden": !open,
style: _objectSpread2({
maxHeight: "".concat(displayHeight)
}, transitionProperties),
className: wrapperClassName,
ref: this.node,
onTransitionEnd: this.handleTransitionEnd
}, /*#__PURE__*/React$1.createElement("div", {
ref: this.heightNode
}, content)));
}
}
CollapsibleInner.contextType = ParentCollapsibleExpandingContext;
function collapsibleHeight(open, animationState, height) {
if (animationState === 'idle' && open) {
return open ? 'none' : undefined;
}
if (animationState === 'measuring') {
return open ? undefined : 'none';
}
return "".concat(height || 0, "px");
}
var Collapsible = CollapsibleInner;
export { Collapsible };