diff --git a/src/state/create-store.js b/src/state/create-store.js index 37978f1c2d..8a8bb5cc4d 100644 --- a/src/state/create-store.js +++ b/src/state/create-store.js @@ -41,11 +41,11 @@ export default ({ // > uncomment to use // debugging logger - // require('./debug-middleware/log-middleware').default, + require('./debug-middleware/log-middleware').default, // debugging timer // require('./debug-middleware/timing-middleware').default, // average action timer - require('./debug-middleware/timing-average-middleware').default(500), + // require('./debug-middleware/timing-average-middleware').default(500), // ## Application middleware diff --git a/src/state/debug-middleware/log-middleware.js b/src/state/debug-middleware/log-middleware.js index 7862d18730..76a0f0a16d 100644 --- a/src/state/debug-middleware/log-middleware.js +++ b/src/state/debug-middleware/log-middleware.js @@ -1,16 +1,14 @@ // @flow /* eslint-disable no-console */ -import type { Store, Action, State } from '../../types'; +import type { Store, Action } from '../../types'; export default (store: Store) => (next: (Action) => mixed) => (action: Action): mixed => { console.group(`action: ${action.type}`); - const before: State = store.getState(); + console.log('state before', store.getState()); const result: mixed = next(action); - const after: State = store.getState(); - - console.log('state', { before, after }); + console.log('state after', store.getState()); console.groupEnd(); return result; diff --git a/src/state/get-drag-impact/in-home-list.js b/src/state/get-drag-impact/in-home-list.js index 8e13a11fd8..67e1372414 100644 --- a/src/state/get-drag-impact/in-home-list.js +++ b/src/state/get-drag-impact/in-home-list.js @@ -45,10 +45,6 @@ export default ({ const isBeyondStartPosition: boolean = currentCenter[axis.line] - originalCenter[axis.line] > 0; - console.log('original center', originalCenter); - console.log('current center', currentCenter); - console.log('isBeyondStartPosition', isBeyondStartPosition); - // Amount to move needs to include the margins const amount: Position = patch(axis.line, draggable.client.marginBox[axis.size]); @@ -90,23 +86,18 @@ export default ({ const ordered: Displacement[] = isBeyondStartPosition ? displaced.reverse() : displaced; const index: number = (() => { const startIndex = insideHome.indexOf(draggable); - console.log('start index', startIndex); const length: number = ordered.length; if (!length) { return startIndex; } if (isBeyondStartPosition) { - console.log('is beyond start position'); return startIndex + length; } // is moving backwards - console.log('moving backwards yolo'); return startIndex - length; })(); - console.log('calculated index', index); - const movement: DragMovement = { amount, displaced: ordered, diff --git a/src/state/middleware/auto-scroll.js b/src/state/middleware/auto-scroll.js index 53ea92c219..8c6d9e2b97 100644 --- a/src/state/middleware/auto-scroll.js +++ b/src/state/middleware/auto-scroll.js @@ -32,7 +32,9 @@ export default (getMarshal: () => DimensionMarshal) => const shouldCancel = (action: Action) => // Need to cancel any pending auto scrolling when drag is ending action.type === 'CANCEL' || + action.type === 'DROP_ANIMATE' || action.type === 'DROP' || + action.type === 'DROP_COMPLETE' || // A new bulk collection is starting - cancel any pending auto scrolls action.type === 'BULK_COLLECTION_STARTING'; diff --git a/src/state/reducer.js b/src/state/reducer.js index da547a1ea1..607e5a76a2 100644 --- a/src/state/reducer.js +++ b/src/state/reducer.js @@ -278,7 +278,6 @@ export default (state: State = idle, action: Action): State => { }, }; - console.log('center diff', centerDiff); const newCurrentOffset: Position = subtract(state.current.client.offset, centerDiff); const current: DragPositions = (() => { diff --git a/src/view/drag-drop-context/drag-drop-context.jsx b/src/view/drag-drop-context/drag-drop-context.jsx index 574addca54..9454ce002b 100644 --- a/src/view/drag-drop-context/drag-drop-context.jsx +++ b/src/view/drag-drop-context/drag-drop-context.jsx @@ -1,6 +1,5 @@ // @flow import React, { type Node } from 'react'; -import { type Position } from 'css-box-model'; import { bindActionCreators } from 'redux'; import PropTypes from 'prop-types'; import createStore from '../../state/create-store'; @@ -53,7 +52,7 @@ export const resetServerContext = () => { resetStyleContext(); }; -const printFatalError = (error: Error) => { +const printFatalDevError = (error: Error) => { if (process.env.NODE_ENV !== 'production') { console.warn(` An error has occurred while a drag is occurring. @@ -140,12 +139,23 @@ export default class DragDropContext extends React.Component { // This is useful when the user canLift = (id: DraggableId) => canStartDrag(this.store.getState(), id); - // TODO: needed? + componentDidMount() { + window.addEventListener('error', this.onWindowError); + this.styleMarshal.mount(); + this.announcer.mount(); + } + componentDidCatch(error: Error) { - printFatalError(error); + printFatalDevError(error); this.store.dispatch(clean()); - // Not swallowing the error - letting it pass through + // If the failure was due to an invariant failure - then we handle the error + if (error.message.indexOf('Invariant failed') !== -1) { + this.setState({}); + return; + } + + // Error is more serious and we throw it throw error; } @@ -156,21 +166,18 @@ export default class DragDropContext extends React.Component { return; } - printFatalError(error); - + printFatalDevError(error); this.store.dispatch(clean()); } - componentDidMount() { - window.addEventListener('error', this.onWindowError); - this.styleMarshal.mount(); - this.announcer.mount(); - } - componentWillUnmount() { window.addEventListener('error', this.onWindowError); - // TODO: is this the right way to cleanup? - this.store.dispatch(clean()); + + const state: State = this.store.getState(); + if (state.phase !== 'IDLE') { + this.store.dispatch(clean()); + } + this.styleMarshal.unmount(); this.announcer.unmount(); } diff --git a/src/view/draggable-dimension-publisher/draggable-dimension-publisher.jsx b/src/view/draggable-dimension-publisher/draggable-dimension-publisher.jsx index 83779ba699..69ff63f60b 100644 --- a/src/view/draggable-dimension-publisher/draggable-dimension-publisher.jsx +++ b/src/view/draggable-dimension-publisher/draggable-dimension-publisher.jsx @@ -91,7 +91,6 @@ export default class DraggableDimensionPublisher extends Component { getDimension = (windowScroll: Position): DraggableDimension => { const targetRef: ?HTMLElement = this.props.getDraggableRef(); const placeholderRef: ?HTMLElement = this.props.getPlaceholderRef(); - console.log('placeholderRef', placeholderRef); const descriptor: ?DraggableDescriptor = this.publishedDescriptor; invariant(targetRef, 'DraggableDimensionPublisher cannot calculate a dimension when not attached to the DOM'); diff --git a/src/view/draggable/draggable.jsx b/src/view/draggable/draggable.jsx index b4a67881f1..5f2d0c64ac 100644 --- a/src/view/draggable/draggable.jsx +++ b/src/view/draggable/draggable.jsx @@ -207,6 +207,7 @@ export default class Draggable extends Component { isDropAnimating: boolean, movementStyle: MovementStyle): DraggingStyle => { const box: BoxModel = dimension.client; + // const { width, height, top, left } = dimension.client.borderBox; // For an explanation of properties see `draggable-types`. const style: DraggingStyle = { @@ -387,6 +388,7 @@ export default class Draggable extends Component { speed={speed} destination={offset} onMoveEnd={this.onMoveEnd} + draggableId={draggableId} > {(movementStyle: MovementStyle) => ( { hidePlaceholder = () => { const placeholder: ?Placeholder = this.props.getPlaceholder(); - console.log('hide', placeholder); if (placeholder) { placeholder.hide(); @@ -165,7 +164,6 @@ export default class DroppableDimensionPublisher extends Component { showPlaceholder = () => { const placeholder: ?Placeholder = this.props.getPlaceholder(); - console.log('show', placeholder); if (placeholder) { placeholder.show(); diff --git a/src/view/moveable/moveable.jsx b/src/view/moveable/moveable.jsx index ca169bf86b..8352aef894 100644 --- a/src/view/moveable/moveable.jsx +++ b/src/view/moveable/moveable.jsx @@ -1,5 +1,6 @@ // @flow import React, { Component } from 'react'; +import memoizeOne from 'memoize-one'; import { type Position } from 'css-box-model'; import { Motion, spring } from 'react-motion'; import { physics } from '../animation'; @@ -15,28 +16,16 @@ const origin: Position = { y: 0, }; -const noMovement: Style = { +const noTransition: Style = { transform: null, }; -const isAtOrigin = (point: PositionLike): boolean => - point.x === origin.x && point.y === origin.y; - -const getStyle = (isNotMoving: boolean, x: number, y: number): Style => { - if (isNotMoving) { - return noMovement; - } +const getTranslate = memoizeOne((x: number, y: number): Style => ({ + transform: `translate(${x}px, ${y}px)`, +})); - const point: Position = { x, y }; - // not applying any transforms when not moving - if (isAtOrigin(point)) { - return noMovement; - } - const style: Style = { - transform: `translate(${point.x}px, ${point.y}px)`, - }; - return style; -}; +const isAtOrigin = (point: { [string]: number }): boolean => + point.x === origin.x && point.y === origin.y; export default class Movable extends Component { /* eslint-disable react/sort-comp */ @@ -83,17 +72,34 @@ export default class Movable extends Component { // 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 - const isNotMoving: boolean = isAtOrigin(final); + const isMovingToOrigin: boolean = isAtOrigin(final); return ( // Expecting a flow error // React Motion type: children: (interpolatedStyle: PlainStyle) => ReactElement // Our type: children: (Position) => (Style) => React.Node - {(current: { [string]: number }): any => - this.props.children( - getStyle(isNotMoving, current.x, current.y) - )} + {(current: { [string]: number }): any => { + // If moving to the origin we can just clear the transition + if (isMovingToOrigin) { + return this.props.children(noTransition); + } + + // Rather than having a translate of 0px, 0px we just clear the transition + if (isAtOrigin(current)) { + return this.props.children(noTransition); + } + + // If moving instantly then we can just move straight to the destination + // Sadly react-motion does a double call in this case so we need to explictly control this + if (this.props.speed === 'INSTANT') { + return this.props.children( + getTranslate(this.props.destination.x, this.props.destination.y) + ); + } + + return this.props.children(getTranslate(current.x, current.y)); + }} ); }