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
11 changes: 8 additions & 3 deletions src/components/Input/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,24 @@ Readonly input:
<Input label="Readonly input" value="lorem ipsum" readonly />
```

Input with placeholder:
```js
<Input placeholder="lorem ipsum" />
```

A non-empty input with the error state:
```js
<Input label="Some input" value="lorem ipsum" status="error" hint="Need something else" />
```

An non-empty textarea:
```js
<Input label="Multiline input" value="This is a value" type="multiline" rows="3" />
<Input label="Multiline input" value="This is a value" type="multiline" rows={3} />
```

An resizeable textarea:
```js
<Input label="Multiline resizeable textarea" value="This is a value" type="multiline" rows="2" resize />
<Input label="Multiline resizeable textarea" value="This is a value" type="multiline" rows={3} resize />
```

An autoresizeable textarea:
Expand All @@ -46,5 +51,5 @@ An autoresizeable textarea:

An autoresizeable textarea with custom initial number of rows:
```js
<Input label="Multiline autoresizeable textarea" value="This is a value" type="multiline" resize="auto" rows="1" />
<Input label="Multiline autoresizeable textarea" value="This is a value" type="multiline" resize="auto" rows={1} />
```
58 changes: 57 additions & 1 deletion src/components/Input/__snapshots__/input.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ exports[`Input autoresizing works correctly 1`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readonly={false}
resize="auto"
rows={2}
Expand All @@ -40,6 +41,7 @@ exports[`Input autoresizing works correctly 1`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readOnly={false}
rows={2}
tabIndex={0}
Expand Down Expand Up @@ -74,6 +76,7 @@ exports[`Input autoresizing works correctly 2`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readonly={false}
resize="auto"
rows={2}
Expand All @@ -97,11 +100,12 @@ exports[`Input autoresizing works correctly 2`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readOnly={false}
rows={2}
style={
Object {
"height": "98px",
"height": "101px",
}
}
tabIndex={0}
Expand Down Expand Up @@ -136,6 +140,7 @@ exports[`Input lifecycle works 1`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readonly={false}
resize={false}
rows={2}
Expand All @@ -158,6 +163,7 @@ exports[`Input lifecycle works 1`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readOnly={false}
tabIndex={0}
type="text"
Expand Down Expand Up @@ -190,6 +196,7 @@ exports[`Input lifecycle works 2`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readonly={false}
resize={false}
rows={2}
Expand All @@ -212,6 +219,7 @@ exports[`Input lifecycle works 2`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readOnly={false}
tabIndex={0}
type="text"
Expand Down Expand Up @@ -244,6 +252,7 @@ exports[`Input lifecycle works 3`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readonly={false}
resize={false}
rows={2}
Expand All @@ -266,6 +275,7 @@ exports[`Input lifecycle works 3`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readOnly={false}
tabIndex={0}
type="text"
Expand Down Expand Up @@ -296,6 +306,7 @@ exports[`Input renders correctly all the standard params 1`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readOnly={false}
tabIndex={0}
type="text"
Expand Down Expand Up @@ -325,6 +336,7 @@ exports[`Input renders correctly disabled 1`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readOnly={false}
tabIndex={0}
type="text"
Expand Down Expand Up @@ -354,6 +366,7 @@ exports[`Input renders correctly readonly 1`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readOnly={true}
tabIndex={0}
type="text"
Expand All @@ -368,6 +381,36 @@ exports[`Input renders correctly readonly 1`] = `
</div>
`;

exports[`Input renders correctly with a placeholder 1`] = `
<div
className="wds-input is-empty"
>
<input
className="wds-input__field "
disabled={false}
id="foo"
name="foo"
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder="That's a placeholder"
readOnly={false}
tabIndex={0}
type="text"
value=""
/>
<label
className="wds-input__label "
htmlFor="foo"
>

