Skip to content

Commit

Permalink
feat(Input): update states to v1 API
Browse files Browse the repository at this point in the history
  • Loading branch information
levithomason committed Sep 20, 2016
1 parent aae0eeb commit d532e7a
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 54 deletions.
8 changes: 8 additions & 0 deletions docs/app/Examples/elements/Input/States/InputLeftLoading.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from 'react'
import { Input } from 'stardust'

const InputLeftLoading = () => (
<Input loading icon='user' iconPosition='left' placeholder='Search...' />
)

export default InputLeftLoading
2 changes: 1 addition & 1 deletion docs/app/Examples/elements/Input/States/InputLoading.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react'
import { Input } from 'stardust'

const InputLoading = () => (
<Input loading icon='user' iconPosition='left' placeholder='Search...' />
<Input loading icon='user' placeholder='Search...' />
)

export default InputLoading
10 changes: 8 additions & 2 deletions docs/app/Examples/elements/Input/States/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import React from 'react'
import ComponentExample from 'docs/app/Components/ComponentDoc/ComponentExample'
import ExampleSection from 'docs/app/Components/ComponentDoc/ExampleSection'

import { Message } from 'src'

const InputStates = () => (
<ExampleSection title='States'>
<ComponentExample
Expand All @@ -12,9 +14,13 @@ const InputStates = () => (
<ComponentExample
title='Loading'
description='An icon input field can show that it is currently loading data'
warning='Loading inputs automatically modify the inputs icon on loading state to show loading indication'
examplePath='elements/Input/States/InputLoading'
/>
>
<Message>
Loading inputs automatically modify the input's icon on loading state to show loading indication
</Message>
</ComponentExample>
<ComponentExample examplePath='elements/Input/States/InputLeftLoading' />
<ComponentExample
title='Disabled'
description='An input field can show that it is disabled'
Expand Down
6 changes: 3 additions & 3 deletions docs/app/Examples/elements/Input/Variations/InputAction.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ const options = [
]

const actions = [
<Select compact options={options} defaultValue='articles' />,
<Button type='submit'>Search</Button>,
<Select childKey='select' compact options={options} defaultValue='articles' />,
<Button childKey='button' type='submit'>Search</Button>,
]

const InputAction = () => (
<Input actions={actions} actionPosition='left' icon='search' placeholder='Search...' />
<Input actions={actions} actionsPosition='left' icon='search' placeholder='Search...' />
)

export default InputAction
10 changes: 5 additions & 5 deletions docs/app/Examples/elements/Input/Variations/InputActionExtra.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import React from 'react'
import { Button, Input } from 'stardust'

const action = (
<Button labeled color='teal' icon='cart'>
const actions = [
<Button childKey='button' labeled color='teal' icon='cart'>
Checkout
</Button>
)
</Button>,
]

const InputActionExtra = () => (
<Input action={action} actionPosition='left' placeholder='$23.43' />
<Input actions={actions} actionsPosition='left' placeholder='$23.43' />
)

export default InputActionExtra
95 changes: 52 additions & 43 deletions src/elements/Input/Input.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import {
SUI,
useKeyOnly,
} from '../../lib'
import Icon from '../../elements/Icon/Icon'
import {
createHTMLInput,
createIcon,
createLabel,
} from '../../factories'

const inputPropNames = [
// React
Expand Down Expand Up @@ -51,46 +55,36 @@ const inputPropNames = [
*/
function Input(props) {
const {
disabled, error, fluid, inverted, loading, size, transparent,
icon, type, children, className,
actions,
actionsPosition,
className,
disabled,
error,
focus,
fluid,
icon,
iconPosition,
inverted,
label,
labelPosition,
loading,
size,
input,
transparent,
} = 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(focus, 'focus'),
useKeyOnly(fluid, 'fluid'),
useKeyOnly(inverted, 'inverted'),
useKeyOnly(loading, 'loading'),
useKeyOnly(transparent, 'transparent'),
icon && 'icon',
iconPosition,
useKeyOnly(icon, 'icon'),
className,
'input',
)
Expand All @@ -99,14 +93,16 @@ function Input(props) {
const inputProps = _.pick(unhandledProps, inputPropNames)
const rest = _.omit(unhandledProps, inputPropNames)
const ElementType = getElementType(Input, props)

return (
<ElementType {...rest} className={classes}>
{isLeftLabeled && labelChildren}
{isLeftAction && actionChildren}
<input {...inputProps} type={type} />
{icon && <Icon name={icon} />}
{isRightLabeled && labelChildren}
{isRightAction && actionChildren}
{labelPosition !== 'right' && createLabel(label)}
{actionsPosition === 'left' && actions}
{iconPosition !== 'right' && createIcon(icon)}
{createHTMLInput(input, inputProps)}
{iconPosition === 'right' && createIcon(icon)}
{labelPosition !== 'left' && createLabel(label)}
{actionsPosition === 'right' && actions}
</ElementType>
)
}
Expand All @@ -115,10 +111,17 @@ Input._meta = {
name: 'Input',
type: META.TYPES.ELEMENT,
props: {
actionsPosition: ['left', 'right'],
iconPosition: ['right'],
labelPosition: ['left', 'right'],
size: SUI.SIZES,
},
}

Input.defaultProps = {
input: 'text',
}

Input.propTypes = {
/** Body of the component. */
children: PropTypes.node,
Expand All @@ -132,15 +135,28 @@ Input.propTypes = {
/** An input field can show the data contains errors */
error: PropTypes.bool,

/** An input field can show a user is currently interacting with it */
focus: PropTypes.bool,

/** Take on the size of it's container */
fluid: PropTypes.bool,

/** Optional icon to display in input */
icon: PropTypes.string,

/** An icon can appear inside an input on the left or right */
iconPosition: PropTypes.oneOf(Input._meta.props.iconPosition),

/** Format to appear on dark backgrounds */
inverted: PropTypes.bool,

/** Shorthand prop for creating the HTML input */
input: PropTypes.oneOfType([
PropTypes.string,
PropTypes.object,
PropTypes.element,
]),

/** An icon input field can show that it is currently loading data */
loading: PropTypes.bool,

Expand All @@ -149,13 +165,6 @@ Input.propTypes = {

/** Transparent input has no background */
transparent: PropTypes.bool,

/** Specifies the type of <input> element to display */
type: PropTypes.string,
}

Input.defaultProps = {
type: 'text',
}

export default Input
9 changes: 9 additions & 0 deletions src/factories/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ export const createImage = createFactory(Image, value => ({ src: value }))
*/
export const createImg = createFactory('img', value => ({ src: value }))

/**
* Returns an HTML input element from an input type, ReactElement, or props object.
* @type {function}
* @param {string|ReactElement|object} val The value to render.
* @param {object} [props = {}] Optional additional props.
* @returns {ReactElement|undefined}
*/
export const createHTMLInput = createFactory('input', value => ({ type: value }))

/**
* Returns a Label element from label text, ReactElement, or props object.
* @type {function}
Expand Down

0 comments on commit d532e7a

Please sign in to comment.