|
@@ -0,0 +1,96 @@
|
|
|
+const { cloneElement, Component } = require('preact')
|
|
|
+const classNames = require('classnames')
|
|
|
+
|
|
|
+const transitionName = 'uppy-transition-slideDownUp'
|
|
|
+const duration = 250
|
|
|
+
|
|
|
+/**
|
|
|
+ * Vertical slide transition.
|
|
|
+ *
|
|
|
+ * This can take a _single_ child component, which _must_ accept a `className` prop.
|
|
|
+ *
|
|
|
+ * Currently this is specific to the `uppy-transition-slideDownUp` transition,
|
|
|
+ * but it should be simple to extend this for any type of single-element
|
|
|
+ * transition by setting the CSS name and duration as props.
|
|
|
+ */
|
|
|
+class Slide extends Component {
|
|
|
+ constructor (props) {
|
|
|
+ super(props)
|
|
|
+
|
|
|
+ this.state = {
|
|
|
+ cachedChildren: null,
|
|
|
+ className: ''
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ componentWillUpdate (nextProps) {
|
|
|
+ const { cachedChildren } = this.state
|
|
|
+ const child = nextProps.children[0]
|
|
|
+
|
|
|
+ if (cachedChildren === child) return
|
|
|
+
|
|
|
+ const patch = {
|
|
|
+ cachedChildren: child
|
|
|
+ }
|
|
|
+
|
|
|
+ // Enter transition
|
|
|
+ if (child && !cachedChildren) {
|
|
|
+ patch.className = `${transitionName}-enter`
|
|
|
+
|
|
|
+ cancelAnimationFrame(this.animationFrame)
|
|
|
+ clearTimeout(this.leaveTimeout)
|
|
|
+ this.leaveTimeout = undefined
|
|
|
+
|
|
|
+ this.animationFrame = requestAnimationFrame(() => {
|
|
|
+ // Force it to render before we add the active class
|
|
|
+ this.base.getBoundingClientRect()
|
|
|
+
|
|
|
+ this.setState({
|
|
|
+ className: `${transitionName}-enter ${transitionName}-enter-active`
|
|
|
+ })
|
|
|
+
|
|
|
+ this.enterTimeout = setTimeout(() => {
|
|
|
+ this.setState({ className: '' })
|
|
|
+ }, duration)
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // Leave transition
|
|
|
+ if (cachedChildren && !child && this.leaveTimeout === undefined) {
|
|
|
+ patch.cachedChildren = cachedChildren
|
|
|
+ patch.className = `${transitionName}-leave`
|
|
|
+
|
|
|
+ cancelAnimationFrame(this.animationFrame)
|
|
|
+ clearTimeout(this.enterTimeout)
|
|
|
+ this.enterTimeout = undefined
|
|
|
+ this.animationFrame = requestAnimationFrame(() => {
|
|
|
+ this.setState({
|
|
|
+ className: `${transitionName}-leave ${transitionName}-leave-active`
|
|
|
+ })
|
|
|
+
|
|
|
+ this.leaveTimeout = setTimeout(() => {
|
|
|
+ this.setState({
|
|
|
+ cachedChildren: null,
|
|
|
+ className: ''
|
|
|
+ })
|
|
|
+ }, duration)
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ this.setState(patch)
|
|
|
+ }
|
|
|
+
|
|
|
+ render () {
|
|
|
+ const { cachedChildren, className } = this.state
|
|
|
+
|
|
|
+ if (!cachedChildren) {
|
|
|
+ return null
|
|
|
+ }
|
|
|
+
|
|
|
+ return cloneElement(cachedChildren, {
|
|
|
+ className: classNames(className, cachedChildren.attributes.className)
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+module.exports = Slide
|