From 7fcf655283054e133351b716db4b3097a4ff6729 Mon Sep 17 00:00:00 2001 From: Tyler Cosgrove Date: Thu, 11 Jan 2018 23:43:22 -0500 Subject: [PATCH 1/2] Add `onBeforeExit` callback --- CHANGELOG.md | 1 + README.md | 1 + __mocks__/intro.js.js | 10 ++++++++ src/components/Steps/index.js | 20 +++++++++++++++ src/components/Steps/index.test.js | 40 ++++++++++++++++++++++++++++++ 5 files changed, 72 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index af6d47b..5ce51f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * Add React 16 support. * If at least intro.js 2.8.0 is used, `false` can be returned in `onBeforeChange` to prevent transitioning to the next / previous step. * Add the `onPreventChange` callback called when a transition is prevented by returning `false` in `onBeforeChange`. +* Add the `onBeforeExit` callback to prevent exiting the intro. ## 0.1.5 diff --git a/README.md b/README.md index b255510..a2ee078 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ import { Steps, Hints } from 'intro.js-react'; | `initialStep` | Step index to start with when showing the steps. | Number | ✅ | | `steps` | All the steps. | [Step[]](#step) | ✅ | | `onExit` | Callback called when the steps are disabled
*Required to force keeping track of the state when the steps are dismissed with an Intro.js event and not the `enabled` prop.* | Function
*(stepIndex)* | ✅ | +| `onBeforeExit` | Callback called before exiting the intro.
*If you want to prevent exiting the intro, you can return `false` in this callback (available since intro.js 0.2.7).* | Function
*(stepIndex)* | | | `onStart` | Callback called when the steps are enabled. | Function
*(stepIndex)* | | | `onChange` | Callback called when the current step is changed. | Function
*(nextStepIndex, nextElement)* | | | `onBeforeChange` | Callback called before changing the current step.
*If you want to prevent the transition to the next / previous step, you can return `false` in this callback (available since intro.js 2.8.0).* | Function
*(nextStepIndex)* | | diff --git a/__mocks__/intro.js.js b/__mocks__/intro.js.js index 6c10817..371b2ce 100644 --- a/__mocks__/intro.js.js +++ b/__mocks__/intro.js.js @@ -9,6 +9,12 @@ class IntroJsMock { } } + onbeforeexit(fn) { + if (fn) { + this.onBeforeExitFn = fn; + } + } + exit() { if (this.exitFn) { this.exitFn(); @@ -35,6 +41,10 @@ class IntroJsMock { if (this.onAfterChangeFn) { this.onAfterChangeFn(null); } + + if (this.onBeforeExitFn) { + this.onBeforeExitFn(); + } } onafterchange(fn) { diff --git a/src/components/Steps/index.js b/src/components/Steps/index.js index 904e1d4..ffd1250 100644 --- a/src/components/Steps/index.js +++ b/src/components/Steps/index.js @@ -27,6 +27,7 @@ export default class Steps extends Component { ).isRequired, onStart: PropTypes.func, onExit: PropTypes.func.isRequired, + onBeforeExit: PropTypes.func, onBeforeChange: PropTypes.func, onAfterChange: PropTypes.func, onChange: PropTypes.func, @@ -42,6 +43,7 @@ export default class Steps extends Component { static defaultProps = { enabled: false, onStart: null, + onBeforeExit: null, onBeforeChange: null, onAfterChange: null, onChange: null, @@ -113,6 +115,23 @@ export default class Steps extends Component { onExit(this.introJs._currentStep); }; + /** + * Triggered before changing step. + * @return {Boolean} Returning `false` will prevent the step transition. + */ + onBeforeExit = () => { + if (!this.isVisible) { + return true; + } + + const { onBeforeExit } = this.props; + + if (onBeforeExit) { + return onBeforeExit(this.introJs._currentStep); + } + return true; + }; + /** * Triggered before changing step. * @return {Boolean} Returning `false` will prevent the step transition. @@ -203,6 +222,7 @@ export default class Steps extends Component { this.introJs = introJs(); this.introJs.onexit(this.onExit); + this.introJs.onbeforeexit(this.onBeforeExit); this.introJs.onbeforechange(this.onBeforeChange); this.introJs.onafterchange(this.onAfterChange); this.introJs.onchange(this.onChange); diff --git a/src/components/Steps/index.test.js b/src/components/Steps/index.test.js index 5f78308..2db85ba 100644 --- a/src/components/Steps/index.test.js +++ b/src/components/Steps/index.test.js @@ -177,6 +177,46 @@ describe('Steps', () => { expect(onChange).toHaveBeenCalledWith(1, null); }); + test('should not call the onBeforeExit callback when disabled', () => { + const onBeforeExit = jest.fn(); + + renderer.create( {}} onBeforeExit={onBeforeExit} />); + + expect(onBeforeExit).not.toHaveBeenCalled(); + }); + + test('should call the onBeforeExit callback when disabled while being enabled', () => { + const onBeforeExit = jest.fn(); + + const wrapper = shallow( + {}} onBeforeExit={onBeforeExit} />, + { + lifecycleExperimental: true, + } + ); + wrapper.setProps({ enabled: false }); + wrapper.instance().onComplete(); + + expect(onBeforeExit).toHaveBeenCalledTimes(1); + }); + + test('should call the onBeforeExit callback with the step number', () => { + const onBeforeExit = jest.fn(); + + const wrapper = shallow( + {}} onBeforeExit={onBeforeExit} />, + { + lifecycleExperimental: true, + } + ); + wrapper.setProps({ enabled: false }); + expect(onBeforeExit).toHaveBeenCalledWith(1); + wrapper.setProps({ enabled: true, initialStep: 10 }); + wrapper.setProps({ enabled: false }); + + expect(onBeforeExit).toHaveBeenCalledWith(11); + }); + test('should not call the onBeforeChange callback when disabled', () => { const onBeforeChange = jest.fn(); From 6036508fd05ecc775a7c3bd4c9727d2434aa6613 Mon Sep 17 00:00:00 2001 From: HiDeo Date: Fri, 12 Jan 2018 10:51:39 +0100 Subject: [PATCH 2/2] Fix mock & some comments --- __mocks__/intro.js.js | 8 ++++---- src/components/Steps/index.js | 9 +++------ src/components/Steps/index.test.js | 7 +++++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/__mocks__/intro.js.js b/__mocks__/intro.js.js index 371b2ce..20a4a7c 100644 --- a/__mocks__/intro.js.js +++ b/__mocks__/intro.js.js @@ -16,6 +16,10 @@ class IntroJsMock { } exit() { + if (this.onBeforeExitFn) { + this.onBeforeExitFn(); + } + if (this.exitFn) { this.exitFn(); } @@ -41,10 +45,6 @@ class IntroJsMock { if (this.onAfterChangeFn) { this.onAfterChangeFn(null); } - - if (this.onBeforeExitFn) { - this.onBeforeExitFn(); - } } onafterchange(fn) { diff --git a/src/components/Steps/index.js b/src/components/Steps/index.js index ffd1250..8e4ac5c 100644 --- a/src/components/Steps/index.js +++ b/src/components/Steps/index.js @@ -116,19 +116,16 @@ export default class Steps extends Component { }; /** - * Triggered before changing step. - * @return {Boolean} Returning `false` will prevent the step transition. + * Triggered before exiting the intro. + * @return {Boolean} Returning `false` will prevent exiting the intro. */ onBeforeExit = () => { - if (!this.isVisible) { - return true; - } - const { onBeforeExit } = this.props; if (onBeforeExit) { return onBeforeExit(this.introJs._currentStep); } + return true; }; diff --git a/src/components/Steps/index.test.js b/src/components/Steps/index.test.js index 2db85ba..38e487f 100644 --- a/src/components/Steps/index.test.js +++ b/src/components/Steps/index.test.js @@ -185,7 +185,7 @@ describe('Steps', () => { expect(onBeforeExit).not.toHaveBeenCalled(); }); - test('should call the onBeforeExit callback when disabled while being enabled', () => { + test('should call the onBeforeExit callback when disabling', () => { const onBeforeExit = jest.fn(); const wrapper = shallow( @@ -195,7 +195,6 @@ describe('Steps', () => { } ); wrapper.setProps({ enabled: false }); - wrapper.instance().onComplete(); expect(onBeforeExit).toHaveBeenCalledTimes(1); }); @@ -210,11 +209,15 @@ describe('Steps', () => { } ); wrapper.setProps({ enabled: false }); + expect(onBeforeExit).toHaveBeenCalledWith(1); + expect(onBeforeExit).toHaveBeenCalledTimes(1); + wrapper.setProps({ enabled: true, initialStep: 10 }); wrapper.setProps({ enabled: false }); expect(onBeforeExit).toHaveBeenCalledWith(11); + expect(onBeforeExit).toHaveBeenCalledTimes(2); }); test('should not call the onBeforeChange callback when disabled', () => {