Convert NodeAnimator to TS

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
This commit is contained in:
Šimon Brandner 2021-09-27 12:38:56 +02:00
parent 1fe96cae8a
commit b621f92805
No known key found for this signature in database
GPG key ID: 55C211A1226CB17D

View file

@ -1,6 +1,21 @@
import React from "react"; import React from "react";
import ReactDom from "react-dom"; import ReactDom from "react-dom";
import PropTypes from 'prop-types';
interface IChildProps {
style: React.CSSProperties;
ref: (node: React.ReactInstance) => void;
}
interface IProps {
// either a list of child nodes, or a single child.
children: React.ReactNode;
// optional transition information for changing existing children
transition?: object;
// a list of state objects to apply to each child node in turn
startStyles: React.CSSProperties[];
}
/** /**
* The NodeAnimator contains components and animates transitions. * The NodeAnimator contains components and animates transitions.
@ -9,55 +24,45 @@ import PropTypes from 'prop-types';
* from DOM order. This makes it a lot simpler and lighter: if you need fully * from DOM order. This makes it a lot simpler and lighter: if you need fully
* automatic positional animation, look at react-shuffle or similar libraries. * automatic positional animation, look at react-shuffle or similar libraries.
*/ */
export default class NodeAnimator extends React.Component { export default class NodeAnimator extends React.Component<IProps> {
static propTypes = { private nodes = {};
// either a list of child nodes, or a single child. private children: { [key: string]: React.DetailedReactHTMLElement<any, HTMLElement> };
children: PropTypes.any, static defaultProps: Partial<IProps> = {
// optional transition information for changing existing children
transition: PropTypes.object,
// a list of state objects to apply to each child node in turn
startStyles: PropTypes.array,
};
static defaultProps = {
startStyles: [], startStyles: [],
}; };
constructor(props) { constructor(props: IProps) {
super(props); super(props);
this.nodes = {}; this.updateChildren(this.props.children);
this._updateChildren(this.props.children);
} }
componentDidUpdate() { public componentDidUpdate(): void {
this._updateChildren(this.props.children); this.updateChildren(this.props.children);
} }
/** /**
* *
* @param {HTMLElement} node element to apply styles to * @param {HTMLElement} node element to apply styles to
* @param {object} styles a key/value pair of CSS properties * @param {React.CSSProperties} styles a key/value pair of CSS properties
* @returns {void} * @returns {void}
*/ */
_applyStyles(node, styles) { private applyStyles(node: HTMLElement, styles: React.CSSProperties): void {
Object.entries(styles).forEach(([property, value]) => { Object.entries(styles).forEach(([property, value]) => {
node.style[property] = value; node.style[property] = value;
}); });
} }
_updateChildren(newChildren) { private updateChildren(newChildren: React.ReactNode): void {
const oldChildren = this.children || {}; const oldChildren = this.children || {};
this.children = {}; this.children = {};
React.Children.toArray(newChildren).forEach((c) => { React.Children.toArray(newChildren).forEach((c: any) => {
if (oldChildren[c.key]) { if (oldChildren[c.key]) {
const old = oldChildren[c.key]; const old = oldChildren[c.key];
const oldNode = ReactDom.findDOMNode(this.nodes[old.key]); const oldNode = ReactDom.findDOMNode(this.nodes[old.key]);
if (oldNode && oldNode.style.left !== c.props.style.left) { if (oldNode && (oldNode as HTMLElement).style.left !== c.props.style.left) {
this._applyStyles(oldNode, { left: c.props.style.left }); this.applyStyles(oldNode as HTMLElement, { left: c.props.style.left });
// console.log("translation: "+oldNode.style.left+" -> "+c.props.style.left); // console.log("translation: "+oldNode.style.left+" -> "+c.props.style.left);
} }
// clone the old element with the props (and children) of the new element // clone the old element with the props (and children) of the new element
@ -66,7 +71,7 @@ export default class NodeAnimator extends React.Component {
} else { } else {
// new element. If we have a startStyle, use that as the style and go through // new element. If we have a startStyle, use that as the style and go through
// the enter animations // the enter animations
const newProps = {}; const newProps: Partial<IChildProps> = {};
const restingStyle = c.props.style; const restingStyle = c.props.style;
const startStyles = this.props.startStyles; const startStyles = this.props.startStyles;
@ -76,7 +81,7 @@ export default class NodeAnimator extends React.Component {
// console.log("mounted@startstyle0: "+JSON.stringify(startStyle)); // console.log("mounted@startstyle0: "+JSON.stringify(startStyle));
} }
newProps.ref = ((n) => this._collectNode( newProps.ref = ((n) => this.collectNode(
c.key, n, restingStyle, c.key, n, restingStyle,
)); ));
@ -85,7 +90,7 @@ export default class NodeAnimator extends React.Component {
}); });
} }
_collectNode(k, node, restingStyle) { private collectNode(k: string, node: React.ReactInstance, restingStyle: React.CSSProperties): void {
if ( if (
node && node &&
this.nodes[k] === undefined && this.nodes[k] === undefined &&
@ -96,7 +101,7 @@ export default class NodeAnimator extends React.Component {
// start from startStyle 1: 0 is the one we gave it // start from startStyle 1: 0 is the one we gave it
// to start with, so now we animate 1 etc. // to start with, so now we animate 1 etc.
for (let i = 1; i < startStyles.length; ++i) { for (let i = 1; i < startStyles.length; ++i) {
this._applyStyles(domNode, startStyles[i]); this.applyStyles(domNode as HTMLElement, startStyles[i]);
// console.log("start:" // console.log("start:"
// JSON.stringify(startStyles[i]), // JSON.stringify(startStyles[i]),
// ); // );
@ -104,7 +109,7 @@ export default class NodeAnimator extends React.Component {
// and then we animate to the resting state // and then we animate to the resting state
setTimeout(() => { setTimeout(() => {
this._applyStyles(domNode, restingStyle); this.applyStyles(domNode as HTMLElement, restingStyle);
}, 0); }, 0);
// console.log("enter:", // console.log("enter:",
@ -113,7 +118,7 @@ export default class NodeAnimator extends React.Component {
this.nodes[k] = node; this.nodes[k] = node;
} }
render() { public render(): JSX.Element {
return ( return (
<>{ Object.values(this.children) }</> <>{ Object.values(this.children) }</>
); );