From fe3c156c11b140b4ce494261a2cc4ac66e99f40c Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Wed, 25 Jul 2018 01:09:17 +0900 Subject: [PATCH] feat(CSSTransition): add "done" class for appear This is not a breaking change because it doesn't remove the `*-enter-done` class name after appearing is done, instead `*-appear-done` is added in addition to that class, which provides you with a bit more control in case you wanted to define a specific animation only when an element first appears in the DOM, not every time it enters. Closes #383. Closes #327. Changes came from #383, but had to rebase to resolve conflicts and make modifications informed by the discussion in #327. --- src/CSSTransition.js | 32 ++++++++++++++++++++++++-------- test/CSSTransition-test.js | 31 ++++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/src/CSSTransition.js b/src/CSSTransition.js index 79c7cd8a..0fee9ded 100644 --- a/src/CSSTransition.js +++ b/src/CSSTransition.js @@ -98,7 +98,11 @@ class CSSTransition extends React.Component { } onEntered = (node, appearing) => { - const { doneClassName } = this.getClassNames('enter'); + const appearClassName = this.getClassNames('appear').doneClassName; + const enterClassName = this.getClassNames('enter').doneClassName; + const doneClassName = appearing + ? `${appearClassName} ${enterClassName}` + : enterClassName; this.removeClasses(node, appearing ? 'appear' : 'enter'); addClass(node, doneClassName); @@ -203,17 +207,29 @@ CSSTransition.propTypes = { ...Transition.propTypes, /** - * The animation classNames applied to the component as it enters, exits or has finished the transition. - * A single name can be provided and it will be suffixed for each stage: e.g. + * The animation classNames applied to the component as it enters, exits or + * has finished the transition. A single name can be provided and it will be + * suffixed for each stage: e.g. + * + * `classNames="fade"` applies `fade-enter`, `fade-enter-active`, + * `fade-enter-done`, `fade-exit`, `fade-exit-active`, `fade-exit-done`, + * `fade-appear`, `fade-appear-active`, and `fade-appear-done`. + * + * **Note**: `fade-appear-done` and `fade-enter-done` will _both_ be applied. + * This allows you to define different behavior for when appearing is done and + * when regular entering is done, using selectors like + * `.fade-enter-done:not(.fade-appear-done)`. For example, you could apply an + * epic entrance animation when element first appears in the DOM using + * [Animate.css](https://daneden.github.io/animate.css/). Otherwise you can + * simply use `fade-enter-done` for defining both cases. * - * `classNames="fade"` applies `fade-enter`, `fade-enter-active`, `fade-enter-done`, - * `fade-exit`, `fade-exit-active`, `fade-exit-done`, `fade-appear`, and `fade-appear-active`. * Each individual classNames can also be specified independently like: * * ```js * classNames={{ * appear: 'my-appear', * appearActive: 'my-active-appear', + * appearDone: 'my-done-appear', * enter: 'my-enter', * enterActive: 'my-active-enter', * enterDone: 'my-done-enter', @@ -229,8 +245,8 @@ CSSTransition.propTypes = { * import styles from './styles.css'; * ``` * - * you might want to use camelCase in your CSS file, that way could simply spread - * them instead of listing them one by one: + * you might want to use camelCase in your CSS file, that way could simply + * spread them instead of listing them one by one: * * ```js * classNames={{ ...styles }} @@ -239,6 +255,7 @@ CSSTransition.propTypes = { * @type {string | { * appear?: string, * appearActive?: string, + * appearDone?: string, * enter?: string, * enterActive?: string, * enterDone?: string, @@ -273,7 +290,6 @@ CSSTransition.propTypes = { */ onEntered: PropTypes.func, - /** * A `` callback fired immediately after the 'exit' class is * applied. diff --git a/test/CSSTransition-test.js b/test/CSSTransition-test.js index 98e2893a..e5436c52 100644 --- a/test/CSSTransition-test.js +++ b/test/CSSTransition-test.js @@ -127,7 +127,7 @@ describe('CSSTransition', () => { onEntered={(node, isAppearing) => { expect(isAppearing).toEqual(true); - expect(node.className).toEqual('appear-test-enter-done'); + expect(node.className).toEqual('appear-test-appear-done appear-test-enter-done'); expect(count).toEqual(2); done(); }} @@ -137,6 +137,35 @@ describe('CSSTransition', () => { ); }); + it('should lose the "*-appear-done" class after leaving and entering again', (done) => { + const wrapper = mount( + { + wrapper.setProps({ + in: false, + onEntered: () => {}, + onExited: (node) => { + expect(node.className).toBe('appear-test-exit-done') + wrapper.setProps({ + in: true, + onEntered: () => { + expect(node.className).toBe('appear-test-enter-done') + done() + } + }) + } + }) + }} + > +
+ + ) + }) + it('should not be appearing in normal enter mode', done => { let count = 0; mount(