Enhaced <Form/> and <Input/>
parent
083375cdee
commit
fa7d199c1f
|
@ -2,6 +2,7 @@
|
|||
@todo
|
||||
###
|
||||
|
||||
Style = require './style/form'
|
||||
Button = require "./button"
|
||||
Input = require "./input"
|
||||
|
||||
|
|
|
@ -2,11 +2,13 @@
|
|||
@todo
|
||||
###
|
||||
|
||||
Style = require './style/input'
|
||||
|
||||
module.exports = React.createClass
|
||||
|
||||
# -- States & Properties
|
||||
propTypes:
|
||||
type : React.PropTypes.string.required
|
||||
type : React.PropTypes.string
|
||||
label : React.PropTypes.string
|
||||
value : React.PropTypes.string
|
||||
error : React.PropTypes.string
|
||||
|
@ -14,47 +16,54 @@ module.exports = React.createClass
|
|||
disabled : React.PropTypes.bool
|
||||
multiline : React.PropTypes.bool
|
||||
onChange : React.PropTypes.func
|
||||
style : React.PropTypes.object
|
||||
|
||||
getDefaultProps: ->
|
||||
type : "text"
|
||||
required : false
|
||||
disabled : false
|
||||
multiline : false
|
||||
style :
|
||||
borderBottom : "solid 2px red"
|
||||
|
||||
getInitialState: ->
|
||||
value : @props.value
|
||||
checked : @props.value
|
||||
error : @props.error
|
||||
touch : @props.type in ["checkbox", "radio"]
|
||||
|
||||
# -- Events
|
||||
onChange: (event) ->
|
||||
@setState value: event.target.value
|
||||
if @state.touch
|
||||
@setState checked: event.target.checked, error: undefined
|
||||
else
|
||||
@setState value: event.target.value, error: undefined
|
||||
@props.onChange? event, @
|
||||
|
||||
# -- Render
|
||||
render: ->
|
||||
# -- styles
|
||||
style = ""
|
||||
style += " error" if @props.error
|
||||
# -- tag
|
||||
<div data-component-input={@props.type} className={style} style={@props.style}>
|
||||
className = ""
|
||||
className += " disabled" if @props.disabled
|
||||
className += " error" if @state.error
|
||||
className += " touch" if @state.touch
|
||||
className += " radio" if @props.type is "radio"
|
||||
className += " checked" if @state.checked
|
||||
|
||||
<div data-component-input={@props.type} className={className}>
|
||||
{
|
||||
if @props.multiline
|
||||
<textarea {...@props} onChange={@onChange}>{@state.value}</textarea>
|
||||
<textarea ref="input" {...@props} onChange={@onChange}>{@state.value}</textarea>
|
||||
else
|
||||
<input {...@props} value={@state.value} onChange={@onChange} />
|
||||
<input ref="input" {...@props} value={@state.value} checked={@state.checked} onChange={@onChange} />
|
||||
}
|
||||
<span className="bar"></span>
|
||||
{ <label>{@props.label}</label> if @props.label }
|
||||
{ <span className="error">{@props.error}</span> if @props.error }
|
||||
{ <span className="error">{@state.error}</span> if @state.error }
|
||||
</div>
|
||||
|
||||
# -- Extends
|
||||
getValue: ->
|
||||
@state.value
|
||||
@refs.input?.getDOMNode()[if @state.touch then "checked" else "value"]
|
||||
|
||||
setValue: (data) ->
|
||||
@setState value: data
|
||||
|
||||
setError: (data = "Unknown error") ->
|
||||
@setState error: data
|
||||
@setState error: @props.error or data
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
@import '__constants.styl'
|
||||
|
||||
[data-component-form]
|
||||
padding : SPACE
|
|
@ -0,0 +1,155 @@
|
|||
@import '__constants.styl'
|
||||
|
||||
[data-component-input]
|
||||
position : relative
|
||||
margin-bottom : SPACE
|
||||
input, textarea, label
|
||||
font-size : FONT_SIZE_NORMAL
|
||||
font-weight : FONT_WEIGHT_NORMAL
|
||||
|
||||
// -- Style
|
||||
RADIUS = (SPACE / 8)
|
||||
&.touch
|
||||
// -- Children
|
||||
input
|
||||
pointer-events : all
|
||||
z-index : 2
|
||||
position : absolute
|
||||
left : 0
|
||||
width : 100%
|
||||
height : 100%
|
||||
opacity : 0
|
||||
.bar, label
|
||||
position : relative
|
||||
display : inline-block
|
||||
vertical-align : middle
|
||||
.bar
|
||||
width : SPACE
|
||||
height : SPACE
|
||||
margin-right : (SPACE / 1.32)
|
||||
border-radius : RADIUS
|
||||
box-shadow : inset 0 0 0 RADIUS COLOR
|
||||
transition-property background-color, box-shadow
|
||||
transition-duration ANIMATION_DURATION
|
||||
transition-timing-function ANIMATION_EASE
|
||||
&:before
|
||||
z-index : -1
|
||||
position : absolute
|
||||
left : -(SPACE)
|
||||
top : -(SPACE)
|
||||
display : block
|
||||
content : ""
|
||||
width : SIZE = (3 * SPACE)
|
||||
height : SIZE
|
||||
border-radius : 50%
|
||||
opacity : 0
|
||||
&:after
|
||||
display : block
|
||||
width : SPACE
|
||||
color : WHITE
|
||||
text-align : center
|
||||
transform scale(0)
|
||||
transition transform ANIMATION_DURATION ANIMATION_DELAY ANIMATION_EASE
|
||||
label
|
||||
font-size : FONT_SIZE_SMALL
|
||||
color : COLOR
|
||||
// -- Style
|
||||
&:not(.radio) .bar:after
|
||||
content : "✓"
|
||||
&.radio .bar
|
||||
border-radius : 50%
|
||||
&.disabled .bar
|
||||
box-shadow inset 0 0 0 RADIUS lighten(COLOR, 75%)
|
||||
|
||||
&:not(.touch)
|
||||
input, textarea
|
||||
display : block
|
||||
padding : (SPACE / 2) 0
|
||||
width : 100%
|
||||
color : COLOR
|
||||
background-color : transparent
|
||||
border : none
|
||||
border-bottom : 1px solid lighten(COLOR, 75%)
|
||||
// -- Attributes
|
||||
&:focus
|
||||
outline : none
|
||||
~ .bar:before, ~ .bar:after
|
||||
width : 50%
|
||||
&:focus ~ label, &:valid ~ label
|
||||
top : -(SPACE / 2)
|
||||
font-size : FONT_SIZE_TINY
|
||||
color : THEME
|
||||
&:disabled
|
||||
border-bottom-style : dotted
|
||||
&:invalid
|
||||
&:not(:required):not(:focus)
|
||||
border-bottom-color : CANCEL
|
||||
&:focus ~ label
|
||||
color : CANCEL
|
||||
~ .bar:before, ~ .bar:after
|
||||
background-color : CANCEL
|
||||
|
||||
label
|
||||
position : absolute
|
||||
left : 0
|
||||
top : (SPACE / 2)
|
||||
color : lighten(COLOR, 75%)
|
||||
transition-property top, font-size, color
|
||||
transition-duration ANIMATION_DURATION
|
||||
transition-timing-function ANIMATION_EASE
|
||||
.bar
|
||||
position : relative
|
||||
display : block
|
||||
width : 100%
|
||||
&:before, &:after
|
||||
content : ''
|
||||
position : absolute
|
||||
height : 2px
|
||||
width : 0
|
||||
bottom : 0
|
||||
background-color : THEME
|
||||
transition-property width, background-color
|
||||
transition-duration ANIMATION_DURATION
|
||||
transition-timing-function ANIMATION_EASE
|
||||
&:before
|
||||
left : 50%
|
||||
&:after
|
||||
right : 50%
|
||||
|
||||
&.error
|
||||
input, textarea
|
||||
border-bottom-color : CANCEL
|
||||
|
||||
&.checked
|
||||
&.radio .bar
|
||||
box-shadow : inset 0 0 0 RADIUS SECONDARY, inset 0 0 0 (RADIUS * 2.5) WHITE
|
||||
&:not(.radio) .bar
|
||||
box-shadow : none
|
||||
.bar
|
||||
background-color : SECONDARY
|
||||
&:before
|
||||
background-color : alpha(SECONDARY, .5)
|
||||
animation-name ripple-touch
|
||||
animation-iteration-count 1
|
||||
animation-timing-function ANIMATION_EASE
|
||||
animation-duration (2 * ANIMATION_DURATION)
|
||||
&:after
|
||||
transform scale(1)
|
||||
|
||||
// -- Children
|
||||
label
|
||||
pointer-events : none
|
||||
.error
|
||||
position : absolute
|
||||
right : (SPACE / 4)
|
||||
bottom : -(SPACE / 1.25)
|
||||
font-size : (FONT_SIZE_TINY * 0.9)
|
||||
color : CANCEL
|
||||
|
||||
@keyframes ripple-touch
|
||||
0%
|
||||
transform scale(0)
|
||||
opacity : 1
|
||||
100%
|
||||
transform scale(1)
|
||||
opacity : 0
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
# -- Components
|
||||
Button = require "../components/button"
|
||||
Form = require "../components/form"
|
||||
|
||||
Test = React.createClass
|
||||
getInitialState: ->
|
||||
|
@ -24,20 +25,38 @@ Test = React.createClass
|
|||
# -- Render
|
||||
render: ->
|
||||
attributes = [
|
||||
ref: "name", label: "Your Name", required: true
|
||||
ref: "name", label: "Your Name", required: true#, onChange: @onInputChange
|
||||
,
|
||||
ref: "description", multiline: true, label: "Description", value: "Doer"
|
||||
,
|
||||
ref: "birthdate", type: "date", label: "Birthdate"
|
||||
,
|
||||
ref: "years", type: "number", label: "Years"
|
||||
,
|
||||
ref: "twitter", label: "Nickname", disabled: true
|
||||
,
|
||||
ref: "nomad", type: "checkbox", label: "Are you a nomad?", value: true
|
||||
,
|
||||
ref: "cow", type: "checkbox", label: "Are you a cow?", value: false
|
||||
,
|
||||
ref: "girl", type: "checkbox", label: "Are you a girl?", value: false, disabled: true
|
||||
,
|
||||
ref: "nomad_2", type: "radio", label: "Are you a nomad_2?", value: true
|
||||
,
|
||||
ref: "cow_2", type: "radio", label: "Are you a cow_2?", value: false
|
||||
,
|
||||
ref: "girl_2", type: "radio", label: "Are you a girl_2?", value: false, disabled: true
|
||||
,
|
||||
type: "submit", caption: "Send", style: "primary anchor", disabled: true
|
||||
]
|
||||
|
||||
<app>
|
||||
<h1>React-Kit</h1>
|
||||
<h2>New way for create</h2>
|
||||
|
||||
<h2>Forms</h2>
|
||||
<Form attributes={attributes} />
|
||||
|
||||
<h3>Buttons</h3>
|
||||
<Button caption="Login" disabled={not @state.submitable} />
|
||||
<Button caption="Primary" style="primary" icon="access_alarm" />
|
||||
|
|
Loading…
Reference in New Issue