GithubHelp home page GithubHelp logo

vidom-animation-group's Introduction

vidom-animation-group Build Status npm version

What is it?

This module provides low-level API for "appearance", "entering" and "leaving" animation inside Vidom.

vidom-animation-group's People

Contributors

dfilatov avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar

vidom-animation-group's Issues

child can be null

Child can be null

<CssAnimationGroup appear="error-message-appear" enter="error-message-enter" leave="error-message-leave">
                    {this.state.showErrorA &&
                    <div class="error-message" key="A">Error A</div>
                    }
                    {this.state.showErrorB &&
                    <div class="error-message" key="B">Error B</div>
                    }

</CssAnimationGroup>

Here is my quick fix, but I think it can be made much more elegant.

AnimationGroup.js

import { Component, IS_DEBUG } from 'vidom';
import { childrenToArray, checkChildrenKeys, collectChildrenKeys, mergeChildren } from './utils';

export default class AnimationGroup extends Component {
    onInit() {
        this._appearingKeys = {};
        this._enteringKeys = {};
        this._leavingKeys = {};
        this._keysToEnter = null;
        this._keysToLeave = null;

        const children = childrenToArray(this.children);

        if(IS_DEBUG) {
            checkChildrenKeys(children);
        }

        this.setState({ children });
    }

    onRender() {
        return this.state.children;
    }

    onMount() {
        const { onAppear } = this.attrs;

        if(onAppear) {
            this.state.children.forEach(child => {
                if(!child) {
                    return;
                }
                const { key } = child;

                this._appearingKeys[key] = onAppear(child.getDomNode(), () => {
                    this._onAppeared(key);
                }) || noOp
            });
        }
    }

    onChange(prevAttrs, prevChildren) {
        if(this.children === prevChildren) {
            return;
        }

        const nextChildren = childrenToArray(this.children);

        if(IS_DEBUG) {
            checkChildrenKeys(nextChildren);
        }

        const { children } = this.state,
            nextKeys = collectChildrenKeys(nextChildren),
            currentKeys = collectChildrenKeys(children);

        children.forEach(child => {
            if(!child) {
                return;
            }
            const { key } = child;

            if(!nextKeys[key] && !this._leavingKeys[key]) {
                (this._keysToLeave || (this._keysToLeave = {}))[key] = true;
            }
        });

        nextChildren.forEach(child => {
            if(!child) {
                return;
            }
            const { key } = child;

            if(!currentKeys[key] || this._leavingKeys[key]) {
                (this._keysToEnter || (this._keysToEnter = {}))[key] = true;
            }
        });

        this.setState({ children : mergeChildren(children, nextChildren, nextKeys) });
    }

    onUpdate() {
        if(!this._keysToEnter && !this._keysToLeave) {
            return;
        }

        const { onEnter, onLeave } = this.attrs;

        this.state.children.forEach(child => {
            if(!child) {
                return;
            }

            const { key } = child;

            if(this._keysToEnter && this._keysToEnter[key]) {
                if(this._leavingKeys[key]) {
                    this._leavingKeys[key]();
                    delete this._leavingKeys[key];
                }

                if(onEnter) {
                    this._enteringKeys[key] = onEnter(child.getDomNode(), () => {
                        this._onEntered(key);
                    }) || noOp;
                }
            }
            else if(this._keysToLeave && this._keysToLeave[key]) {
                if(this._appearingKeys[key]) {
                    this._appearingKeys[key]();
                    delete this._appearingKeys[key];
                }
                else if(this._enteringKeys[key]) {
                    this._enteringKeys[key]();
                    delete this._enteringKeys[key];
                }

                if(onLeave) {
                    this._leavingKeys[key] = onLeave(child.getDomNode(), () => {
                        this._onLeft(key);
                    }) || noOp;
                }
                else {
                    this._removeChildByKey(key);
                }
            }
        });

        this._keysToEnter = null;
        this._keysToLeave = null;
    }

    _onAppeared(key) {
        delete this._appearingKeys[key];
    }

    _onEntered(key) {
        delete this._enteringKeys[key];
    }

    _onLeft(key) {
        if(this._leavingKeys[key]) {
            delete this._leavingKeys[key];
            this._removeChildByKey(key);
        }
    }

    _removeChildByKey(key) {
        this.setState({ children : this.state.children.filter(child => child.key !== key) });
    }
}

function noOp() {}

utils.js

import { console } from 'vidom';

export function childrenToArray(children) {
    return children?
        Array.isArray(children)? children : [children] :
        [];
}

export function checkChildrenKeys(children) {
    children.forEach(child => {
        if(!child) {
            return;
        }

        if(child.key == null) {
            console.error('You must specify a key for each child of AnimationGroup.')
        }
    });
}

export function collectChildrenKeys(children) {
    return children.reduce((res, child) => {
        if(!child) {
            return res;
        }

        res[child.key] = child;
        return res;
    }, {});
}

export function mergeChildren(currentChildren, nextChildren, nextKeys) {
    if(!currentChildren.length) {
        return nextChildren;
    }

    if(!nextChildren.length) {
        return currentChildren;
    }

    const nextChildrenPending = {};
    let pendingChildren = [];

    currentChildren.forEach(child => {
        if(!child) {
            return;
        }

        if(nextKeys[child.key]) {
            if(pendingChildren.length) {
                nextChildrenPending[child.key] = pendingChildren;
                pendingChildren = [];
            }
        }
        else {
            pendingChildren.push(child);
        }
    });

    return nextChildren
        .reduce((res, child) => {
            if(!child) {
                return res;
            }

            if(nextChildrenPending[child.key]) {
                res = res.concat(nextChildrenPending[child.key]);
            }

            res.push(child);

            return res;
        }, [])
        .concat(pendingChildren);
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.