Skip to content
This repository was archived by the owner on Apr 14, 2020. It is now read-only.

Commit 143a40a

Browse files
author
Michael Dougall
committed
fix(motion): fixes motions flickering when animating and images having dimensions of zero
1 parent ef9cfb6 commit 143a40a

3 files changed

Lines changed: 41 additions & 33 deletions

File tree

packages/core/src/Motion/__snapshots__/test.tsx.snap

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ You're switching between persisted and unpersisted, don't do this. Either always
99
exports[`<Motion /> self targetted motions should throw when changing into "triggerSelfKey" after initial mount 1`] = `
1010
"@element-motion/core v0.0.0
1111
12-
You're switching between self triggering modes, don't do this. Either always set the \\"triggerSelfKey\\" prop, or keep as undefined."
12+
You're switching between self triggering modes, don't do this. Either always set the \\"triggerSelfKey\\" prop or keep as undefined."
1313
`;
1414

1515
exports[`<Motion /> self targetted motions should throw when using both "in" and "triggerSelfKey" props after initial mount 1`] = `
@@ -22,7 +22,7 @@ exports[`<Motion /> should pass dom data to child motion 1`] = `
2222
Array [
2323
Object {
2424
"destination": Object {
25-
"element": undefined,
25+
"element": <div />,
2626
"elementBoundingBox": Object {
2727
"location": Object {
2828
"left": 0,
@@ -40,7 +40,7 @@ Array [
4040
},
4141
"focalTargetElement": undefined,
4242
"focalTargetElementBoundingBox": undefined,
43-
"render": undefined,
43+
"render": [Function],
4444
},
4545
"origin": Object {
4646
"element": <div />,
@@ -71,7 +71,7 @@ exports[`<Motion /> should pass dom data to child motion when using in prop 1`]
7171
Array [
7272
Object {
7373
"destination": Object {
74-
"element": undefined,
74+
"element": <div />,
7575
"elementBoundingBox": Object {
7676
"location": Object {
7777
"left": 0,
@@ -89,7 +89,7 @@ Array [
8989
},
9090
"focalTargetElement": undefined,
9191
"focalTargetElementBoundingBox": undefined,
92-
"render": undefined,
92+
"render": [Function],
9393
},
9494
"origin": Object {
9595
"element": <div />,

packages/core/src/Motion/index.tsx

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import Collector, {
1111
MotionData,
1212
MotionCallback,
1313
} from '../Collector';
14-
import { getElementBoundingBox } from '../lib/dom';
14+
import { getElementBoundingBox, eventListener } from '../lib/dom';
1515
import defer from '../lib/defer';
1616
import noop from '../lib/noop';
1717
import { throwIf, warn } from '../lib/log';
@@ -57,9 +57,17 @@ export default class Motion extends React.PureComponent<MotionProps, MotionState
5757
);
5858
}
5959

60-
if (componentIn === undefined && store.has(name)) {
60+
if (this.element && componentIn === undefined && store.has(name)) {
6161
// A child has already been stored, so this is probably the matching pair.
62-
this.execute();
62+
if (this.element.tagName === 'IMG' && !(this.element as HTMLImageElement).complete) {
63+
const remove = eventListener(this.element, 'load', () => {
64+
remove();
65+
this.execute();
66+
});
67+
} else {
68+
this.execute();
69+
}
70+
6371
return;
6472
}
6573

@@ -111,7 +119,7 @@ export default class Motion extends React.PureComponent<MotionProps, MotionState
111119
throwIf(
112120
(this.props.triggerSelfKey === undefined || prevProps.triggerSelfKey === undefined) &&
113121
!triggerSelfKeyPropSame,
114-
`You're switching between self triggering modes, don't do this. Either always set the "triggerSelfKey" prop, or keep as undefined.`
122+
`You're switching between self triggering modes, don't do this. Either always set the "triggerSelfKey" prop or keep as undefined.`
115123
);
116124
}
117125

@@ -127,12 +135,8 @@ export default class Motion extends React.PureComponent<MotionProps, MotionState
127135
}
128136

129137
if (!triggerSelfKeyPropSame) {
130-
// Defer execution to the next frame to capture correctly.
131-
// Make sure to keep react state the same for any inflight motions to be captured correctly.
132-
requestAnimationFrame(() => {
133-
this.cancel();
134-
this.execute(DOMSnapshot);
135-
});
138+
this.cancel();
139+
this.execute(DOMSnapshot);
136140
}
137141
}
138142

@@ -190,8 +194,8 @@ export default class Motion extends React.PureComponent<MotionProps, MotionState
190194
: undefined;
191195

192196
if (process.env.NODE_ENV === 'development' && elementBoundingBox.size.height === 0) {
193-
warn(`Your target child had a height of zero when capturing it's DOM data. This may affect the motion.
194-
If it's an image, try and have the image loaded before mounting, or set a static height.`);
197+
warn(`Your origin element had a height of zero when capturing it's DOM data. This may affect the motion.
198+
If it's an image, try and have the image loaded before mounting or set a static height.`);
195199
}
196200

197201
const { name } = this.props;
@@ -244,6 +248,14 @@ If it's an image, try and have the image loaded before mounting, or set a static
244248
},
245249
};
246250

251+
if (
252+
process.env.NODE_ENV === 'development' &&
253+
motionData.destination.elementBoundingBox.size.height === 0
254+
) {
255+
warn(`Your destination element had a height of zero when capturing it's DOM data. This may affect the motion.
256+
If it's an image, try and have the image loaded before mounting or set a static height.`);
257+
}
258+
247259
// Loads each action up in an easy-to-execute format.
248260
const actions = collectorData.map((targetData, index) => {
249261
if (targetData.action !== CollectorActions.motion) {
@@ -260,19 +272,15 @@ If it's an image, try and have the image loaded before mounting, or set a static
260272
container.insertBefore(elementToMountChildren, container.firstChild);
261273
}
262274

263-
// This ensures that if there was an update to the jsx that is animating it changes next frame.
264-
// Resulting in the transition _actually_ happening.
265-
requestAnimationFrame(() => {
266-
if (elementToMountChildren) {
267-
this.setState(prevState => {
268-
const markup = prevState.motionsMarkup.concat();
269-
markup[index] = createPortal(jsx, elementToMountChildren!);
270-
return {
271-
motionsMarkup: markup,
272-
};
273-
});
274-
}
275-
});
275+
if (elementToMountChildren) {
276+
this.setState(prevState => {
277+
const markup = prevState.motionsMarkup.concat();
278+
markup[index] = createPortal(jsx, elementToMountChildren!);
279+
return {
280+
motionsMarkup: markup,
281+
};
282+
});
283+
}
276284
};
277285

278286
const setChildProps = (props: TargetPropsFunc | null) => {

packages/core/src/Motion/test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ describe('<Motion />', () => {
8181
}
8282
to={
8383
<Motion name="anim-0" onFinish={done}>
84-
<div />
84+
{motion => <div {...motion} />}
8585
</Motion>
8686
}
8787
start={false}
@@ -108,7 +108,7 @@ describe('<Motion />', () => {
108108
}
109109
to={
110110
<Motion name="anim-1" onFinish={deferred.resolve}>
111-
<div />
111+
{motion => <div {...motion} />}
112112
</Motion>
113113
}
114114
start={false}
@@ -138,7 +138,7 @@ describe('<Motion />', () => {
138138
)}
139139
to={
140140
<Motion name="anim-aa" onFinish={deferred.resolve}>
141-
<div />
141+
{motion => <div {...motion} />}
142142
</Motion>
143143
}
144144
start={false}

0 commit comments

Comments
 (0)