From 46723374facedc04530866fb724303c25a859371 Mon Sep 17 00:00:00 2001 From: "Bartosz V. Bentkowski" Date: Mon, 20 Aug 2018 19:52:36 -0700 Subject: [PATCH] Autofocus fix --- .../Input/__snapshots__/input.spec.js.snap | 5 +++ src/components/Input/index.js | 23 +++++++++-- src/components/Input/input.spec.js | 40 +++++++++++++++++-- 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/src/components/Input/__snapshots__/input.spec.js.snap b/src/components/Input/__snapshots__/input.spec.js.snap index df95198..ccf04ab 100644 --- a/src/components/Input/__snapshots__/input.spec.js.snap +++ b/src/components/Input/__snapshots__/input.spec.js.snap @@ -5,6 +5,7 @@ exports[`Input autoresizing works correctly 1`] = ` autoFocus={false} className="" disabled={false} + forceFocus={false} hint={null} hintClassName="" id={null} @@ -66,6 +67,7 @@ exports[`Input autoresizing works correctly 2`] = ` autoFocus={false} className="" disabled={false} + forceFocus={false} hint={null} hintClassName="" id={null} @@ -132,6 +134,7 @@ exports[`Input lifecycle works 1`] = ` autoFocus={false} className="" disabled={false} + forceFocus={false} hint={null} hintClassName="" id={null} @@ -190,6 +193,7 @@ exports[`Input lifecycle works 2`] = ` autoFocus={false} className="" disabled={false} + forceFocus={false} hint={null} hintClassName="" id={null} @@ -248,6 +252,7 @@ exports[`Input lifecycle works 3`] = ` autoFocus={false} className="" disabled={false} + forceFocus={false} hint={null} hintClassName="" id="bar" diff --git a/src/components/Input/index.js b/src/components/Input/index.js index 21b7f43..31981a2 100644 --- a/src/components/Input/index.js +++ b/src/components/Input/index.js @@ -44,7 +44,7 @@ class Input extends React.Component { } componentDidUpdate() { - this.autoFocus(); + this.forceFocus(); } getClassName() { @@ -153,7 +153,11 @@ class Input extends React.Component { } isAutoFocus() { - return this.props.autoFocus && !this.props.disabled && !this.props.readonly; + return (this.props.autoFocus || this.props.forceFocus) && !this.props.disabled && !this.props.readonly; + } + + isForceFocus() { + return this.props.forceFocus && !this.props.disabled && !this.props.readonly; } isAutoResize() { @@ -162,6 +166,12 @@ class Input extends React.Component { autoFocus() { if (this.isAutoFocus() && this.input) { + this.input.focus(); + } + } + + forceFocus() { + if (this.isForceFocus() && this.input) { if (document.activeElement !== this.input) { this.input.focus(); } @@ -328,6 +338,10 @@ Input.propTypes = { * Auto focus flag */ autoFocus: PropTypes.bool, + /** + * Force focus flag + */ + forceFocus: PropTypes.bool, /** * Disabled flag */ @@ -371,13 +385,14 @@ Input.defaultProps = { autoFocus: false, className: '', disabled: false, - label: '', + forceFocus: false, hint: null, - placeholder: null, hintClassName: '', id: null, inputClassName: '', + label: '', labelClassName: '', + placeholder: null, readonly: false, resize: false, rows: 2, diff --git a/src/components/Input/input.spec.js b/src/components/Input/input.spec.js index 6fef2e7..0c88c01 100644 --- a/src/components/Input/input.spec.js +++ b/src/components/Input/input.spec.js @@ -198,7 +198,38 @@ test('Input autoFocus works correctly', () => { ); expect(focusStub.callCount).toBe(1); - // second `autoFocus` call, but `document.activeElement` will return input element + const instance = component.instance(); + + activeElementStub.get(() => instance.input); + component.unmount(); + component.setProps({label: 'bar1'}); + component.mount(); + expect(focusStub.callCount).toBe(2); + + component.unmount(); + component.setProps({label: 'bar2'}); + component.mount(); + expect(focusStub.callCount).toBe(3); + + focusStub.restore(); +}); + +test('Input forceFocus works correctly', () => { + const activeElementStub = sinon.stub(document, 'activeElement').get(() => null); + const autoFocusStub = sinon.spy(Input.prototype, 'autoFocus'); + const forceFocusStub = sinon.spy(Input.prototype, 'forceFocus'); + + // first `autoFocus` call on mount + const component = mount( + + ); + // first call is autoFocus + expect(autoFocusStub.callCount).toBe(1); + + // second `autoFocus` call (`forceFocus`), but `document.activeElement` will return input element const instance = component.instance(); activeElementStub.get(() => instance.input); const inputFocusSpy = sinon.spy(); @@ -206,14 +237,17 @@ test('Input autoFocus works correctly', () => { component.setProps({label: 'bar'}); expect(inputFocusSpy.notCalled).toBe(true); - expect(focusStub.callCount).toBe(2); + expect(forceFocusStub.callCount).toBe(1); // third `autoFocus` call, but `document.activeElement` will return null activeElementStub.get(() => null); component.setProps({label: 'foo1'}); expect(inputFocusSpy.calledOnce).toBe(true); - expect(focusStub.callCount).toBe(3); + expect(forceFocusStub.callCount).toBe(2); + + autoFocusStub.restore(); + forceFocusStub.restore(); }); test('Input handleAutoResize works correctly', () => {