Merge with master and solve conflicts

old
Javi Velasco 2015-07-07 22:43:55 +02:00
commit 8344e94a37
13 changed files with 396 additions and 93 deletions

View File

@ -34,6 +34,7 @@ INPUT_HEIGHT = (2 * SPACE)
BUTTON_HEIGHT = (2.5 * SPACE)
BUTTON_CIRCLE_HEIGHT = (2.75 * SPACE)
LOADING_HEIGHT = (1.5 * UNIT)
PROGRESS_BAR_HEIGHT = (SPACE / 4)
// -- Shadows
ZDEPTH_SHADOW_1 = 0 1px 6px rgba(0,0,0,0.12), 0 1px 4px rgba(0,0,0,0.24)

View File

@ -3,28 +3,33 @@
```
var DropDown = require('react-toolbox/components/dropdown');
var data = [
{ '1': 'Never' },
{ '2': 'Every Night' },
{ '3': 'Weeknights' },
{ '4': 'Weekends' },
{ '5': 'Weekly' },
var countries: [
value: 'ES-es', label: 'Spain', img: 'http://'
,
value: 'TH-th', label: 'Thailand', img: 'http://'
,
value: 'EN-gb', label: 'England', img: 'http://'
,
value: 'EN-en', label: 'USA', img: 'http://'
,
value: 'FR-fr', label: 'France', img: 'http://'
];
<DropDown dataSource={data} value='2' />
<DropDown dataSource={countries} value='TH-th' />
```
## Properties
| Name | Type | Default | Description|
| Name | Type | Default | Description |
|:- |:-: | :- |:-|
| **className** | String | | Set the class-styles of the Component.|
| **dataSource** | Object | | JSON data representing all items in the dropdown.|
| **disabled** | Boolean | false | Set components disabled.|
| **label** | String | | The text string to use for the floating label element.|
| **onChange** | Function | | Callback function that is fired when the components's value changes.|
| **value** | String | | Default value using JSON data.|
| **type** | String | "normal" | Type of the component, overwrite this property if you need set a different stylesheet.|
| **className** | String | | Set the class-styles of the Component.
| **dataSource** | Array | | JSON data representing all items in the dropdown.
| **disabled** | Boolean | false | Set components disabled.
| **label** | String | | The text string to use for the floating label element.
| **onChange** | Function | | Callback function that is fired when the components's value changes.
| **template** | Function | | Callback function that represents a item for the component.
| **type** | String | "normal" | Type of the component, overwrite this property if you need set a different stylesheet.
| **value** | String | | Default value using JSON data.
## Methods
@ -33,11 +38,13 @@ Returns the value of the input.
```
dropdown_instance.getValue();
> 'TH-th'
```
#### setValue
Sets the value of the input element.
```
dropdown_instance.setValue(newValue);
var new_value = 'ES-es'
dropdown_instance.setValue(new_value);
```

View File

