Skip to content

Commit

Permalink
latest
Browse files Browse the repository at this point in the history
  • Loading branch information
mattgperry committed Apr 12, 2018
1 parent f0888fb commit 6965721
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 93 deletions.
7 changes: 7 additions & 0 deletions packages/react-pose/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

React Pose adheres to [Semantic Versioning](http://semver.org/).

## [1.5.0] 2018-04-12

### Added

- `posed(Component)` via [Jess Telford](https://twitter.com/jesstelford)
- React < 16.3 compatibility

## [1.4.0] 2018-04-11

### Added
Expand Down
14 changes: 7 additions & 7 deletions packages/react-pose/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions packages/react-pose/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-pose",
"version": "1.4.0",
"version": "1.5.0",
"description": "A declarative animation library for React",
"main": "lib/index.js",
"types": "./lib/index.d.ts",
Expand Down Expand Up @@ -43,7 +43,7 @@
},
"dependencies": {
"popmotion-pose": "^1.3.0",
"react-lifecycles-compat": "^1.1.0"
"react-lifecycles-compat": "^1.1.4"
},
"unpkg": "./dist/react-pose.js",
"prettier": {
Expand Down
100 changes: 21 additions & 79 deletions packages/react-pose/src/components/PoseElement.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as React from 'react';
import { createContext, createElement } from 'react';
import reactLifecyclesCompat = require('react-lifecycles-compat');
import poseFactory, { Poser, PoserProps } from 'popmotion-pose';
import {
ChildRegistration,
Expand All @@ -9,33 +8,10 @@ import {
PoseElementProps,
PopStyle
} from './PoseElement.types';
import reactLifecyclePolyfill = require('react-lifecycles-compat');

export const PoseParentContext = createContext({});

// Future enhancement: Memoize these functions for speed
function isReactComponent(component) {
let proto;

try {
// Must use getPrototypeOf to capture the case where Proxy components are
// used (they don't have a `.prototype`)
proto = component.prototype || Object.getPrototypeOf(component);
} catch {
// getPrototypeOf will throw in ES5, so we return early here
return false;
}

return 'isReactComponent' in proto;
}

function isStatelessFunctionalComponent(component) {
return typeof component === 'function' && !isReactComponent(component);
}

function isDOMPrimitiveComponent(component) {
return typeof component === 'string';
}

const calcPopFromFlowStyle = (el: HTMLElement): PopStyle => {
const { offsetTop, offsetLeft, offsetWidth, offsetHeight } = el;

Expand Down Expand Up @@ -145,6 +121,22 @@ class PoseElement extends React.PureComponent<PoseElementProps> {
this.popStyle = null;
}

/**
* We need to get a ref to the underlying DOM element. Styled Components and
* other libraries use `innerRef`, though this will be swallowed if the
* styled component is not a primitive (ie styled(Component)).
*
* Instead we pass another function, `hostRef`, as recommended by Facebook
* https://github.com/facebook/react/issues/11401
*
* We also only pass `ref` to DOM primitive components.
*/
if (typeof elementType === 'string') {
props.ref = this.setRef;
} else {
props.innerRef = props.hostRef = this.setRef;
}

// Deprecated for 2.0.0
// If this is a function, it's intended for the DOM element
if (typeof onChange === 'function') props.onChange = onChange;
Expand All @@ -154,30 +146,8 @@ class PoseElement extends React.PureComponent<PoseElementProps> {

setRef = (ref: Element) => {
const { innerRef } = this.props;

if (innerRef) {
// The parent component which set `innerRef` is interested in the
// immediately wrapped component, not necessarily the forwarded refs from
// children.
if (isDOMPrimitiveComponent(this.props.elementType)) {
// If the posed element is a DOM primitive, then we always pass the ref
// back
innerRef(ref);
} else if (!ref || isReactComponent(ref)) {
// Otherwise, we only pass the ref back if it's _not_ the forwarded
// ref (which would point to a DOM element)
innerRef(ref);
}
}

// In the `render()` function, we are setting both `ref` and `innerRef`.
// We're only interested in the thing that results in a DOM node here, so we
// only set the ref when we know what we got back was a DOM node.
// NOTE: We don't check for a functional component here since it's not
// possible to set a `ref` on one
if (!ref || (!isReactComponent(ref) && !isStatelessFunctionalComponent(ref))) {
this.ref = ref;
}
if (innerRef) innerRef(ref);
this.ref = ref;
};

componentDidMount() {
Expand Down Expand Up @@ -229,7 +199,6 @@ class PoseElement extends React.PureComponent<PoseElementProps> {
const { onUnmount } = this.props;
if (onUnmount) onUnmount(this.poser);
this.poser.destroy();
this.ref = undefined;

This comment has been minimized.

Copy link
@mattgperry

mattgperry Apr 13, 2018

Author Collaborator

Traditionally handled by the setRef(null) when the element is unmounted

}

initPoser(poser: Poser) {
Expand Down Expand Up @@ -259,46 +228,19 @@ class PoseElement extends React.PureComponent<PoseElementProps> {

render() {
const { elementType, children } = this.props;
const props = this.getSetProps();

const elementProps : {
ref?: (ref: Element) => void;
innerRef?: (ref: Element) => void;
hostRef?: (ref: Element) => void;
} = {
// Functional components throw a warning when passed a `ref` prop
ref: isStatelessFunctionalComponent(elementType) ? undefined : this.setRef,
};

if (!isDOMPrimitiveComponent(elementType)) {
// We need to get a ref to an underlying DOM element. The standard is to
// accept an `innerRef` prop (ala: Styled Components), so we pass that
// function along.
// Unfortunately when using Styled Components, it will intercept the
// `innerRef` prop, and not pass it down to a wrapped component (when
// doing styled(Component)``, hence we pass in another standard ref
// getting function `hostRef`, which the consuming code can opt into if
// they want.
// ( see https://github.com/facebook/react/issues/11401 )
elementProps.innerRef = this.setRef;
elementProps.hostRef = this.setRef;
}

return (
<PoseParentContext.Provider value={this.childrenHandlers}>
{createElement(
elementType,
{
...props,
...elementProps,
},
this.getSetProps(),
children
)}
</PoseParentContext.Provider>
);
}
}

reactLifecyclesCompat(PoseElement);
reactLifecyclePolyfill(PoseElement);

export { PoseElement };
11 changes: 6 additions & 5 deletions playground/plugins/react-pose.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ const itemStyle = `
width: 100%;
opacity: 0;
margin-bottom: 10px;
transform-origin-y: 0%;
transform-origin: 0%;
transform-style: flat;
color: white;
`;

Expand Down Expand Up @@ -102,9 +103,9 @@ const itemProps = {
}
};

const Item = styled(posed.div(itemProps))`
${itemStyle};
`;
const ItemStyled = styled.div`${itemStyle}`

const Item = posed(ItemStyled)(itemProps)

export class ReactPoseChildren extends React.PureComponent {
state = { isOpen: false };
Expand All @@ -118,7 +119,7 @@ export class ReactPoseChildren extends React.PureComponent {

return (
<SidePanel innerRef={console.log} pose={isOpen ? "open" : "closed"}>
<Item i={0} />
<Item i={0} ref={console.log} />
<Item i={1} />
<Item i={2} />
<Item i={3} />
Expand Down

0 comments on commit 6965721

Please sign in to comment.