Unverified Commit 1d25dfca by Farhanah Sheets Committed by GitHub

fix(input): Use prop.id/prop.type when available and allow for ref on inputs

Leverage the ID that is passed through as prop when it's available, allow for InputText to accept a type prop, and allow for input components to be assigned a ref
parent 57c13c46
...@@ -49,6 +49,7 @@ class Select extends React.Component { ...@@ -49,6 +49,7 @@ class Select extends React.Component {
aria-describedby={props.describedBy} aria-describedby={props.describedBy}
onChange={props.onChange} onChange={props.onChange}
onBlur={props.onBlur} onBlur={props.onBlur}
ref={props.inputRef}
> >
{options} {options}
</select> </select>
......
...@@ -3,6 +3,41 @@ import React from 'react'; ...@@ -3,6 +3,41 @@ import React from 'react';
import { storiesOf } from '@storybook/react'; import { storiesOf } from '@storybook/react';
import InputText from './index'; import InputText from './index';
import StatusAlert from '../StatusAlert';
class FocusInputWrapper extends React.Component {
constructor(props) {
super(props);
this.state = { open: true };
this.resetStatusAlertWrapperState = this.resetStatusAlertWrapperState.bind(this);
}
resetStatusAlertWrapperState() {
this.setState({ open: false });
this.inputForm.focus();
}
render() {
return (
<div>
<StatusAlert
alertType="info"
open={this.state.open}
dialog="Close me to input data!"
onClose={this.resetStatusAlertWrapperState}
/>
<InputText
id="data"
name="data"
label="Data Input"
inputRef={(input) => { this.inputForm = input; }}
/>
</div>
);
}
}
storiesOf('InputText', module) storiesOf('InputText', module)
.add('minimal usage', () => ( .add('minimal usage', () => (
...@@ -14,6 +49,7 @@ storiesOf('InputText', module) ...@@ -14,6 +49,7 @@ storiesOf('InputText', module)
)) ))
.add('validation', () => ( .add('validation', () => (
<InputText <InputText
id="username"
name="username" name="username"
label="Username" label="Username"
description="The unique name that identifies you throughout the site." description="The unique name that identifies you throughout the site."
...@@ -28,4 +64,7 @@ storiesOf('InputText', module) ...@@ -28,4 +64,7 @@ storiesOf('InputText', module)
return feedback; return feedback;
}} }}
/> />
))
.add('focus test', () => (
<FocusInputWrapper />
)); ));
...@@ -8,7 +8,7 @@ function Text(props) { ...@@ -8,7 +8,7 @@ function Text(props) {
<input <input
id={props.id} id={props.id}
className={classNames(props.className)} className={classNames(props.className)}
type="text" type={props.type || 'text'}
name={props.name} name={props.name}
value={props.value} value={props.value}
placeholder={props.placeholder} placeholder={props.placeholder}
...@@ -18,6 +18,7 @@ function Text(props) { ...@@ -18,6 +18,7 @@ function Text(props) {
aria-invalid={!props.isValid} aria-invalid={!props.isValid}
disabled={props.disabled} disabled={props.disabled}
required={props.required} required={props.required}
ref={props.inputRef}
/> />
); );
} }
......
...@@ -8,7 +8,6 @@ function Text(props) { ...@@ -8,7 +8,6 @@ function Text(props) {
<textarea <textarea
id={props.id} id={props.id}
className={classNames(props.className)} className={classNames(props.className)}
type="text"
name={props.name} name={props.name}
value={props.value} value={props.value}
placeholder={props.placeholder} placeholder={props.placeholder}
...@@ -18,6 +17,7 @@ function Text(props) { ...@@ -18,6 +17,7 @@ function Text(props) {
aria-invalid={!props.isValid} aria-invalid={!props.isValid}
disabled={props.disabled} disabled={props.disabled}
required={props.required} required={props.required}
ref={props.inputRef}
/> />
); );
} }
......
...@@ -8,6 +8,7 @@ import asInput, { getDisplayName } from './index'; ...@@ -8,6 +8,7 @@ import asInput, { getDisplayName } from './index';
function testComponent(props) { function testComponent(props) {
return ( return (
<input <input
id={props.id}
defaultValue={props.value} defaultValue={props.value}
onBlur={props.onBlur} onBlur={props.onBlur}
onChange={props.onChange} onChange={props.onChange}
...@@ -43,6 +44,43 @@ describe('asInput()', () => { ...@@ -43,6 +44,43 @@ describe('asInput()', () => {
expect(wrapper.state('value')).toEqual(props.value); expect(wrapper.state('value')).toEqual(props.value);
}); });
it('creates generic prop id', () => {
const props = {
...baseProps,
};
const wrapper = mount(<InputTestComponent {...props} />);
expect(wrapper.state('id')).toContain('asInput');
expect(wrapper.find('label').prop('id')).toContain('asInput');
expect(wrapper.find('input').prop('id')).toContain('asInput');
expect(wrapper.find('small').prop('id')).toContain('asInput');
});
it('creates generic prop id when passed null id value', () => {
const testId = null;
const props = {
...baseProps,
id: testId,
};
const wrapper = mount(<InputTestComponent {...props} />);
expect(wrapper.state('id')).toContain('asInput');
expect(wrapper.find('label').prop('id')).toContain('asInput');
expect(wrapper.find('input').prop('id')).toContain('asInput');
expect(wrapper.find('small').prop('id')).toContain('asInput');
});
it('uses passed in prop id', () => {
const testId = 'testId';
const props = {
...baseProps,
id: testId,
};
const wrapper = mount(<InputTestComponent {...props} />);
expect(wrapper.state('id')).toEqual(testId);
expect(wrapper.find('label').prop('id')).toEqual(`label-${testId}`);
expect(wrapper.find('input').prop('id')).toEqual(testId);
expect(wrapper.find('small').prop('id')).toEqual(`description-${testId}`);
});
describe('fires', () => { describe('fires', () => {
it('blur handler', () => { it('blur handler', () => {
const spy = jest.fn(); const spy = jest.fn();
......
...@@ -11,6 +11,7 @@ export const getDisplayName = WrappedComponent => ...@@ -11,6 +11,7 @@ export const getDisplayName = WrappedComponent =>
export const inputProps = { export const inputProps = {
label: PropTypes.string.isRequired, label: PropTypes.string.isRequired,
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
id: PropTypes.string,
value: PropTypes.string, value: PropTypes.string,
description: PropTypes.oneOfType([ description: PropTypes.oneOfType([
PropTypes.string, PropTypes.string,
...@@ -31,7 +32,7 @@ const asInput = (WrappedComponent, labelFirst = true) => { ...@@ -31,7 +32,7 @@ const asInput = (WrappedComponent, labelFirst = true) => {
this.handleChange = this.handleChange.bind(this); this.handleChange = this.handleChange.bind(this);
this.handleBlur = this.handleBlur.bind(this); this.handleBlur = this.handleBlur.bind(this);
const id = newId('asInput'); const id = this.props.id ? this.props.id : newId('asInput');
this.state = { this.state = {
id, id,
value: this.props.value, value: this.props.value,
...@@ -90,7 +91,7 @@ const asInput = (WrappedComponent, labelFirst = true) => { ...@@ -90,7 +91,7 @@ const asInput = (WrappedComponent, labelFirst = true) => {
const { description, error, describedBy } = this.getDescriptions(); const { description, error, describedBy } = this.getDescriptions();
return ( return (
<div className={styles['form-group']}> <div className={styles['form-group']}>
{labelFirst && <label htmlFor={this.state.id}>{this.props.label}</label>} {labelFirst && <label id={`label-${this.state.id}`} htmlFor={this.state.id}>{this.props.label}</label>}
<WrappedComponent <WrappedComponent
{...this.props} {...this.props}
{...this.state} {...this.state}
...@@ -117,6 +118,7 @@ const asInput = (WrappedComponent, labelFirst = true) => { ...@@ -117,6 +118,7 @@ const asInput = (WrappedComponent, labelFirst = true) => {
NewComponent.defaultProps = { NewComponent.defaultProps = {
onChange: () => {}, onChange: () => {},
onBlur: () => {}, onBlur: () => {},
id: newId('asInput'),
value: '', value: '',
description: undefined, description: undefined,
disabled: false, disabled: false,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment