Skip to content
This repository was archived by the owner on Jan 21, 2019. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/components/Input/__snapshots__/input.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ exports[`Input autoresizing works correctly 1`] = `
autoFocus={false}
className=""
disabled={false}
forceFocus={false}
hint={null}
hintClassName=""
id={null}
Expand Down Expand Up @@ -66,6 +67,7 @@ exports[`Input autoresizing works correctly 2`] = `
autoFocus={false}
className=""
disabled={false}
forceFocus={false}
hint={null}
hintClassName=""
id={null}
Expand Down Expand Up @@ -132,6 +134,7 @@ exports[`Input lifecycle works 1`] = `
autoFocus={false}
className=""
disabled={false}
forceFocus={false}
hint={null}
hintClassName=""
id={null}
Expand Down Expand Up @@ -190,6 +193,7 @@ exports[`Input lifecycle works 2`] = `
autoFocus={false}
className=""
disabled={false}
forceFocus={false}
hint={null}
hintClassName=""
id={null}
Expand Down Expand Up @@ -248,6 +252,7 @@ exports[`Input lifecycle works 3`] = `
autoFocus={false}
className=""
disabled={false}
forceFocus={false}
hint={null}
hintClassName=""
id="bar"
Expand Down
23 changes: 19 additions & 4 deletions src/components/Input/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class Input extends React.Component {
}

componentDidUpdate() {
this.autoFocus();
this.forceFocus();
}

getClassName() {
Expand Down Expand Up @@ -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() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one small note, maybe we should call it should(Force/Auto)Focus?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this is an internal function, let's do it in separate PR.

return this.props.forceFocus && !this.props.disabled && !this.props.readonly;
}

isAutoResize() {
Expand All @@ -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();
}
Expand Down Expand Up @@ -328,6 +338,10 @@ Input.propTypes = {
* Auto focus flag
*/
autoFocus: PropTypes.bool,
/**
* Force focus flag
*/
forceFocus: PropTypes.bool,
/**
* Disabled flag
*/
Expand Down Expand Up @@ -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,
Expand Down
40 changes: 37 additions & 3 deletions src/components/Input/input.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -198,22 +198,56 @@ 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(
<Input
label="forceFocus"
forceFocus
/>
);
// 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();
instance.input.focus = inputFocusSpy;
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', () => {
Expand Down