diff --git a/docs/app/Examples/elements/Input/Variations/InputFluidExample.js b/docs/app/Examples/elements/Input/Variations/InputFluidExample.js
index f69f9778c7..b91031688d 100644
--- a/docs/app/Examples/elements/Input/Variations/InputFluidExample.js
+++ b/docs/app/Examples/elements/Input/Variations/InputFluidExample.js
@@ -4,7 +4,7 @@ import { Input } from 'stardust'
export default class InputFluidExample extends Component {
render() {
return (
-
+
)
}
}
diff --git a/docs/app/Examples/elements/Input/Variations/InputIconExample.js b/docs/app/Examples/elements/Input/Variations/InputIconExample.js
index a56f20c3f4..13e3b55f41 100644
--- a/docs/app/Examples/elements/Input/Variations/InputIconExample.js
+++ b/docs/app/Examples/elements/Input/Variations/InputIconExample.js
@@ -4,7 +4,7 @@ import { Input } from 'stardust'
export default class InputIconExample extends Component {
render() {
return (
-
+
)
}
}
diff --git a/docs/app/Examples/elements/Input/Variations/InputInvertedExample.js b/docs/app/Examples/elements/Input/Variations/InputInvertedExample.js
index c81efec052..8e5b6d6e32 100644
--- a/docs/app/Examples/elements/Input/Variations/InputInvertedExample.js
+++ b/docs/app/Examples/elements/Input/Variations/InputInvertedExample.js
@@ -5,7 +5,7 @@ export default class InputInvertedExample extends Component {
render() {
return (
-
+
)
}
diff --git a/docs/app/Examples/elements/Input/Variations/InputSizeExample.js b/docs/app/Examples/elements/Input/Variations/InputSizeExample.js
index 7bece9a1a0..ec5de6831d 100644
--- a/docs/app/Examples/elements/Input/Variations/InputSizeExample.js
+++ b/docs/app/Examples/elements/Input/Variations/InputSizeExample.js
@@ -5,17 +5,17 @@ export default class InputSizeExample extends Component {
render() {
return (
-
+
-
+
-
+
-
+
-
+
-
+
)
diff --git a/docs/app/Examples/elements/Input/Variations/InputTransparentExample.js b/docs/app/Examples/elements/Input/Variations/InputTransparentExample.js
index 9ab2ebb87c..4c6b04914e 100644
--- a/docs/app/Examples/elements/Input/Variations/InputTransparentExample.js
+++ b/docs/app/Examples/elements/Input/Variations/InputTransparentExample.js
@@ -4,7 +4,7 @@ import { Input } from 'stardust'
export default class InputTransparentExample extends Component {
render() {
return (
-
+
)
}
}
diff --git a/src/elements/Input/Input.js b/src/elements/Input/Input.js
index a58c242842..cc8292c6da 100644
--- a/src/elements/Input/Input.js
+++ b/src/elements/Input/Input.js
@@ -1,9 +1,15 @@
import _ from 'lodash'
-import classNames from 'classnames'
-import React, { Component, PropTypes, Children } from 'react'
+import React, { PropTypes, Children } from 'react'
+import cx from 'classnames'
-import { getElementType, getUnhandledProps, META } from '../../lib'
-import { Icon } from '../../elements'
+import {
+ getElementType,
+ getUnhandledProps,
+ META,
+ SUI,
+ useKeyOnly,
+} from '../../lib'
+import Icon from '../../elements/Icon/Icon'
const inputPropNames = [
// React
@@ -43,73 +49,113 @@ const inputPropNames = [
* An Input is a field used to elicit a response from a user
* @see Form
*/
-export default class Input extends Component {
- static propTypes = {
- /** An element type to render as (string or function). */
- as: PropTypes.oneOfType([
- PropTypes.string,
- PropTypes.func,
- ]),
-
- children: PropTypes.node,
- className: PropTypes.string,
- icon: PropTypes.string,
- type: PropTypes.string,
- }
-
- static defaultProps = {
- type: 'text',
- }
-
- static _meta = {
- name: 'Input',
- type: META.TYPES.ELEMENT,
- }
-
- render() {
- const { className, children, icon, type } = this.props
- // Semantic supports actions and labels on either side of an input.
- // The element must be on the same side as the indicated class.
- // We first determine the left/right classes for each type of child,
- // then we extract the children and place them on the correct side
- // of the input.
- const isLeftAction = _.includes(className, 'left action')
- const isRightAction = !isLeftAction && _.includes(className, 'action')
- const isRightLabeled = _.includes(className, 'right labeled')
- const isLeftLabeled = !isRightLabeled && _.includes(className, 'labeled')
-
- const labelChildren = []
- const actionChildren = []
-
- Children.forEach(children, child => {
- const isAction = _.includes(['Button', 'Dropdown', 'Select'], child.type._meta.name)
- const isLabel = child.type._meta.name === 'Label'
-
- if (isAction) {
- actionChildren.push(child)
- } else if (isLabel) {
- labelChildren.push(child)
- }
- })
-
- const classes = classNames(
- 'ui',
- className,
- 'input'
- )
- const unhandledProps = getUnhandledProps(Input, this.props)
- const inputProps = _.pick(unhandledProps, inputPropNames)
- const rest = _.omit(unhandledProps, inputPropNames)
- const ElementType = getElementType(Input, this.props)
- return (
-
- {isLeftLabeled && labelChildren}
- {isLeftAction && actionChildren}
-
- {icon && }
- {isRightLabeled && labelChildren}
- {isRightAction && actionChildren}
-
- )
- }
+function Input(props) {
+ const {
+ disabled, error, fluid, inverted, loading, size, transparent,
+ icon, type, children, className,
+ } = props
+
+ // Semantic supports actions and labels on either side of an input.
+ // The element must be on the same side as the indicated class.
+ // We first determine the left/right classes for each type of child,
+ // then we extract the children and place them on the correct side
+ // of the input.
+ const isLeftAction = _.includes(className, 'left action')
+ const isRightAction = !isLeftAction && _.includes(className, 'action')
+ const isRightLabeled = _.includes(className, 'right labeled')
+ const isLeftLabeled = !isRightLabeled && _.includes(className, 'labeled')
+
+ const labelChildren = []
+ const actionChildren = []
+
+ Children.forEach(children, child => {
+ const isButton = child.type.name === 'Button'
+ const isDropdown = child.type.name === 'Dropdown'
+ const isLabel = child.type.name === 'Label'
+ const childIsAction = !isLabel && isButton || isDropdown
+
+ if (childIsAction) {
+ actionChildren.push(child)
+ } else if (isLabel) {
+ labelChildren.push(child)
+ }
+ })
+
+ const classes = cx(
+ 'ui',
+ size,
+ useKeyOnly(disabled, 'disabled'),
+ useKeyOnly(error, 'error'),
+ useKeyOnly(fluid, 'fluid'),
+ useKeyOnly(inverted, 'inverted'),
+ useKeyOnly(loading, 'loading'),
+ useKeyOnly(transparent, 'transparent'),
+ icon && 'icon',
+ className,
+ 'input',
+ )
+
+ const unhandledProps = getUnhandledProps(Input, this.props)
+ const inputProps = _.pick(unhandledProps, inputPropNames)
+ const rest = _.omit(unhandledProps, inputPropNames)
+ const ElementType = getElementType(Input, this.props)
+ return (
+
+ {isLeftLabeled && labelChildren}
+ {isLeftAction && actionChildren}
+
+ {icon && }
+ {isRightLabeled && labelChildren}
+ {isRightAction && actionChildren}
+
+ )
}
+
+Input._meta = {
+ name: 'Input',
+ type: META.TYPES.ELEMENT,
+ props: {
+ size: SUI.SIZES,
+ },
+}
+
+Input.propTypes = {
+ /** Body of the component. */
+ children: PropTypes.node,
+
+ /** Class names for custom styling. */
+ className: PropTypes.string,
+
+ /** An input field can show that it is disabled */
+ disabled: PropTypes.bool,
+
+ /** An input field can show the data contains errors */
+ error: PropTypes.bool,
+
+ /** Take on the size of it's container */
+ fluid: PropTypes.bool,
+
+ /** Optional icon to display in input */
+ icon: PropTypes.string,
+
+ /** Format to appear on dark backgrounds */
+ inverted: PropTypes.bool,
+
+ /** An icon input field can show that it is currently loading data */
+ loading: PropTypes.bool,
+
+ /** An input can vary in size */
+ size: PropTypes.oneOf(Input._meta.props.size),
+
+ /** Transparent input has no background */
+ transparent: PropTypes.bool,
+
+ /** Specifies the type of element to display */
+ type: PropTypes.string,
+}
+
+Input.defaultProps = {
+ type: 'text',
+}
+
+export default Input
diff --git a/test/specs/elements/Input/Input-test.js b/test/specs/elements/Input/Input-test.js
index 21cf1226a3..4bb11ff617 100644
--- a/test/specs/elements/Input/Input-test.js
+++ b/test/specs/elements/Input/Input-test.js
@@ -3,7 +3,7 @@ import React from 'react'
import Input from 'src/elements/Input/Input'
import * as common from 'test/specs/commonTests'
-describe('Input', () => {
+describe.only('Input', () => {
common.isConformant(Input)
common.hasUIClassName(Input)
// TODO: inputs do not render child text, only child components in special cases
@@ -11,6 +11,15 @@ describe('Input', () => {
// perhaps splitting rendersChildText() and rendersChildComponents()
// common.rendersChildren(Input)
+ common.propKeyOnlyToClassName(Input, 'disabled')
+ common.propKeyOnlyToClassName(Input, 'error')
+ common.propKeyOnlyToClassName(Input, 'fluid')
+ common.propKeyOnlyToClassName(Input, 'inverted')
+ common.propKeyOnlyToClassName(Input, 'loading')
+ common.propKeyOnlyToClassName(Input, 'transparent')
+
+ common.propValueOnlyToClassName(Input, 'size')
+
it('has the input type of text by default', () => {
shallow()
.find('input')
@@ -35,8 +44,8 @@ describe('Input', () => {
.should.have.prop('name', 'emailAddress')
})
- it('adds an Icon given an icon class and prop', () => {
- shallow()
+ it('adds an Icon given prop, but no class', () => {
+ shallow()
.should.have.descendants('Icon')
})
})