@ -12,23 +12,32 @@ module.exports = React.createClass
# -- States & Properties
propTypes:
className : React.PropTypes.string
dataSource : React.PropTypes.object
dataSource : React.PropTypes.array
disabled : React.PropTypes.disabled
label : React.PropTypes.string
onChange : React.PropTypes.func
template : React.PropTypes.func
type : React.PropTypes.string
value : React.PropTypes.string
getDefaultProps: ->
className : ""
dataSource : {}
dataSource : []
disabled : false
type : "normal"
getInitialState: ->
active : false
value : @props.value or Object.keys(@props.dataSource)[0]
ripple : undefined
selected : _selectValue @props.value, @props.dataSource
# -- Lifecycle
componentDidMount: ->
@setState
height: @refs.values.getDOMNode().firstElementChild.getBoundingClientRect().height
componentDidUpdate: (prev_props, prev_state) ->
@props.onChange? @ if prev_state.selected isnt @state.selected and prev_state.active
# -- Events
onSelect: (event) ->
@ -36,16 +45,17 @@ module.exports = React.createClass
onItem: (event) ->
unless @props.disabled
target = event.target
client = target.getBoundingClientRect?()
@setState
active : false
value : target.getAttribute "id"
ripple :
left : event.pageX - client?.left
top : event.pageY - client?.top
width : (client?.width * 2)
@props.onChange event, @
client = event.target.getBoundingClientRect?()
value = event.target.getAttribute("id").toString()
for item in @props.dataSource when item.value.toString() is value
@setState
active : false
selected : item
ripple :
left : event.pageX - client?.left
top : event.pageY - client?.top
width : (client?.width * 2)
break
# -- Render
render: ->
@ -53,25 +63,41 @@ module.exports = React.createClass
className += " disabled" if @props.disabled
if @state.active is true
className += " active"
stylesheet = height: @refs.value.getDOMNode().offsetHeight * Object.keys(@props.dataSource).length
stylesheet = height: @state.height * @props.dataSource.length
<div data-component-dropdown={@props.type} className={className}>
{ <label>{@props.label}</label> if @props.label }
<ul style={stylesheet}>
<ul ref="values" style={stylesheet} onClick={@onItem}>
{
for key, label of @props.dataSource
<li id={key} onClick={@onItem} className={"selected" if key is @state.value}>
{label}
{ <Ripple origin={@state.ripple}/> if key is @state.value }
for item in @props.dataSource
<li id={item.value} className={"selected" if item.value is @state.selected.value}>
{ if @props.template then @props.template item else item.label }
{ <Ripple origin={@state.ripple}/> if item.value is @state.selected.value }
</li>
}
</ul>
<span ref="value" onClick={@onSelect}>{@props.dataSource[@state.value]}</span>
<div ref="value" onClick={@onSelect}>
{
if @props.template
@props.template @state.selected
else
<span>{@state.selected.label}</span>
}
</div>
</div>
# -- Extends
getValue: ->
@state.value
@state.selected.value
setValue: (data) ->
@setState value: data
@setState selected: data
# -- Internal methods
_selectValue = (value, dataSource) ->
if value
for item in dataSource when item.value.toString() is value.toString()
return item
break
else
dataSource[0]

View File

@ -9,10 +9,10 @@
// -- Class
&.active
> label, > span
> label, > div
opacity : 0
transform translateY((INPUT_HEIGHT / 4))
> span:after
> div:after
transform scale(0)
> ul
opacity : 1
@ -30,39 +30,23 @@
&.disabled
color : FORM_BORDER_COLOR
border-bottom-style : dotted
> span:after
> div:after
transform scale(0)
// -- Children
> *
width : 100%
> label, > span
> label, > div
transition-property opacity, transform
transition-duration ANIMATION_DURATION
transition-timing-function ANIMATION_EASE
> label + ul
top : SPACE
> label
position : relative
bottom : -(SPACE / 4)
font-size : FONT_SIZE_TINY
color : FORM_BORDER_COLOR
> span
display : block
height : INPUT_HEIGHT
line-height : INPUT_HEIGHT
font-size : FONT_SIZE_NORMAL
&:after
SIZE = (INPUT_HEIGHT / 7)
position : absolute
content : ""
right : (SPACE / 2)
bottom : SPACE
width : 0
height : 0
border-left : BORDER = SIZE solid transparent
border-right : BORDER
border-top : SIZE solid FORM_BORDER_COLOR
transition transform ANIMATION_DURATION ANIMATION_EASE
> ul
z-index : 2
position : absolute
@ -93,6 +77,24 @@
pointer-events : none
> [data-component-ripple]
background-color : lighten(FORM_BORDER_COLOR, 50%)
> div
display : block
> span
height : INPUT_HEIGHT
font-size : FONT_SIZE_NORMAL
line-height : INPUT_HEIGHT
> :not(span)
margin : (SPACE / 2) 0
&:after
SIZE = (INPUT_HEIGHT / 7)
position : absolute
content : ""
right : (SPACE / 2)
bottom : SPACE
width : 0
height : 0
border-left : BORDER = SIZE solid transparent
border-right : BORDER
border-top : SIZE solid FORM_BORDER_COLOR
transition transform ANIMATION_DURATION ANIMATION_EASE
> label + ul
top : SPACE

View File

@ -14,4 +14,5 @@ module.exports =
Loading : require "./loading"
Navigation : require "./navigation"
Ripple : require "./ripple"
ProgressBar : require "./progress_bar"
# -- Tools

