diff --git a/components/constants.styl b/components/constants.styl
index 410f96c6..b658f468 100644
--- a/components/constants.styl
+++ b/components/constants.styl
@@ -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)
diff --git a/components/index.coffee b/components/index.coffee
index 2d690e24..da40a088 100644
--- a/components/index.coffee
+++ b/components/index.coffee
@@ -14,5 +14,6 @@ module.exports =
Loading : require "./loading"
Navigation : require "./navigation"
Ripple : require "./ripple"
+ ProgressBar : require "./progress_bar"
# -- Tools
Router : require "./router"
diff --git a/components/progress_bar/index.cjsx b/components/progress_bar/index.cjsx
new file mode 100644
index 00000000..750f5e53
--- /dev/null
+++ b/components/progress_bar/index.cjsx
@@ -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}"
+
+ { if @props.type == 'circular' then @renderCircular() else @renderLinear() }
+
+
+ renderCircular: ->
+ style = transformDasharray(@calculateRatio(@props.value)) unless @props.mode == 'indeterminate'
+
+
+ renderLinear: ->
+ unless @props.mode == 'indeterminate'
+ bufferStyle = transformProgress(@calculateRatio(@props.buffer))
+ valueStyle = transformProgress(@calculateRatio(@props.value))
+
+
+
+
+
+# -- Private methods
+transformDasharray = (ratio) ->
+ strokeDasharray: "#{2 * Math.PI * 45 * ratio}, 400"
+
+transformProgress = (ratio) ->
+ WebkitTransform: "scaleX(#{ratio})"
+ MsTransform: "scaleX(#{ratio})"
+ transform: "scaleX(#{ratio})"
diff --git a/components/progress_bar/progress_bar.md b/components/progress_bar/progress_bar.md
new file mode 100644
index 00000000..ccf86009
--- /dev/null
+++ b/components/progress_bar/progress_bar.md
@@ -0,0 +1,27 @@
+# Progress Bar
+
+```javascript
+var ProgressBar = require('react-toolbox/components/progress_bar');
+
+// Circular indeterminate progress bar
+
+
+// Linear determinate progress bar with buffer
+
+```
+
+## 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.
diff --git a/components/progress_bar/style.styl b/components/progress_bar/style.styl
new file mode 100644
index 00000000..76bd4d02
--- /dev/null
+++ b/components/progress_bar/style.styl
@@ -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
diff --git a/spec/components/progress.cjsx b/spec/components/progress.cjsx
new file mode 100644
index 00000000..0946e105
--- /dev/null
+++ b/spec/components/progress.cjsx
@@ -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: ->
+
+ Progress bars
+
+ Determinate
+
+
+ Indeterminate...
+
+
+ Circular
+
+
diff --git a/spec/index.cjsx b/spec/index.cjsx
index bea66306..77a99f9e 100644
--- a/spec/index.cjsx
+++ b/spec/index.cjsx
@@ -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
+
React.render , document.body