diff --git a/docs/app/Examples/addons/TextArea/Usage/TextAreaExample.js b/docs/app/Examples/addons/TextArea/Types/TextAreaExampleTextArea.js
similarity index 64%
rename from docs/app/Examples/addons/TextArea/Usage/TextAreaExample.js
rename to docs/app/Examples/addons/TextArea/Types/TextAreaExampleTextArea.js
index 1a3d119ece..f0d10fe44c 100644
--- a/docs/app/Examples/addons/TextArea/Usage/TextAreaExample.js
+++ b/docs/app/Examples/addons/TextArea/Types/TextAreaExampleTextArea.js
@@ -1,10 +1,10 @@
import React from 'react'
import { Form, TextArea } from 'semantic-ui-react'
-const TextAreaExample = () => (
+const TextAreaExampleTextArea = () => (
)
-export default TextAreaExample
+export default TextAreaExampleTextArea
diff --git a/docs/app/Examples/addons/TextArea/Types/index.js b/docs/app/Examples/addons/TextArea/Types/index.js
new file mode 100644
index 0000000000..34584d189e
--- /dev/null
+++ b/docs/app/Examples/addons/TextArea/Types/index.js
@@ -0,0 +1,16 @@
+import React from 'react'
+
+import ComponentExample from 'docs/app/Components/ComponentDoc/ComponentExample'
+import ExampleSection from 'docs/app/Components/ComponentDoc/ExampleSection'
+
+const TextAreaTypesExamples = () => (
+
+
+
+)
+
+export default TextAreaTypesExamples
diff --git a/docs/app/Examples/addons/TextArea/Usage/TextAreaExampleAutoHeight.js b/docs/app/Examples/addons/TextArea/Usage/TextAreaExampleAutoHeight.js
index 96dd0ce298..75bfbeb525 100644
--- a/docs/app/Examples/addons/TextArea/Usage/TextAreaExampleAutoHeight.js
+++ b/docs/app/Examples/addons/TextArea/Usage/TextAreaExampleAutoHeight.js
@@ -3,7 +3,7 @@ import { Form, TextArea } from 'semantic-ui-react'
const TextAreaExampleAutoHeight = () => (
)
diff --git a/docs/app/Examples/addons/TextArea/Usage/TextAreaExampleAutoHeightMinHeight.js b/docs/app/Examples/addons/TextArea/Usage/TextAreaExampleAutoHeightMinHeight.js
new file mode 100644
index 0000000000..e04e040577
--- /dev/null
+++ b/docs/app/Examples/addons/TextArea/Usage/TextAreaExampleAutoHeightMinHeight.js
@@ -0,0 +1,10 @@
+import React from 'react'
+import { Form, TextArea } from 'semantic-ui-react'
+
+const TextAreaExampleAutoHeightMinHeight = () => (
+
+)
+
+export default TextAreaExampleAutoHeightMinHeight
diff --git a/docs/app/Examples/addons/TextArea/Usage/TextAreaExampleAutoHeightRows.js b/docs/app/Examples/addons/TextArea/Usage/TextAreaExampleAutoHeightRows.js
new file mode 100644
index 0000000000..7c042026d9
--- /dev/null
+++ b/docs/app/Examples/addons/TextArea/Usage/TextAreaExampleAutoHeightRows.js
@@ -0,0 +1,10 @@
+import React from 'react'
+import { Form, TextArea } from 'semantic-ui-react'
+
+const TextAreaExampleAutoHeightRows = () => (
+
+)
+
+export default TextAreaExampleAutoHeightRows
diff --git a/docs/app/Examples/addons/TextArea/Usage/TextAreaExampleMinHeight.js b/docs/app/Examples/addons/TextArea/Usage/TextAreaExampleMinHeight.js
new file mode 100644
index 0000000000..c1d0d6e383
--- /dev/null
+++ b/docs/app/Examples/addons/TextArea/Usage/TextAreaExampleMinHeight.js
@@ -0,0 +1,10 @@
+import React from 'react'
+import { Form, TextArea } from 'semantic-ui-react'
+
+const TextAreaExampleMinHeight = () => (
+
+)
+
+export default TextAreaExampleMinHeight
diff --git a/docs/app/Examples/addons/TextArea/Usage/TextAreaExampleRows.js b/docs/app/Examples/addons/TextArea/Usage/TextAreaExampleRows.js
new file mode 100644
index 0000000000..4e06fceea3
--- /dev/null
+++ b/docs/app/Examples/addons/TextArea/Usage/TextAreaExampleRows.js
@@ -0,0 +1,10 @@
+import React from 'react'
+import { Form, TextArea } from 'semantic-ui-react'
+
+const TextAreaExampleRows = () => (
+
+)
+
+export default TextAreaExampleRows
diff --git a/docs/app/Examples/addons/TextArea/Usage/index.js b/docs/app/Examples/addons/TextArea/Usage/index.js
index 5ee3630998..fb6f17b348 100644
--- a/docs/app/Examples/addons/TextArea/Usage/index.js
+++ b/docs/app/Examples/addons/TextArea/Usage/index.js
@@ -1,20 +1,36 @@
import React from 'react'
+
import ComponentExample from 'docs/app/Components/ComponentDoc/ComponentExample'
import ExampleSection from 'docs/app/Components/ComponentDoc/ExampleSection'
-const TextAreaTypesExamples = () => (
+const TextAreaUsageExamples = () => (
+
+
+
+
+
)
-export default TextAreaTypesExamples
+export default TextAreaUsageExamples
diff --git a/docs/app/Examples/addons/TextArea/index.js b/docs/app/Examples/addons/TextArea/index.js
index ecadcbc7e3..86ac72d442 100644
--- a/docs/app/Examples/addons/TextArea/index.js
+++ b/docs/app/Examples/addons/TextArea/index.js
@@ -1,8 +1,11 @@
import React from 'react'
+
+import Types from './Types'
import Usage from './Usage'
const TextAreaExamples = () => (
+
)
diff --git a/src/addons/TextArea/TextArea.d.ts b/src/addons/TextArea/TextArea.d.ts
index 202805b158..30fc3cc2bb 100644
--- a/src/addons/TextArea/TextArea.d.ts
+++ b/src/addons/TextArea/TextArea.d.ts
@@ -11,11 +11,18 @@ export interface TextAreaProps {
/**
* Called on change.
+ *
* @param {SyntheticEvent} event - The React SyntheticEvent object
* @param {object} data - All props and the event value.
*/
onChange?: (event: React.FormEvent, data: TextAreaOnChangeData) => void;
+ /** Indicates row count for a TextArea. */
+ rows?: number;
+
+ /** Custom TextArea style. */
+ style?: Object;
+
/** The value of the textarea. */
value?: string;
}
diff --git a/src/addons/TextArea/TextArea.js b/src/addons/TextArea/TextArea.js
index cd24ba9804..794c2f2be5 100644
--- a/src/addons/TextArea/TextArea.js
+++ b/src/addons/TextArea/TextArea.js
@@ -1,5 +1,7 @@
+import _ from 'lodash'
import PropTypes from 'prop-types'
import React, { Component } from 'react'
+
import {
customPropTypes,
getElementType,
@@ -31,12 +33,19 @@ class TextArea extends Component {
*/
onChange: PropTypes.func,
+ /** Indicates row count for a TextArea. */
+ rows: PropTypes.number,
+
+ /** Custom TextArea style. */
+ style: PropTypes.object,
+
/** The value of the textarea. */
value: PropTypes.string,
}
static defaultProps = {
as: 'textarea',
+ rows: 3,
}
componentDidMount() {
@@ -56,45 +65,50 @@ class TextArea extends Component {
focus = () => (this.ref.focus())
- handleChange = (e) => {
- const { onChange } = this.props
- if (onChange) onChange(e, { ...this.props, value: e.target && e.target.value })
+ handleChange = e => {
+ const value = _.get(e, 'target.value')
- this.updateHeight(e.target)
+ _.invoke(this.props, 'onChange', e, { ...this.props, value })
+ this.updateHeight()
}
handleRef = c => (this.ref = c)
removeAutoHeightStyles = () => {
- this.ref.removeAttribute('rows')
this.ref.style.height = null
- this.ref.style.minHeight = null
this.ref.style.resize = null
}
updateHeight = () => {
- if (!this.ref) return
-
const { autoHeight } = this.props
- if (!autoHeight) return
+ if (!this.ref || !autoHeight) return
let { borderTopWidth, borderBottomWidth } = window.getComputedStyle(this.ref)
borderTopWidth = parseInt(borderTopWidth, 10)
borderBottomWidth = parseInt(borderBottomWidth, 10)
- this.ref.rows = '1'
- this.ref.style.minHeight = '0'
this.ref.style.resize = 'none'
this.ref.style.height = 'auto'
this.ref.style.height = (this.ref.scrollHeight + borderTopWidth + borderBottomWidth) + 'px'
}
render() {
- const { value } = this.props
+ const { rows, style, value } = this.props
+ const minHeight = _.get(style, 'minHeight', 0)
+
const rest = getUnhandledProps(TextArea, this.props)
const ElementType = getElementType(TextArea, this.props)
- return
+ return (
+
+ )
}
}
diff --git a/test/specs/addons/TextArea/TextArea-test.js b/test/specs/addons/TextArea/TextArea-test.js
index 36e1c3979d..15bea7f30d 100644
--- a/test/specs/addons/TextArea/TextArea-test.js
+++ b/test/specs/addons/TextArea/TextArea-test.js
@@ -40,33 +40,21 @@ describe('TextArea', () => {
},
})
- describe('focus', () => {
- it('can be set via a ref', () => {
- wrapperMount()
- const element = document.querySelector('textarea')
-
- wrapper.instance().focus()
- document.activeElement.should.equal(element)
- })
- })
-
describe('autoHeight', () => {
// simplify styles to make height assertions easier
const style = { padding: 0, fontSize: '10px', lineHeight: 1, border: 'none' }
- const assertHeight = (height) => {
+ const assertHeight = (height, minHeight = '0px') => {
const element = document.querySelector('textarea')
if (!height) {
- element.should.not.have.property('rows', 1)
- element.style.should.have.property('minHeight', '')
+ element.style.should.have.property('minHeight', minHeight)
element.style.should.have.property('resize', '')
element.style.should.have.property('height', '')
return
}
- element.should.have.property('rows', 1)
- element.style.should.have.property('minHeight', '0px')
+ element.style.should.have.property('minHeight', minHeight)
element.style.should.have.property('resize', 'none')
// CI renders textareas with an extra pixel
@@ -76,49 +64,72 @@ describe('TextArea', () => {
}
it('sets styles when true', () => {
- wrapperMount()
-
- assertHeight('10px') // 1 line
- })
- it('sets styles when there is a multiline value', () => {
- wrapperMount()
-
+ wrapperMount()
assertHeight('30px') // 3 lines
})
+
it('does not set styles when not set', () => {
wrapperMount()
-
assertHeight('') // no height
})
+
+ it('depends on minHeight value of style', () => {
+ wrapperMount()
+ assertHeight('50px', '50px')
+ })
+
+ it('depends on rows value', () => {
+ wrapperMount()
+ assertHeight('10px') // 1 line
+ })
+
+ it('sets styles when there is a multiline value', () => {
+ wrapperMount(
+
+ )
+ assertHeight('40px') // 4 lines
+ })
+
it('updates the height on change', () => {
- wrapperMount()
+ wrapperMount()
// initial height
- const element = document.querySelector('textarea')
- element.style.height.should.equal('10px')
+ assertHeight('30px') // 3 lines
// update the value and fire a change event
- element.value = 'line1\nline2\nline3'
- wrapper.simulate('change')
-
- assertHeight('30px') // 3 lines
+ wrapper.setProps({ value: 'line1\nline2\nline3\nline4' })
+ assertHeight('40px') // 4 lines
})
+
it('adds styles when toggled to true', () => {
wrapperMount()
-
- wrapper.setProps({ autoHeight: true })
+ wrapper.setProps({ autoHeight: true, rows: 1 })
assertHeight('10px') // 1 line
})
- it('removes styles when toggled to false', () => {
- wrapperMount()
+ it('removes styles when toggled to false', () => {
+ wrapperMount()
wrapper.setProps({ autoHeight: false })
assertHeight('') // no height
})
})
+ describe('focus', () => {
+ it('can be set via a ref', () => {
+ wrapperMount()
+ const element = document.querySelector('textarea')
+
+ wrapper.instance().focus()
+ document.activeElement.should.equal(element)
+ })
+ })
+
describe('onChange', () => {
it('is called with (e, data) on change', () => {
const spy = sandbox.spy()
@@ -126,11 +137,47 @@ describe('TextArea', () => {
const props = { 'data-foo': 'bar', onChange: spy }
wrapperShallow()
-
wrapper.find('textarea').simulate('change', e)
spy.should.have.been.calledOnce()
spy.should.have.been.calledWithMatch(e, { ...props, value: e.target.value })
})
})
+
+ describe('rows', () => {
+ it('has default value', () => {
+ shallow()
+ .should.have.prop('rows', 3)
+ })
+
+ it('sets prop', () => {
+ shallow()
+ .should.have.prop('rows', 1)
+ })
+ })
+
+ describe('style', () => {
+ it('applies defined style', () => {
+ const style = { marginTop: '1em', top: 0 }
+
+ wrapperShallow()
+ wrapper.should.have.style('margin-top', '1em')
+ wrapper.should.have.style('top', '0')
+ })
+
+ it('has default value of minHeight', () => {
+ shallow()
+ .should.have.style('min-height', '0')
+ })
+
+ it('sets number value of minHeight', () => {
+ shallow()
+ .should.have.style('min-height', '10px')
+ })
+
+ it('sets string value of minHeight', () => {
+ shallow()
+ .should.have.style('min-height', '10em')
+ })
+ })
})