View File

@ -11,21 +11,25 @@ module.exports = React.createClass
multiline : React.PropTypes.bool
onBlur : React.PropTypes.func
onChange : React.PropTypes.func
onFocus : React.PropTypes.func
onKeyPress : React.PropTypes.func
onFocus : React.PropTypes.func
onBlur : React.PropTypes.func
required : React.PropTypes.bool
type : React.PropTypes.string
value : React.PropTypes.string
getDefaultProps: ->
className : ""
type : "text"
className : ''
disabled : false
multiline : false
required : false
type : 'text'
getInitialState: ->
value : @props.value
checked : @props.value
error : @props.error
touch : @props.type in ["checkbox", "radio"]
touch : @props.type in ['checkbox', 'radio']
value : @props.value
# -- Events
onChange: (event) ->
@ -38,38 +42,38 @@ module.exports = React.createClass
# -- Render
render: ->
className = @props.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
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 ref="input" {...@props} value={@state.value}
<textarea ref='input' {...@props} value={@state.value}
onChange={@onChange}
onKeyPress={@props.onKeyPress}
onFocus={@props.onFocus}
onBlur={@props.onBlur}>{@state.value}</textarea>
else
<input ref="input" {...@props} value={@state.value} checked={@state.checked} 
<input ref='input' {...@props} value={@state.value} checked={@state.checked} 
onChange={@onChange}
onKeyPress={@props.onKeyPress}
onFocus={@props.onFocus}
onBlur={@props.onBlur}/>
}
<span className="bar"></span>
<span className='bar'></span>
{ <label>{@props.label}</label> if @props.label }
{ <span className="error">{@state.error}</span> if @state.error }
{ <span className='error'>{@state.error}</span> if @state.error }
</div>
# -- Extends
getValue: ->
@refs.input?.getDOMNode()[if @state.touch then "checked" else "value"]
@refs.input?.getDOMNode()[if @state.touch then 'checked' else 'value']
setValue: (data) ->
@setState value: data
setError: (data = "Unknown error") ->
setError: (data = 'Unknown error') ->
@setState error: @props.error or data

View File

@ -0,0 +1,69 @@
###
@todo
v2
- can set different sizes for circular progress
- maybe a multicolor indeterminate circular progress bar
- refactor vendor prefixes adding to a module
###
require './style'
module.exports = React.createClass
# -- Properties
propTypes:
buffer : React.PropTypes.number
className : React.PropTypes.string
max : React.PropTypes.number
min : React.PropTypes.number
mode : React.PropTypes.string
type : React.PropTypes.string
value : React.PropTypes.number
getDefaultProps: ->
buffer : 0
className : ''
max : 100
min : 0
mode : 'indeterminate'
type : 'linear'
value : 0
# -- Helper methods
calculateRatio: (value) ->
(value - @props.min) / (@props.max - @props.min)
# -- Render
render: ->
className = "#{@props.type} #{@props.className} #{@props.mode}"
<div data-component-progressbar role="progressbar"
className={className}
aria-valuenow={@props.value}
aria-valuemin={@props.min}
aria-valuemax={@props.max}>
{ if @props.type == 'circular' then @renderCircular() else @renderLinear() }
</div>
renderCircular: ->
style = transformDasharray(@calculateRatio(@props.value)) unless @props.mode == 'indeterminate'
<svg data-component-progressbar-circle>
<circle style={style} data-component-progressbar-circle-path cx="50" cy="50" r="45"/>
</svg>
renderLinear: ->
unless @props.mode == 'indeterminate'
bufferStyle = transformProgress(@calculateRatio(@props.buffer))
valueStyle = transformProgress(@calculateRatio(@props.value))
<div>
<span data-component-progressbar-buffer style={bufferStyle}></span>
<span data-component-progressbar-value style={valueStyle}></span>
</div>
# -- Private methods
transformDasharray = (ratio) ->
strokeDasharray: "#{2 * Math.PI * 45 * ratio}, 400"
transformProgress = (ratio) ->
WebkitTransform: "scaleX(#{ratio})"
MsTransform: "scaleX(#{ratio})"
transform: "scaleX(#{ratio})"

