UNPKG

react-beautiful-dnd

Version:

Beautiful, accessible drag and drop for lists with React.js

89 lines (73 loc) 2.45 kB
// @flow import React, { Component, type Element } from 'react'; import type { SpringHelperConfig } from 'react-motion/lib/Types'; import { type Position } from 'css-box-model'; import { Motion, spring } from 'react-motion'; import { isEqual, origin } from '../../state/position'; import { physics } from '../animation'; import type { Props, Speed, DefaultProps } from './moveable-types'; type PositionLike = {| x: any, y: any, |}; type BlockerProps = {| change: Position, children: Position => Element<*>, |}; // Working around react-motion double render issue class DoubleRenderBlocker extends React.Component<BlockerProps> { shouldComponentUpdate(nextProps: BlockerProps): boolean { // let a render go through if not moving anywhere if (isEqual(origin, nextProps.change)) { return true; } // blocking a duplicate change (workaround for react-motion) if (isEqual(this.props.change, nextProps.change)) { return false; } // let everything else through return true; } render() { return this.props.children(this.props.change); } } export default class Moveable extends Component<Props> { /* eslint-disable react/sort-comp */ static defaultProps: DefaultProps = { destination: origin, }; getFinal(): PositionLike { const destination: Position = this.props.destination; const speed: Speed = this.props.speed; if (speed === 'INSTANT') { return destination; } const config: SpringHelperConfig = speed === 'FAST' ? physics.fast : physics.standard; return { x: spring(destination.x, config), y: spring(destination.y, config), }; } render() { const final = this.getFinal(); // bug with react-motion: https://github.com/chenglou/react-motion/issues/437 // even if both defaultStyle and style are {x: 0, y: 0 } if there was // a previous animation it uses the last value rather than the final value return ( <Motion defaultStyle={origin} style={final} onRest={this.props.onMoveEnd}> {(current: { [string]: number }): Element<*> => { const { speed, destination, children } = this.props; const target: Position = speed === 'INSTANT' ? destination : (current: any); return ( <DoubleRenderBlocker change={target}> {children} </DoubleRenderBlocker> ); }} </Motion> ); } }