Skip to content

Commit

Permalink
feat(input): add form inputs
Browse files Browse the repository at this point in the history
  • Loading branch information
estevanmaito committed Jun 25, 2020
1 parent 12539d2 commit 8b4f69e
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 0 deletions.
68 changes: 68 additions & 0 deletions __tests__/Input.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React from 'react'
import { mount } from 'enzyme'
import Input from '../src/Input'

describe('Input', () => {
it('should render without crashing', () => {
mount(<Input />)
})

it('should render with base styles', () => {
const expected =
'block w-full text-sm dark:border-gray-600 focus:outline-none dark:text-gray-300 form-input'
const wrapper = mount(<Input />)

expect(wrapper.find('input').getDOMNode().getAttribute('class')).toContain(expected)
})

it('should render with active styles', () => {
const expected =
'focus:border-purple-400 focus:shadow-outline-purple dark:focus:border-gray-600 dark:focus:shadow-outline-gray dark:bg-gray-700'
const wrapper = mount(<Input />)

expect(wrapper.find('input').getDOMNode().getAttribute('class')).toContain(expected)
})

it('should render with disabled styles', () => {
const expected = 'cursor-not-allowed opacity-50 bg-gray-300 dark:bg-gray-800'
const wrapper = mount(<Input disabled />)

expect(wrapper.find('input').getDOMNode().getAttribute('class')).toContain(expected)
})

it('should render with valid styles', () => {
const expected =
'border-green-600 dark:bg-gray-700 focus:border-green-400 focus:shadow-outline-green'
const wrapper = mount(<Input valid />)

expect(wrapper.find('input').getDOMNode().getAttribute('class')).toContain(expected)
})

it('should render with invalid styles', () => {
const expected =
'border-red-600 dark:text-gray-300 dark:bg-gray-700 focus:border-red-400 focus:shadow-outline-red'
const wrapper = mount(<Input valid={false} />)

expect(wrapper.find('input').getDOMNode().getAttribute('class')).toContain(expected)
})

it('should render with radio styles', () => {
const expected =
'text-purple-600 form-radio focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:focus:shadow-outline-gray'
const wrapper = mount(<Input type="radio" />)

expect(wrapper.find('input[type="radio"]').getDOMNode().getAttribute('class')).toContain(
expected
)
})

it('should render with checkbox styles', () => {
const expected =
'text-purple-600 form-checkbox focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:focus:shadow-outline-gray'
const wrapper = mount(<Input type="checkbox" />)

expect(wrapper.find('input[type="checkbox"]').getDOMNode().getAttribute('class')).toContain(
expected
)
})
})
65 changes: 65 additions & 0 deletions src/Input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React, { useContext } from 'react'
import classNames from 'classnames'
import PropTypes from 'prop-types'
import { ThemeContext } from './context/ThemeContext'
import defaultTheme from './themes/default'

const Input = React.forwardRef(function Input(props, ref) {
const { valid, disabled, className, type, ...other } = props

const { input } = useContext(ThemeContext) || defaultTheme

const baseStyle = input.base
const activeStyle = input.active
const disabledStyle = input.disabled
const validStyle = input.valid
const invalidStyle = input.invalid
const radioStyle = input.radio
const checkStyle = input.checkbox

function hasValidation(valid) {
return valid !== undefined
}

function validationStyle(valid) {
if (hasValidation(valid)) {
return valid ? validStyle : invalidStyle
}
}

function typeStyle(type) {
switch (type) {
case 'radio':
return radioStyle
case 'checkbox':
return checkStyle
default:
return baseStyle
}
}

const cls = classNames(
typeStyle(type),
// don't apply activeStyle if has valid or disabled
!hasValidation(valid) && !disabled && activeStyle,
// don't apply disabledStyle if has valid
!hasValidation(valid) && disabled && disabledStyle,
validationStyle(valid),
className
)

return <input className={cls} type={type} ref={ref} disabled={disabled} {...other} />
})

Input.propTypes = {
type: PropTypes.string,
disabled: PropTypes.bool,
valid: PropTypes.bool,
className: PropTypes.string,
}

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

export default Input
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { default as Button } from './Button'
export { default as Card } from './Card'
export { default as CardBody } from './CardBody'
export { default as HelperText } from './HelperText'
export { default as Input } from './Input'
15 changes: 15 additions & 0 deletions src/themes/default.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
export default {
// Input
input: {
base:
'block w-full text-sm dark:border-gray-600 focus:outline-none dark:text-gray-300 form-input',
active:
'focus:border-purple-400 focus:shadow-outline-purple dark:focus:border-gray-600 dark:focus:shadow-outline-gray dark:bg-gray-700',
disabled: 'cursor-not-allowed opacity-50 bg-gray-300 dark:bg-gray-800',
valid: 'border-green-600 dark:bg-gray-700 focus:border-green-400 focus:shadow-outline-green',
invalid:
'border-red-600 dark:text-gray-300 dark:bg-gray-700 focus:border-red-400 focus:shadow-outline-red',
radio:
'text-purple-600 form-radio focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:focus:shadow-outline-gray',
checkbox:
'text-purple-600 form-checkbox focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:focus:shadow-outline-gray',
},
// HelperText
helperText: {
base: 'text-xs',
Expand Down

0 comments on commit 8b4f69e

Please sign in to comment.