From 2857c1803d4d6786d32d077c83b344a0efb66e1a Mon Sep 17 00:00:00 2001 From: Alexander Fedyashov Date: Thu, 13 Apr 2017 16:35:19 +0300 Subject: [PATCH 1/2] fix(Input): add handling of input's ref --- src/elements/Input/Input.js | 20 +++++++--- test/specs/elements/Input/Input-test.js | 51 ++++++++++++++++--------- 2 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/elements/Input/Input.js b/src/elements/Input/Input.js index 3abb1619fd..d77a66a9b0 100644 --- a/src/elements/Input/Input.js +++ b/src/elements/Input/Input.js @@ -1,6 +1,6 @@ -import _ from 'lodash' -import React, { Children, cloneElement, Component, PropTypes } from 'react' import cx from 'classnames' +import _ from 'lodash' +import React, { Children, Component, PropTypes } from 'react' import { createHTMLInput, @@ -114,6 +114,8 @@ class Input extends Component { type: META.TYPES.ELEMENT, } + focus = () => (this.inputRef.focus()) + handleChange = (e) => { const { onChange } = this.props const value = _.get(e, 'target.value') @@ -121,9 +123,12 @@ class Input extends Component { onChange(e, { ...this.props, value }) } - focus = () => { - this.inputRef.focus() - } + handleInputOverrides = predefinedProps => ({ + ref: c => { + _.invoke(predefinedProps, 'ref', c) + this.handleInputRef(c) + }, + }) handleInputRef = c => (this.inputRef = c) @@ -187,7 +192,10 @@ class Input extends Component { const childElements = _.map(Children.toArray(children), (child) => { if (child.type !== 'input') return child - return cloneElement(child, { ...htmlInputProps, ...child.props }) + return createHTMLInput(child, { + defaultProps: htmlInputProps, + overrideProps: this.handleInputOverrides, + }) }) return {childElements} diff --git a/test/specs/elements/Input/Input-test.js b/test/specs/elements/Input/Input-test.js index f5648fbad1..2de0ab2eca 100644 --- a/test/specs/elements/Input/Input-test.js +++ b/test/specs/elements/Input/Input-test.js @@ -53,14 +53,14 @@ describe('Input', () => { common.hasUIClassName(Input) common.rendersChildren(Input) - common.implementsLabelProp(Input, { - shorthandDefaultProps: { className: 'label' }, - }) common.implementsButtonProp(Input, { propKey: 'action', shorthandDefaultProps: { className: 'button' }, }) common.implementsCreateMethod(Input) + common.implementsLabelProp(Input, { + shorthandDefaultProps: { className: 'label' }, + }) common.implementsHTMLInputProp(Input, { alwaysPresent: true, shorthandDefaultProps: { type: 'text' }, @@ -138,6 +138,22 @@ describe('Input', () => { }) }) + describe('focus', () => { + it('can be set via a ref', () => { + const mountNode = document.createElement('div') + document.body.appendChild(mountNode) + + const wrapper = mount(, { attachTo: mountNode }) + wrapper.instance().focus() + + const input = document.querySelector('.ui.input input') + document.activeElement.should.equal(input) + + wrapper.detach() + document.body.removeChild(mountNode) + }) + }) + describe('onChange', () => { it('is called with (e, data) on change', () => { const spy = sandbox.spy() @@ -170,42 +186,39 @@ describe('Input', () => { }) }) + describe('ref', () => { + it('maintains ref on child node', () => { + const ref = sandbox.spy() + const wrapper = mount() + + // ref.should.have.been.calledOnce() + wrapper.instance().inputRef.tagName.should.equal('INPUT') + }) + }) + describe('tabIndex', () => { it('is not set by default', () => { shallow() .find('input') .should.not.have.prop('tabIndex') }) + it('defaults to -1 when disabled', () => { shallow() .find('input') .should.have.prop('tabIndex', -1) }) + it('can be set explicitly', () => { shallow() .find('input') .should.have.prop('tabIndex', 123) }) + it('can be set explicitly when disabled', () => { shallow() .find('input') .should.have.prop('tabIndex', 123) }) }) - - describe('focus', () => { - it('can be set via a ref', () => { - const mountNode = document.createElement('div') - document.body.appendChild(mountNode) - - const wrapper = mount(, { attachTo: mountNode }) - wrapper.instance().focus() - - const input = document.querySelector('.ui.input input') - document.activeElement.should.equal(input) - - wrapper.detach() - document.body.removeChild(mountNode) - }) - }) }) From eb7badc7be6b6685d8aca2794151b2da571236f3 Mon Sep 17 00:00:00 2001 From: Alexander Fedyashov Date: Fri, 14 Apr 2017 10:26:54 +0300 Subject: [PATCH 2/2] fix(Input): update handling of input's ref --- src/elements/Input/Input.js | 13 ++++++------- test/specs/elements/Input/Input-test.js | 14 +++++++++++--- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/elements/Input/Input.js b/src/elements/Input/Input.js index d77a66a9b0..4c23b84c67 100644 --- a/src/elements/Input/Input.js +++ b/src/elements/Input/Input.js @@ -1,6 +1,6 @@ import cx from 'classnames' import _ from 'lodash' -import React, { Children, Component, PropTypes } from 'react' +import React, { Children, cloneElement, Component, PropTypes } from 'react' import { createHTMLInput, @@ -123,9 +123,11 @@ class Input extends Component { onChange(e, { ...this.props, value }) } - handleInputOverrides = predefinedProps => ({ + handleChildOverrides = (child, defaultProps) => ({ + ...defaultProps, + ...child.props, ref: c => { - _.invoke(predefinedProps, 'ref', c) + _.invoke(child, 'ref', c) this.handleInputRef(c) }, }) @@ -192,10 +194,7 @@ class Input extends Component { const childElements = _.map(Children.toArray(children), (child) => { if (child.type !== 'input') return child - return createHTMLInput(child, { - defaultProps: htmlInputProps, - overrideProps: this.handleInputOverrides, - }) + return cloneElement(child, this.handleChildOverrides(child, htmlInputProps)) }) return {childElements} diff --git a/test/specs/elements/Input/Input-test.js b/test/specs/elements/Input/Input-test.js index 2de0ab2eca..dd2f46d8c4 100644 --- a/test/specs/elements/Input/Input-test.js +++ b/test/specs/elements/Input/Input-test.js @@ -189,10 +189,18 @@ describe('Input', () => { describe('ref', () => { it('maintains ref on child node', () => { const ref = sandbox.spy() - const wrapper = mount() + const mountNode = document.createElement('div') + document.body.appendChild(mountNode) + + const wrapper = mount(, { attachTo: mountNode }) + const input = document.querySelector('.ui.input input') - // ref.should.have.been.calledOnce() - wrapper.instance().inputRef.tagName.should.equal('INPUT') + ref.should.have.been.calledOnce() + ref.should.have.been.calledWithMatch(input) + wrapper.instance().inputRef.should.equal(input) + + wrapper.detach() + document.body.removeChild(mountNode) }) })