</label>
</div>
`;

exports[`Input renders correctly with an error status and a hint 1`] = `
<div
className="wds-input has-error"
Expand All @@ -383,6 +426,7 @@ exports[`Input renders correctly with an error status and a hint 1`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readOnly={false}
tabIndex={0}
type="text"
Expand Down Expand Up @@ -417,6 +461,7 @@ exports[`Input renders correctly with custom class names 1`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readOnly={false}
tabIndex={0}
type="text"
Expand Down Expand Up @@ -446,6 +491,7 @@ exports[`Input renders correctly with default values 1`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readOnly={false}
tabIndex={0}
type="text"
Expand Down Expand Up @@ -475,6 +521,7 @@ exports[`Input renders correctly with different types 1`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readOnly={false}
tabIndex={0}
type="text"
Expand Down Expand Up @@ -504,6 +551,7 @@ exports[`Input renders correctly with different types 2`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readOnly={false}
tabIndex={0}
type="number"
Expand Down Expand Up @@ -533,6 +581,7 @@ exports[`Input renders correctly with different types 3`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readOnly={false}
tabIndex={0}
type="email"
Expand Down Expand Up @@ -562,6 +611,7 @@ exports[`Input renders correctly with different types 4`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readOnly={false}
tabIndex={0}
type="search"
Expand Down Expand Up @@ -591,6 +641,7 @@ exports[`Input renders correctly with different types 5`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readOnly={false}
tabIndex={0}
type="tel"
Expand Down Expand Up @@ -620,6 +671,7 @@ exports[`Input renders correctly with different types 6`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readOnly={false}
tabIndex={0}
type="url"
Expand Down Expand Up @@ -649,6 +701,7 @@ exports[`Input renders correctly with different types 7`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readOnly={false}
tabIndex={0}
type="password"
Expand Down Expand Up @@ -678,6 +731,7 @@ exports[`Input renders correctly with multiline 1`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readOnly={false}
rows={3}
tabIndex={0}
Expand Down Expand Up @@ -709,6 +763,7 @@ exports[`Input renders correctly with multiline 2`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readOnly={false}
rows={3}
tabIndex={0}
Expand Down Expand Up @@ -740,6 +795,7 @@ exports[`Input renders correctly with tabIndex 1`] = `
onKeyDown={[Function]}
onKeyPress={[Function]}
onKeyUp={[Function]}
placeholder={null}
readOnly={false}
tabIndex={-2}
type="text"
Expand Down
31 changes: 26 additions & 5 deletions src/components/Input/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ class Input extends React.Component {
readOnly: this.props.readonly,
disabled: this.props.disabled,
tabIndex: this.props.tabIndex,
placeholder: this.props.placeholder,
};
}

Expand Down Expand Up @@ -169,12 +170,12 @@ class Input extends React.Component {
handleAutoResize() {
// height has to be reset first because if not it keeps increasing every time user will type a character
// setting actual height must be done in setState callback, because React might optimize this into one setState call
// scrollHeight includes padding, we need to compensate this
// keep value in sync with padding-bottom in .wds-input__field styles
const BOTTOM_PADDING = 2;
// scrollHeight includes padding but not border, we need to compensate this to avoid slight height change
// keep value in sync with bottom-border in .wds-input__field styles
const BOTTOM_BORDER_WIDTH = 1;

this.setState({dynamicTextareaHeight: 'auto'}, () => {
this.setState({dynamicTextareaHeight: `${this.input.scrollHeight - BOTTOM_PADDING}px`});
this.setState({dynamicTextareaHeight: `${this.input.scrollHeight + BOTTOM_BORDER_WIDTH}px`});
});

// to prevent scroll jumping
Expand Down Expand Up @@ -278,11 +279,29 @@ Input.propTypes = {
/**
* Label that we want to display.
*/
label: PropTypes.string.isRequired,
label: (props, propName) => {
if (props.placeholder && props[propName]) {
return new Error(`Prop ${propName} is not used when placeholder is set`);
}

if (!props.placeholder && !props[propName]) {
return new Error(`Prop ${propName} is required when placeholder is not set`);
}

if (typeof props[propName] !== 'string') {
return new Error(`Prop ${propName} is not a string`);
}

return null;
},
/**
* Hint to display
*/
hint: PropTypes.string,
/**
* Placeholder to display
*/
placeholder: PropTypes.string,
/**
* Status
*/
Expand Down Expand Up @@ -347,7 +366,9 @@ Input.defaultProps = {
autoFocus: false,
className: '',
disabled: false,
label: '',
hint: null,
placeholder: null,
hintClassName: '',
id: null,
inputClassName: '',
Expand Down
33 changes: 33 additions & 0 deletions src/components/Input/input.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ jest.mock('lodash.uniqueid');
uniqueId.mockImplementation(() => 'foo');

/* eslint-disable no-console */
function testPropTypeError(Component, props, expectedError) {
const stub = sinon.stub(console, 'error');

renderer.create(<Component {...props} />);

expect(stub.calledOnce).toEqual(true);
expect(stub.calledWithMatch(sinon.match(new RegExp(expectedError)))).toEqual(true);

console.error.restore();
}

test('Input renders correctly with default values', () => {
const component = renderer.create(
Expand Down Expand Up @@ -66,6 +76,29 @@ test('Input renders correctly with an error status and a hint', () => {
expect(component.toJSON()).toMatchSnapshot();
});

test('Input renders correctly with a placeholder', () => {
const component = renderer.create(
<Input placeholder="That's a placeholder" />,
);
expect(component.toJSON()).toMatchSnapshot();
});

test('Input throws error when rendered with a placeholder and label', () => {
testPropTypeError(
Input,
{label: 'Label', placeholder: 'Placeholder'},
'Prop label is not used when placeholder is set'
);
});

test('Input throws error when rendered without a placeholder or label', () => {
testPropTypeError(Input, {}, 'Prop label is required when placeholder is not set');
});

test('Input throws error when rendered with invalid label', () => {
testPropTypeError(Input, {label: 100}, 'Prop label is not a string');
});

test('Input renders correctly with custom class names', () => {
const component = renderer.create(
<Input
Expand Down
Loading