View File

@ -0,0 +1,27 @@
# Progress Bar
```javascript
var ProgressBar = require('react-toolbox/components/progress_bar');
// Circular indeterminate progress bar
<ProgressBar type="circular" mode="indeterminate" />
// Linear determinate progress bar with buffer
<ProgressBar type="linear" mode="determinate" value={83} buffer={90}/>
```
## Properties
| Name | Type | Default | Description|
| ------------- |:-------:|:--------------- |:---------- |
| **type** | String | `linear` | Type of the component, it can be *circular* or *linear*.|
| **mode** | String | `indeterminate` | Mode of the progress bar, it can be *determinate* or *indeterminate*.|
| **value** | Number | `0` | Value of the current progress.|
| **min** | Number | `0` | Minimum value permitted.|
| **max** | Number | `100` | Maximum value permitted.|
| **buffer** | Number | `0` | Value of a secondary progress bar useful for buffering.|
| **className** | String | `''` | Additional class name to provide custom styling.|
## Methods
This component has no methods.

View File

@ -0,0 +1,89 @@
@import '../constants.styl'
// -- NOTE: Parameters depend on the component SVG Markup too
CIRCLE_WRAPPER_WIDTH = 100
CIRCLE_RADIUS = 45
SCALE_RATIO = CIRCLE_RADIUS/20
[data-component-progressbar]
display : inline-block
&.linear
position : relative
height : PROGRESS_BAR_HEIGHT
width : 100%
background : darken(BACKGROUND, 7.5%)
overflow : hidden
[data-component-progressbar-value], [data-component-progressbar-buffer]
position : absolute
bottom : 0
left : 0
right : 0
top : 0
transform scaleX(0)
transform-origin left center
transition-duration ANIMATION_DURATION
transition-timing-function ANIMATION_EASE
[data-component-progressbar-value]
background-color : SECONDARY
[data-component-progressbar-buffer]
background-color : alpha(SECONDARY, 15%)
&.indeterminate [data-component-progressbar-value]
transform-origin center center
animation linear-indeterminate-bar 1s linear infinite
&.circular
position : relative
height : CIRCLE_WRAPPER_WIDTH * 1px
width : CIRCLE_WRAPPER_WIDTH * 1px
transform rotate(-90deg)
[data-component-progressbar-circle]
height : 100%
width : 100%
[data-component-progressbar-circle-path]
stroke-dasharray : 0, SCALE_RATIO * 200
stroke-dashoffset : 0
stroke-linecap : round
stroke-miterlimit : 20
stroke-width : 4
stroke : SECONDARY
fill : none
transition stroke-dasharray ANIMATION_DURATION ANIMATION_EASE
&.indeterminate
[data-component-progressbar-circle]
animation circular-indeterminate-bar-rotate 2s linear infinite
[data-component-progressbar-circle-path]
stroke-dasharray : SCALE_RATIO * 1, SCALE_RATIO * 200
stroke-dashoffset : 0
animation circular-indeterminate-bar-dash 1.5s ease-in-out infinite
@keyframes linear-indeterminate-bar
0%
transform translate(-50%) scaleX(0)
50%
transform translate(-0%) scaleX(0.3)
100%
transform translate(50%) scaleX(0)
@keyframes circular-indeterminate-bar-rotate
100%
transform : rotate(360deg)
@keyframes circular-indeterminate-bar-dash
0%
stroke-dasharray : SCALE_RATIO * 1, SCALE_RATIO * 200
stroke-dashoffset : SCALE_RATIO * 0
50%
stroke-dasharray : SCALE_RATIO * 89, SCALE_RATIO * 200
stroke-dashoffset : SCALE_RATIO * -35
100%
stroke-dasharray : SCALE_RATIO * 89, SCALE_RATIO * 200
stroke-dashoffset : SCALE_RATIO * -124

View File

