Skip to content

Commit

Permalink
stable base
Browse files Browse the repository at this point in the history
  • Loading branch information
alexreardon committed Jun 22, 2018
1 parent 1eb695d commit 48e86ac
Show file tree
Hide file tree
Showing 5 changed files with 262 additions and 37 deletions.
2 changes: 1 addition & 1 deletion src/state/create-store.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export default ({
// debugging timer
// require('./debug-middleware/action-timing-middleware').default,
// average action timer
// require('./debug-middleware/action-timing-average-middleware').default(500),
require('./debug-middleware/action-timing-average-middleware').default(500),

// ## Application middleware

Expand Down
6 changes: 3 additions & 3 deletions src/view/draggable/draggable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -287,14 +287,14 @@ export default class Draggable extends Component<Props> {
return 'STANDARD';
}

// if dragging and can animate - then move quickly
if (isDragging && shouldAnimateDragMovement) {
return 'FAST';
}

// Animation taken care of by css
// Animating taken care of by CSS or not at all
return 'INSTANT';
})
}
)

renderChildren = (movementStyle: MovementStyle, dragHandleProps: ?DragHandleProps): ?Node => {
const {
Expand Down
126 changes: 126 additions & 0 deletions src/view/moveable/moveable.draft.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// @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';
import type { Props, DefaultProps, Style } from './moveable-types';

type PositionLike = {|
x: any,
y: any,
|};

const origin: Position = {
x: 0,
y: 0,
};

const noTransition: Style = {
transform: null,
};

const isAtOrigin = (x: mixed, y: mixed): boolean =>
x === origin.x && y === origin.y;

export default class Movable extends Component<Props> {
/* eslint-disable react/sort-comp */

static defaultProps: DefaultProps = {
destination: origin,
}
/* eslint-enable */

onRest = () => {
const { onMoveEnd } = this.props;

if (!onMoveEnd) {
return;
}

// This needs to be async otherwise Motion will not re-execute if
// offset or start change

// Could check to see if another move has started
// and abort the previous onMoveEnd
setTimeout(onMoveEnd);
}

getTranslate = memoizeOne((x: number, y: number): Style => ({
transform: `translate(${x}px, ${y}px)`,
}))

getFinal = (): PositionLike => {
const destination: Position = this.props.destination;
const speed = this.props.speed;

if (speed === 'INSTANT') {
return destination;
}

const selected = speed === 'FAST' ? physics.fast : physics.standard;

return {
x: spring(destination.x, selected),
y: spring(destination.y, selected),
};
}

// renderChildren = (current: { [string]: number }): any => {
// const destination: Position = this.props.destination;
// // 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(
// this.getTranslate(destination.x, destination.y)
// );
// }

// // If moving to the origin we can just clear the transition
// if (isAtOrigin(current)) {
// return this.props.children(noTransition);
// }

// // Rather than having a translate of 0px, 0px we just clear the transition
// if (isAtOrigin(destination)) {
// return this.props.children(noTransition);
// }

// return this.props.children(this.getTranslate(current.x, current.y));
// }

render() {
const final: PositionLike = this.getFinal();
const { speed, destination } = this.props;
const shouldIgnore: boolean = speed === 'INSTANT' && isAtOrigin(destination);

// 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 isMovingToOrigin: boolean = isAtOrigin(final);

return (
<Motion defaultStyle={origin} style={final} onRest={this.onRest}>
{(current: { [string]: number }): any => {
// the default for Draggables
if (shouldIgnore) {
return this.props.children(noTransition);
}

if (speed === 'INSTANT') {
return this.props.children(
this.getTranslate(destination.x, destination.y)
);
}
// Rather than having a translate of 0px, 0px we just clear the transition
// If moving to the origin we can just clear the transition
if (isAtOrigin(current)) {
return this.props.children(noTransition);
}

return this.props.children(this.getTranslate(current.x, current.y));
}}
</Motion>
);
}
}
64 changes: 31 additions & 33 deletions src/view/moveable/moveable.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @flow
import React, { Component } from 'react';
import memoizeOne from 'memoize-one';
import type { SpringHelperConfig } from 'react-motion/lib/Types';
import { type Position } from 'css-box-model';
import { Motion, spring } from 'react-motion';
import { physics } from '../animation';
Expand All @@ -16,17 +16,29 @@ const origin: Position = {
y: 0,
};

const noTransition: Style = {
const noMovement: Style = {
transform: null,
};

const getTranslate = memoizeOne((x: number, y: number): Style => ({
transform: `translate(${x}px, ${y}px)`,
}));

const isAtOrigin = (point: { [string]: number }): boolean =>
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 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;
};

export default class Movable extends Component<Props> {
/* eslint-disable react/sort-comp */

Expand All @@ -47,7 +59,7 @@ export default class Movable extends Component<Props> {

// Could check to see if another move has started
// and abort the previous onMoveEnd
setTimeout(onMoveEnd);
setTimeout(() => onMoveEnd());
}

getFinal = (): PositionLike => {
Expand All @@ -58,11 +70,11 @@ export default class Movable extends Component<Props> {
return destination;
}

const selected = speed === 'FAST' ? physics.fast : physics.standard;
const config: SpringHelperConfig = speed === 'FAST' ? physics.fast : physics.standard;

return {
x: spring(destination.x, selected),
y: spring(destination.y, selected),
x: spring(destination.x, config),
y: spring(destination.y, config),
};
}

Expand All @@ -72,31 +84,17 @@ export default class Movable extends Component<Props> {
// 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 isMovingToOrigin: boolean = isAtOrigin(final);
const isNotMoving: boolean = isAtOrigin(final);

return (
// Expecting a flow error
// React Motion type: children: (interpolatedStyle: PlainStyle) => ReactElement
// Our type: children: (Position) => (Style) => React.Node
<Motion defaultStyle={origin} style={final} onRest={this.onRest}>
{(current: { [string]: number }): any => {
// 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)
);
}

// 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);
}

return this.props.children(getTranslate(current.x, current.y));
}}
{(current: { [string]: number }): any =>
this.props.children(
getStyle(isNotMoving, current.x, current.y)
)}
</Motion>
);
}
Expand Down
101 changes: 101 additions & 0 deletions src/view/moveable/moveable.old.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// @flow
import React, { Component } from 'react';
import type { SpringHelperConfig } from 'react-motion/lib/Types';
import { type Position } from 'css-box-model';
import { Motion, spring } from 'react-motion';
import { physics } from '../animation';
import type { Props, DefaultProps, Style } from './moveable-types';

type PositionLike = {|
x: any,
y: any,
|};

const origin: Position = {
x: 0,
y: 0,
};

const noMovement: 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 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;
};

export default class Movable extends Component<Props> {
/* eslint-disable react/sort-comp */

static defaultProps: DefaultProps = {
destination: origin,
}
/* eslint-enable */

onRest = () => {
const { onMoveEnd } = this.props;

if (!onMoveEnd) {
return;
}

// This needs to be async otherwise Motion will not re-execute if
// offset or start change

// Could check to see if another move has started
// and abort the previous onMoveEnd
setTimeout(() => onMoveEnd());
}

getFinal = (): PositionLike => {
const destination: Position = this.props.destination;
const 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
const isNotMoving: boolean = isAtOrigin(final);

return (
// Expecting a flow error
// React Motion type: children: (interpolatedStyle: PlainStyle) => ReactElement
// Our type: children: (Position) => (Style) => React.Node
<Motion defaultStyle={origin} style={final} onRest={this.onRest}>
{(current: { [string]: number }): any =>
this.props.children(
getStyle(isNotMoving, current.x, current.y)
)}
</Motion>
);
}
}

0 comments on commit 48e86ac

Please sign in to comment.