@ -8,24 +8,50 @@ module.exports = React.createClass
# -- States & Properties
getInitialState: ->
countries: ["Spain", "England", "USA", "Thailand", "Tongo", "Slovenia"]
countries_obj:
"ES-es" : "Spain"
"TH-th" : "Thailand"
"EN-gb" : "England"
"EN-en" : "USA"
"FR-fr" : "France"
countries: [
value: "ES-es", label: "Spain", img: "http://"
,
value: "TH-th", label: "Thailand", img: "http://"
,
value: "EN-gb", label: "England", img: "http://"
,
value: "EN-en", label: "USA", img: "http://"
,
value: "FR-fr", label: "France", img: "http://"
]
selected: "TH-th"
# -- Events
onChange: (dropdown) ->
console.log "[DROPDOWN]", dropdown.getValue()
# -- Internal
customDropdownItem: (data) ->
style =
width : 32
height : 32
backgroundColor : '#ccc'
marginRight : 8
<div data-flex="horizontal grow" data-flex-content="center">
<img src={data.img} data-flex-grow="min" style={style} />
<div data-flex-grow="max" data-flex="vertical" >
<strong>{data.label}</strong>
<small>{data.value}</small>
</div>
</div>
# -- Render
render: ->
countries_selected = ["USA", "Tongo"]
countries_obj_selected = "TH-th"
<section>
<h2>Dropdown</h2>
<p>lorem ipsum...</p>
<Dropdown ref="dropdown" dataSource={@state.countries_obj} label="Countries"/>
<Dropdown ref="dropdown" dataSource={@state.countries_obj} disabled={true}/>
<Dropdown ref="dropdown" dataSource={@state.countries_obj}
value={countries_obj_selected} />
<Dropdown dataSource={@state.countries} label="Countries"
onChange={@onChange}/>
<Dropdown dataSource={@state.countries} disabled={true}
onChange={@onChange}/>
<Dropdown dataSource={@state.countries} value={@state.selected}
onChange={@onChange}/>
<Dropdown dataSource={@state.countries} value={@state.selected}
template={@customDropdownItem} onChange={@onChange}/>
</section>

View File

@ -3,6 +3,7 @@
###
Form = require '../../components/form'
Input = require '../../components/input'
module.exports = React.createClass
@ -31,7 +32,7 @@ module.exports = React.createClass
,
ref: "girl_2", type: "radio", label: "Are you a girl_2?", value: false, disabled: true
,
ref: "type_user", type: "dropdown", label: "Type of user", dataSource: {1: "Normal", 2: "Root"}
ref: "type_user", type: "dropdown", label: "Type of user", dataSource: [{value: 1, label: "Normal"}, {value: 2, label: "Root"}]
,
type: "submit", caption: "Send", style: "primary anchor", disabled: true
]

View File

@ -0,0 +1,48 @@
###
@todo
###
ProgressBar = require '../../components/progress_bar'
module.exports = React.createClass
# -- States & Properties
getInitialState: ->
progress: 0
buffer: 10
# -- Lifecycle
componentWillMount: ->
@simulateProgress()
# -- Simulate kind of a progress async function
simulateProgress: ->
setTimeout =>
if @state.progress < 100
@increaseProgress()
@increaseBuffer() if @state.progress > @state.buffer
else
@replaceState @getInitialState()
@simulateProgress()
, (Math.random() * 1 + 1) * 1000
increaseProgress: ->
@setState progress: Math.random() * 30 + @state.progress
increaseBuffer: ->
@setState buffer: Math.random() * (100 - @state.progress) + @state.progress
# -- Render
render: ->
<section>
<h2>Progress bars</h2>
<p>Determinate</p>
<ProgressBar mode="determinate" value={@state.progress} buffer={@state.buffer}/>
<p>Indeterminate...</p>
<ProgressBar mode="indeterminate"/>
<p>Circular</p>
<ProgressBar type="circular" mode="indeterminate"/>
</section>

View File

@ -7,6 +7,7 @@ Button = require './components/button'
Dialog = require './components/dialog'
Dropdown = require './components/dropdown'
Form = require './components/form'
Progress = require './components/progress'
# React = require('react/addons')
# TestUtils = React.addons.TestUtils
@ -30,6 +31,7 @@ Test = React.createClass
<Button />
<Dialog />
<Dropdown />
<Progress />
</app>
React.render <Test/>, document.body