├── .travis.yml ├── gulpfile.js ├── react-topcoat.sublime-project ├── .gitignore ├── dist ├── topcoat │ ├── button_spec.js │ ├── tabbar.js │ ├── range.js │ ├── notification.js │ ├── listheader.js │ ├── input.js │ ├── switch.js │ ├── tab.js │ ├── list.js │ ├── searchinput.js │ ├── buttonbarbutton.js │ ├── navigationbar.js │ ├── textarea.js │ ├── button.js │ ├── buttonbar.js │ ├── listitems.js │ ├── checkbox.js │ ├── navigationbaritem.js │ └── radiobutton.js └── index.js ├── app ├── src │ ├── topcoat │ │ ├── tabbar.coffee │ │ ├── notification.coffee │ │ ├── range.coffee │ │ ├── listheader.coffee │ │ ├── list.coffee │ │ ├── switch.coffee │ │ ├── tab.coffee │ │ ├── input.coffee │ │ ├── navigationbar.coffee │ │ ├── searchinput.coffee │ │ ├── listitems.coffee │ │ ├── buttonbarbutton.coffee │ │ ├── textarea.coffee │ │ ├── button.coffee │ │ ├── buttonbar.coffee │ │ ├── checkbox.coffee │ │ ├── radiobutton.coffee │ │ ├── navigationbaritem.coffee │ │ └── button_spec.coffee │ ├── index.coffee │ └── test.coffee └── index.html ├── .editorconfig ├── README.md ├── package.json └── gulpfile.coffee /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | require('coffee-script/register'); 2 | require('./gulpfile.coffee'); 3 | -------------------------------------------------------------------------------- /react-topcoat.sublime-project: -------------------------------------------------------------------------------- 1 | { 2 | "folders": 3 | [ 4 | { 5 | "follow_symlinks": true, 6 | "path": "." 7 | } 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.sublime-workspace 2 | .*.swp 3 | ._* 4 | .DS_Store 5 | .git 6 | .hg 7 | .lock-wscript 8 | .svn 9 | .tmp/ 10 | .wafpickle-* 11 | build/ 12 | CVS 13 | node_modules 14 | npm-debug.log 15 | -------------------------------------------------------------------------------- /dist/topcoat/button_spec.js: -------------------------------------------------------------------------------- 1 | var button;button=require("./button"),describe("Button",function(){return it("should have a props property",function(){var t;return t=button(),t.should.have.ownProperty("props")})}); -------------------------------------------------------------------------------- /dist/topcoat/tabbar.js: -------------------------------------------------------------------------------- 1 | var React,TabBar,div;React=require("react/addons"),div=React.DOM.div,TabBar=React.createClass({render:function(){return div({className:"topcoat-tab-bar"},this.props.children)}}),module.exports=TabBar; -------------------------------------------------------------------------------- /dist/topcoat/range.js: -------------------------------------------------------------------------------- 1 | var Range,React,input;React=require("react/addons"),input=React.DOM.input,Range=React.createClass({render:function(){return this.transferPropsTo(input({type:"range",className:"topcoat-range"}))}}),module.exports=Range; -------------------------------------------------------------------------------- /dist/topcoat/notification.js: -------------------------------------------------------------------------------- 1 | var Notification,React,span;React=require("react/addons"),span=React.DOM.span,Notification=React.createClass({render:function(){return span({className:"topcoat-notification"},this.props.children)}}),module.exports=Notification; -------------------------------------------------------------------------------- /app/src/topcoat/tabbar.coffee: -------------------------------------------------------------------------------- 1 | React = require 'react/addons' 2 | 3 | {div} = React.DOM 4 | 5 | TabBar = React.createClass 6 | 7 | render: -> 8 | div className: 'topcoat-tab-bar', 9 | @props.children 10 | 11 | module.exports = TabBar 12 | -------------------------------------------------------------------------------- /dist/topcoat/listheader.js: -------------------------------------------------------------------------------- 1 | var ListHeader,React,h3;React=require("react/addons"),h3=React.DOM.h3,ListHeader=React.createClass({componentName:"ListHeader",render:function(){return h3({className:"topcoat-list__header"},this.props.children)}}),module.exports=ListHeader; -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /app/src/topcoat/notification.coffee: -------------------------------------------------------------------------------- 1 | React = require 'react/addons' 2 | 3 | {span} = React.DOM 4 | 5 | Notification = React.createClass 6 | 7 | render: -> 8 | span className: 'topcoat-notification', 9 | @props.children 10 | 11 | module.exports = Notification 12 | -------------------------------------------------------------------------------- /app/src/topcoat/range.coffee: -------------------------------------------------------------------------------- 1 | React = require 'react/addons' 2 | 3 | {input} = React.DOM 4 | 5 | Range = React.createClass 6 | 7 | render: -> 8 | @transferPropsTo input 9 | type: 'range' 10 | className: 'topcoat-range' 11 | 12 | module.exports = Range 13 | -------------------------------------------------------------------------------- /app/src/topcoat/listheader.coffee: -------------------------------------------------------------------------------- 1 | React = require 'react/addons' 2 | 3 | {h3} = React.DOM 4 | 5 | ListHeader = React.createClass 6 | 7 | componentName: 'ListHeader' 8 | 9 | render: -> 10 | h3 className: 'topcoat-list__header', 11 | @props.children 12 | 13 | module.exports = ListHeader 14 | -------------------------------------------------------------------------------- /app/src/topcoat/list.coffee: -------------------------------------------------------------------------------- 1 | React = require 'react/addons' 2 | 3 | {div, h3, ul, li} = React.DOM 4 | 5 | List = React.createClass 6 | 7 | propTypes: 8 | large: React.PropTypes.bool 9 | 10 | render: -> 11 | newList = true 12 | div className: 'topcoat-list', 13 | child for child in @props.children 14 | 15 | module.exports = List 16 | -------------------------------------------------------------------------------- /dist/topcoat/input.js: -------------------------------------------------------------------------------- 1 | var Input,React,input;React=require("react/addons"),input=React.DOM.input,Input=React.createClass({propTypes:{large:React.PropTypes.bool},render:function(){return this.transferPropsTo(input({type:"text",className:""+this._className()}))},_className:function(){var t;return t="topcoat-text-input",this.props.large&&(t=t.concat("--large")),t}}),module.exports=Input; -------------------------------------------------------------------------------- /dist/topcoat/switch.js: -------------------------------------------------------------------------------- 1 | var React,Switch,div,input,label,_ref;React=require("react/addons"),_ref=React.DOM,label=_ref.label,input=_ref.input,div=_ref.div,Switch=React.createClass({render:function(){return label({className:"topcoat-switch"},this.transferPropsTo(input({type:"checkbox",className:"topcoat-switch__input"})),div({className:"topcoat-switch__toggle"}))}}),module.exports=Switch; -------------------------------------------------------------------------------- /dist/topcoat/tab.js: -------------------------------------------------------------------------------- 1 | var React,Tab,button,input,label,_ref;React=require("react/addons"),_ref=React.DOM,label=_ref.label,input=_ref.input,button=_ref.button,Tab=React.createClass({render:function(){return label({className:"topcoat-tab-bar__item"},this.transferPropsTo(input({type:"radio",name:"tab-bar"})),button({className:"topcoat-tab-bar__button"},this.props.children))}}),module.exports=Tab; -------------------------------------------------------------------------------- /app/src/topcoat/switch.coffee: -------------------------------------------------------------------------------- 1 | React = require 'react/addons' 2 | 3 | {label, input, div} = React.DOM 4 | 5 | Switch = React.createClass 6 | 7 | render: -> 8 | label className: 'topcoat-switch', 9 | @transferPropsTo input 10 | type: 'checkbox' 11 | className: 'topcoat-switch__input' 12 | div className: 'topcoat-switch__toggle' 13 | 14 | module.exports = Switch 15 | -------------------------------------------------------------------------------- /dist/topcoat/list.js: -------------------------------------------------------------------------------- 1 | var List,React,div,h3,li,ul,_ref;React=require("react/addons"),_ref=React.DOM,div=_ref.div,h3=_ref.h3,ul=_ref.ul,li=_ref.li,List=React.createClass({propTypes:{large:React.PropTypes.bool},render:function(){var e,r;return r=!0,div({className:"topcoat-list"},function(){var r,t,a,i;for(a=this.props.children,i=[],r=0,t=a.length;t>r;r++)e=a[r],i.push(e);return i}.call(this))}}),module.exports=List; -------------------------------------------------------------------------------- /app/src/topcoat/tab.coffee: -------------------------------------------------------------------------------- 1 | React = require 'react/addons' 2 | 3 | {label, input, button} = React.DOM 4 | 5 | Tab = React.createClass 6 | 7 | render: -> 8 | label className: 'topcoat-tab-bar__item', 9 | @transferPropsTo input 10 | type: 'radio' 11 | name: 'tab-bar' 12 | button className: 'topcoat-tab-bar__button', 13 | @props.children 14 | 15 | module.exports = Tab 16 | -------------------------------------------------------------------------------- /dist/topcoat/searchinput.js: -------------------------------------------------------------------------------- 1 | var React,SearchInput,input;React=require("react/addons"),input=React.DOM.input,SearchInput=React.createClass({propTypes:{large:React.PropTypes.bool},render:function(){return input({type:"search",className:""+this._className(),placeholder:null!=this.props.placeholder||"search"})},_className:function(){var e;return e="topcoat-search-input",this.props.large&&(e=e.concat("--large")),e}}),module.exports=SearchInput; -------------------------------------------------------------------------------- /dist/topcoat/buttonbarbutton.js: -------------------------------------------------------------------------------- 1 | var ButtonBarButton,React,button;React=require("react/addons"),button=React.DOM.button,ButtonBarButton=React.createClass({propTypes:{large:React.PropTypes.bool},render:function(){return this.transferPropsTo(button({className:""+this._className()},this.props.children))},_className:function(){var t;return t="topcoat-button-bar__button",this.props.large&&(t=t.concat("--large")),t}}),module.exports=ButtonBarButton; -------------------------------------------------------------------------------- /dist/topcoat/navigationbar.js: -------------------------------------------------------------------------------- 1 | var NavigationBar,NavigationBarItem,React,div,h1,_ref;React=require("react/addons"),NavigationBarItem=require("./navigationbaritem"),_ref=React.DOM,div=_ref.div,h1=_ref.h1,NavigationBar=React.createClass({propTypes:{onTop:React.PropTypes.bool},render:function(){var a;return a=React.addons.classSet({"topcoat-navigation-bar":!0,"on-top":this.props.onTop}),div({className:a},this.props.children)}}),module.exports=NavigationBar; -------------------------------------------------------------------------------- /app/src/topcoat/input.coffee: -------------------------------------------------------------------------------- 1 | React = require 'react/addons' 2 | 3 | {input} = React.DOM 4 | 5 | Input = React.createClass 6 | 7 | propTypes: 8 | large: React.PropTypes.bool 9 | 10 | render: -> 11 | @transferPropsTo input 12 | type: 'text' 13 | className: "#{@_className()}" 14 | 15 | _className: -> 16 | className = 'topcoat-text-input' 17 | className = className.concat '--large' if @props.large 18 | className 19 | 20 | module.exports = Input 21 | -------------------------------------------------------------------------------- /dist/topcoat/textarea.js: -------------------------------------------------------------------------------- 1 | var React,TextArea,textarea;React=require("react/addons"),textarea=React.DOM.textarea,TextArea=React.createClass({propTypes:{value:React.PropTypes.string,large:React.PropTypes.bool},getDefaultProps:function(){return{rows:"6"}},render:function(){return this.transferPropsTo(textarea({type:"text",rows:this.props.rows,className:""+this._className()}))},_className:function(){var e;return e="topcoat-textarea",this.props.large&&(e=e.concat("--large")),e}}),module.exports=TextArea; -------------------------------------------------------------------------------- /app/src/topcoat/navigationbar.coffee: -------------------------------------------------------------------------------- 1 | React = require 'react/addons' 2 | NavigationBarItem = require './navigationbaritem' 3 | 4 | {div, h1} = React.DOM 5 | 6 | NavigationBar = React.createClass 7 | 8 | propTypes: 9 | onTop: React.PropTypes.bool 10 | 11 | render: -> 12 | classSet = React.addons.classSet 13 | 'topcoat-navigation-bar': true 14 | 'on-top': @props.onTop 15 | div className: classSet, 16 | @props.children 17 | 18 | module.exports = NavigationBar 19 | -------------------------------------------------------------------------------- /dist/topcoat/button.js: -------------------------------------------------------------------------------- 1 | var Button,React,button;React=require("react/addons"),button=React.DOM.button,Button=React.createClass({propTypes:{cta:React.PropTypes.bool,quiet:React.PropTypes.bool,large:React.PropTypes.bool},render:function(){return this.transferPropsTo(button({className:""+this._className()},this.props.children))},_className:function(){var t;return t="topcoat-button",this.props.large&&(t=t.concat("--large")),this.props.cta&&(t=t.concat("--cta")),this.props.quiet&&(t=t.concat("--quiet")),t}}),module.exports=Button; -------------------------------------------------------------------------------- /dist/topcoat/buttonbar.js: -------------------------------------------------------------------------------- 1 | var ButtonBar,ButtonBarButton,React,div;React=require("react/addons"),ButtonBarButton=require("./buttonbarbutton"),div=React.DOM.div,ButtonBar=React.createClass({render:function(){var t,r;return div({className:"topcoat-button-bar"},function(){var a,e,o,n;if(Array.isArray(this.props.children)){for(o=this.props.children,n=[],r=a=0,e=o.length;e>a;r=++a)t=o[r],n.push(div({key:r,className:"topcoat-button-bar__item"},t));return n}return div({className:"topcoat-button-bar__item"},t)}.call(this))}}),module.exports=ButtonBar; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | React Topcoat 2 | ======= 3 | 4 | [Topcoat](http://topcoat.io) components built with [React](http://facebook.github.io/react/). 5 | 6 | #### Build tasks 7 | 8 | - `gulp` defaults to `gulp build` 9 | - `gulp clean` 10 | 11 | #### Test tasks 12 | 13 | - `gulp test:console` runs mocha tests in console 14 | - `gulp test:web` runs the web/test server at http://localhost:3000 15 | 16 | #### Demo App 17 | 18 | A demo app that builds for Web/Chrome/iOS/Android can be found at: 19 | 20 | - https://github.com/plaxdan/react-topcoat-demo 21 | -------------------------------------------------------------------------------- /app/src/topcoat/searchinput.coffee: -------------------------------------------------------------------------------- 1 | React = require 'react/addons' 2 | 3 | {input} = React.DOM 4 | 5 | SearchInput = React.createClass 6 | 7 | propTypes: 8 | large: React.PropTypes.bool 9 | 10 | render: -> 11 | input 12 | type: 'search' 13 | className: "#{@_className()}" 14 | placeholder: @props.placeholder? or 'search' 15 | 16 | _className: -> 17 | className = 'topcoat-search-input' 18 | className = className.concat '--large' if @props.large 19 | className 20 | 21 | module.exports = SearchInput 22 | -------------------------------------------------------------------------------- /dist/topcoat/listitems.js: -------------------------------------------------------------------------------- 1 | var ListItems,React,li,ul,_ref;React=require("react/addons"),_ref=React.DOM,ul=_ref.ul,li=_ref.li,ListItems=React.createClass({propTypes:{large:React.PropTypes.bool},render:function(){var t;return ul({className:"topcoat-list__container"},function(){var e,r,s,i;if(Array.isArray(this.props.children)){for(s=this.props.children,i=[],e=0,r=s.length;r>e;e++)t=s[e],i.push(this._listItem(t));return i}return this._listItem(this.props.children)}.call(this))},_listItem:function(t){return li({className:"topcoat-list__item"},t)}}),module.exports=ListItems; -------------------------------------------------------------------------------- /app/src/topcoat/listitems.coffee: -------------------------------------------------------------------------------- 1 | React = require 'react/addons' 2 | 3 | {ul, li} = React.DOM 4 | 5 | ListItems = React.createClass 6 | 7 | propTypes: 8 | large: React.PropTypes.bool 9 | 10 | render: -> 11 | ul className: 'topcoat-list__container', 12 | if Array.isArray @props.children 13 | for child in @props.children 14 | @_listItem child 15 | else 16 | @_listItem @props.children 17 | 18 | _listItem: (child) -> 19 | li className: 'topcoat-list__item', 20 | child 21 | 22 | module.exports = ListItems 23 | -------------------------------------------------------------------------------- /app/src/topcoat/buttonbarbutton.coffee: -------------------------------------------------------------------------------- 1 | React = require 'react/addons' 2 | 3 | {button} = React.DOM 4 | 5 | ButtonBarButton = React.createClass 6 | 7 | # TODO: set large at the parent ButtonBar 8 | propTypes: 9 | large: React.PropTypes.bool 10 | 11 | render: -> 12 | @transferPropsTo button 13 | className: "#{@_className()}", 14 | 15 | @props.children 16 | 17 | _className: -> 18 | className = 'topcoat-button-bar__button' 19 | className = className.concat '--large' if @props.large 20 | className 21 | 22 | module.exports = ButtonBarButton 23 | -------------------------------------------------------------------------------- /app/src/topcoat/textarea.coffee: -------------------------------------------------------------------------------- 1 | React = require 'react/addons' 2 | 3 | {textarea} = React.DOM 4 | 5 | TextArea = React.createClass 6 | 7 | propTypes: 8 | value: React.PropTypes.string 9 | large: React.PropTypes.bool 10 | 11 | getDefaultProps: -> 12 | rows: '6' 13 | 14 | render: -> 15 | @transferPropsTo textarea 16 | type: 'text' 17 | rows: @props.rows 18 | className: "#{@_className()}", 19 | 20 | _className: -> 21 | className = 'topcoat-textarea' 22 | className = className.concat '--large' if @props.large 23 | className 24 | 25 | module.exports = TextArea 26 | -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Mocha Spec Runner 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/topcoat/button.coffee: -------------------------------------------------------------------------------- 1 | React = require 'react/addons' 2 | 3 | {button} = React.DOM 4 | 5 | Button = React.createClass 6 | 7 | propTypes: 8 | variant: React.PropTypes.oneOf ['cta', 'quiet'] 9 | large: React.PropTypes.bool 10 | 11 | render: -> 12 | @transferPropsTo button 13 | className: "#{@_className()}", 14 | 15 | @props.children 16 | 17 | _className: -> 18 | className = 'topcoat-button' 19 | className = className.concat '--large' if @props.large 20 | className = className.concat "--#{@props.variant}" if @props.variant? 21 | className 22 | 23 | module.exports = Button 24 | -------------------------------------------------------------------------------- /dist/topcoat/checkbox.js: -------------------------------------------------------------------------------- 1 | var Checkbox,React,div,input,label,_ref;React=require("react/addons"),_ref=React.DOM,label=_ref.label,input=_ref.input,div=_ref.div,Checkbox=React.createClass({propTypes:{labelPosition:React.PropTypes.oneOf(["left","right"])},getDefaultProps:function(){return{labelPosition:"right"}},render:function(){var e;switch(e=[this._input(),this._div()],this.props.labelPosition){case"left":e.unshift(this.props.children);break;case"right":e.push(this.props.children)}return label({className:"topcoat-checkbox"},e)},_input:function(){return this.transferPropsTo(input({type:"checkbox"}))},_div:function(){return div({className:"topcoat-checkbox__checkmark"})}}),module.exports=Checkbox; -------------------------------------------------------------------------------- /app/src/topcoat/buttonbar.coffee: -------------------------------------------------------------------------------- 1 | React = require 'react/addons' 2 | ButtonBarButton = require './buttonbarbutton' 3 | 4 | {div} = React.DOM 5 | 6 | ButtonBar = React.createClass 7 | 8 | render: -> 9 | div className: 'topcoat-button-bar', 10 | # @props.children may or may not be an Array 11 | # see: http://facebook.github.io/react/tips/children-props-type.html 12 | if Array.isArray @props.children 13 | for child, index in @props.children 14 | div key: index, className: 'topcoat-button-bar__item', 15 | child 16 | else 17 | div className: 'topcoat-button-bar__item', 18 | child 19 | 20 | module.exports = ButtonBar 21 | -------------------------------------------------------------------------------- /dist/topcoat/navigationbaritem.js: -------------------------------------------------------------------------------- 1 | var NavigationBarItem,React,div,h1,h4,_ref;React=require("react/addons"),_ref=React.DOM,div=_ref.div,h4=_ref.h4,h1=_ref.h1,NavigationBarItem=React.createClass({propTypes:{title:React.PropTypes.bool,position:React.PropTypes.oneOf(["center","left","right"]),width:React.PropTypes.oneOf(["quarter","third","half","full","three-quarters","two-thirds"])},getDefaultProps:function(){return{title:!1,position:"center",width:"full"}},render:function(){return div({className:"topcoat-navigation-bar__item "+this.props.position+" "+this.props.width},this.props.title?h1({className:"topcoat-navigation-bar__title"},this.props.children):this.props.children)}}),module.exports=NavigationBarItem; -------------------------------------------------------------------------------- /dist/topcoat/radiobutton.js: -------------------------------------------------------------------------------- 1 | var RadioButton,React,div,input,label,_ref;React=require("react/addons"),_ref=React.DOM,label=_ref.label,input=_ref.input,div=_ref.div,RadioButton=React.createClass({propTypes:{labelPosition:React.PropTypes.oneOf(["left","right"])},getDefaultProps:function(){return{labelPosition:"right"}},render:function(){var t;switch(t=[this._input(),this._div()],this.props.labelPosition){case"left":t.unshift(this.props.children);break;case"right":t.push(this.props.children)}return label({className:"topcoat-radio-button"},t)},_input:function(){return this.transferPropsTo(input({type:"radio"}))},_div:function(){return div({className:"topcoat-radio-button__checkmark"})}}),module.exports=RadioButton; -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | module.exports={Button:require("./topcoat/button"),ButtonBar:require("./topcoat/buttonbar"),ButtonBarButton:require("./topcoat/buttonbarbutton"),Checkbox:require("./topcoat/checkbox"),Input:require("./topcoat/input"),List:require("./topcoat/list"),ListHeader:require("./topcoat/listheader"),ListItems:require("./topcoat/listitems"),NavigationBar:require("./topcoat/navigationbar"),NavigationBarItem:require("./topcoat/navigationbaritem"),Notification:require("./topcoat/notification"),RadioButton:require("./topcoat/radiobutton"),Range:require("./topcoat/range"),SearchInput:require("./topcoat/searchinput"),Switch:require("./topcoat/switch"),Tab:require("./topcoat/tab"),TabBar:require("./topcoat/tabbar"),TextArea:require("./topcoat/textarea")}; -------------------------------------------------------------------------------- /app/src/topcoat/checkbox.coffee: -------------------------------------------------------------------------------- 1 | React = require 'react/addons' 2 | 3 | {label, input, div} = React.DOM 4 | 5 | Checkbox = React.createClass 6 | 7 | propTypes: 8 | labelPosition: React.PropTypes.oneOf [ 9 | 'left' 10 | 'right' 11 | ] 12 | 13 | getDefaultProps: -> 14 | labelPosition: 'right' 15 | 16 | render: -> 17 | elements = [@_input(), @_div()] 18 | switch @props.labelPosition 19 | when 'left' then elements.unshift @props.children 20 | when 'right' then elements.push @props.children 21 | 22 | label className: 'topcoat-checkbox', 23 | elements 24 | 25 | _input: -> 26 | @transferPropsTo input 27 | type: 'checkbox' 28 | 29 | _div: -> 30 | div className: 'topcoat-checkbox__checkmark' 31 | 32 | module.exports = Checkbox 33 | -------------------------------------------------------------------------------- /app/src/topcoat/radiobutton.coffee: -------------------------------------------------------------------------------- 1 | React = require 'react/addons' 2 | 3 | {label, input, div} = React.DOM 4 | 5 | RadioButton = React.createClass 6 | 7 | propTypes: 8 | labelPosition: React.PropTypes.oneOf [ 9 | 'left' 10 | 'right' 11 | ] 12 | 13 | getDefaultProps: -> 14 | labelPosition: 'right' 15 | 16 | render: -> 17 | elements = [@_input(), @_div()] 18 | switch @props.labelPosition 19 | when 'left' then elements.unshift @props.children 20 | when 'right' then elements.push @props.children 21 | 22 | label className: 'topcoat-radio-button', 23 | elements 24 | 25 | _input: -> 26 | @transferPropsTo input 27 | type: 'radio' 28 | 29 | _div: -> 30 | div className: 'topcoat-radio-button__checkmark' 31 | 32 | module.exports = RadioButton 33 | -------------------------------------------------------------------------------- /app/src/index.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | Button: require './topcoat/button' 3 | ButtonBar: require './topcoat/buttonbar' 4 | ButtonBarButton: require './topcoat/buttonbarbutton' 5 | Checkbox: require './topcoat/checkbox' 6 | Input: require './topcoat/input' 7 | List: require './topcoat/list' 8 | ListHeader: require './topcoat/listheader' 9 | ListItems: require './topcoat/listitems' 10 | NavigationBar: require './topcoat/navigationbar' 11 | NavigationBarItem: require './topcoat/navigationbaritem' 12 | Notification: require './topcoat/notification' 13 | RadioButton: require './topcoat/radiobutton' 14 | Range: require './topcoat/range' 15 | SearchInput: require './topcoat/searchinput' 16 | Switch: require './topcoat/switch' 17 | Tab: require './topcoat/tab' 18 | TabBar: require './topcoat/tabbar' 19 | TextArea: require './topcoat/textarea' 20 | -------------------------------------------------------------------------------- /app/src/topcoat/navigationbaritem.coffee: -------------------------------------------------------------------------------- 1 | React = require 'react/addons' 2 | 3 | {div, h4, h1} = React.DOM 4 | 5 | NavigationBarItem = React.createClass 6 | 7 | propTypes: 8 | title: React.PropTypes.bool 9 | position: React.PropTypes.oneOf ['center', 'left', 'right'] 10 | width: React.PropTypes.oneOf [ 11 | 'quarter' 12 | 'third' 13 | 'half' 14 | 'full' 15 | 'three-quarters' 16 | 'two-thirds' 17 | ] 18 | 19 | getDefaultProps: -> 20 | title: false 21 | position: 'center' 22 | width: 'full' 23 | 24 | render: -> 25 | div className: "topcoat-navigation-bar__item #{@props.position} #{@props.width}", 26 | if @props.title 27 | h1 className: 'topcoat-navigation-bar__title', 28 | @props.children 29 | else 30 | @props.children 31 | 32 | module.exports = NavigationBarItem 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-topcoat", 3 | "description": "React components for the Topcoat UI framework", 4 | "version": "0.0.1", 5 | "author": "Daniel Walker ", 6 | "main": "dist/index.js", 7 | "license": "MIT", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/plaxdan/react-topcoat" 11 | }, 12 | "bugs": { 13 | "url": "https://github.com/plaxdan/react-topcoat/issues" 14 | }, 15 | "keywords": [ 16 | "react", 17 | "topcoat" 18 | ], 19 | "dependencies": { 20 | "react": "~0.10.0", 21 | "topcoat": "^0.7.5" 22 | }, 23 | "devDependencies": { 24 | "gulp": "~3.5.0", 25 | "gulp-util": "~2.2.10", 26 | "gulp-concat": "~2.1.7", 27 | "gulp-uglify": "~0.1.0", 28 | "gulp-minify-css": "~0.2.0", 29 | "gulp-rename": "~0.2.2", 30 | "connect": "~2.12.0", 31 | "open": "~0.0.4", 32 | "tiny-lr": "0.0.5", 33 | "gulp-open": "~0.2.8", 34 | "gulp-browserify": "~0.3.4", 35 | "gulp-embedlr": "~0.5.2", 36 | "gulp-clean": "~0.2.4", 37 | "chai": "~1.8.1", 38 | "sinon": "~1.7.3", 39 | "sinon-chai": "~2.4.0", 40 | "gulp-mocha": "~0.4.1", 41 | "mocha": "~1.17.1", 42 | "event-stream": "~3.1.0", 43 | "coffee-script": "~1.7.1", 44 | "gulp-coffee": "~1.4.1", 45 | "gulp-livereload": "^1.2.0" 46 | }, 47 | "scripts": { 48 | "test": "gulp test" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/test.coffee: -------------------------------------------------------------------------------- 1 | chai = require 'chai' 2 | sinonChai = require 'sinon-chai' 3 | 4 | # enable 'should' assertion syntax 5 | # TODO: configure this in gulpfile 6 | expect = chai.expect 7 | chai.use sinonChai 8 | chai.should() 9 | 10 | 11 | React = require 'react/addons' 12 | 13 | describe 'Test environment', -> 14 | 15 | before -> 16 | @testUtils = React.addons.TestUtils 17 | 18 | it 'should run a basic test', -> 19 | (1 + 2).should.equal 3 20 | 21 | it 'should have access to React', -> 22 | React.should.not.be.null 23 | 24 | it 'should have access to React.addons.TestUtils', -> 25 | @testUtils.should.not.be.null 26 | 27 | describe 'ReactTopcoat module', -> 28 | ReactTopcoat = require './index' 29 | 30 | it 'should export as ReactTopcoat', -> 31 | ReactTopcoat.should.not.be.null 32 | 33 | it 'should export all the components', -> 34 | ReactTopcoat.Button.should.not.be.null 35 | ReactTopcoat.ButtonBar.should.not.be.null 36 | ReactTopcoat.ButtonBarButton.should.not.be.null 37 | ReactTopcoat.Checkbox.should.not.be.null 38 | ReactTopcoat.Input.should.not.be.null 39 | ReactTopcoat.List.should.not.be.null 40 | ReactTopcoat.ListHeader.should.not.be.null 41 | ReactTopcoat.ListItems.should.not.be.null 42 | ReactTopcoat.NavigationBar.should.not.be.null 43 | ReactTopcoat.NavigationBarItem.should.not.be.null 44 | ReactTopcoat.Notification.should.not.be.null 45 | ReactTopcoat.RadioButton.should.not.be.null 46 | ReactTopcoat.Range.should.not.be.null 47 | ReactTopcoat.SearchInput.should.not.be.null 48 | ReactTopcoat.Switch.should.not.be.null 49 | ReactTopcoat.Tab.should.not.be.null 50 | ReactTopcoat.TabBar.should.not.be.null 51 | ReactTopcoat.TextArea.should.not.be.null 52 | 53 | # TODO: do this dynamically 54 | require './topcoat/button_spec' 55 | -------------------------------------------------------------------------------- /app/src/topcoat/button_spec.coffee: -------------------------------------------------------------------------------- 1 | 2 | Button = require './button' 3 | React = require 'react/addons' 4 | button = null 5 | buttonNode = null 6 | 7 | describe 'Button', -> 8 | 9 | before -> 10 | @testUtils = React.addons.TestUtils 11 | 12 | it 'should have a props property', -> 13 | reactButton = Button() 14 | reactButton.should.have.ownProperty 'props' 15 | 16 | describe 'with variant cta', -> 17 | 18 | beforeEach -> 19 | button = Button variant: 'cta' 20 | @testUtils.renderIntoDocument button 21 | buttonNode = button.getDOMNode() 22 | 23 | it 'should have one class', -> 24 | buttonNode.classList?.length.should.equal 1 25 | 26 | it 'should have the correct class', -> 27 | buttonNode.classList[0].should.equal 'topcoat-button--cta' 28 | 29 | describe 'with variant quiet', -> 30 | 31 | beforeEach -> 32 | button = Button variant: 'quiet' 33 | @testUtils.renderIntoDocument button 34 | buttonNode = button.getDOMNode() 35 | 36 | it 'should have one class', -> 37 | buttonNode.classList?.length.should.equal 1 38 | 39 | it 'should have the correct class', -> 40 | buttonNode.classList[0].should.equal 'topcoat-button--quiet' 41 | 42 | describe 'when large', -> 43 | 44 | beforeEach -> 45 | button = Button large: true 46 | @testUtils.renderIntoDocument button 47 | buttonNode = button.getDOMNode() 48 | 49 | it 'should have one class', -> 50 | buttonNode.classList?.length.should.equal 1 51 | 52 | it 'should have the correct class', -> 53 | buttonNode.classList[0].should.equal 'topcoat-button--large' 54 | 55 | describe 'with variant cta', -> 56 | 57 | beforeEach -> 58 | button = Button large: true, variant: 'cta' 59 | @testUtils.renderIntoDocument button 60 | buttonNode = button.getDOMNode() 61 | 62 | it 'should have one class', -> 63 | buttonNode.classList?.length.should.equal 1 64 | 65 | it 'should have the correct class', -> 66 | buttonNode.classList[0].should.equal 'topcoat-button--large--cta' 67 | 68 | describe 'with variant quiet', -> 69 | 70 | beforeEach -> 71 | button = Button large: true, variant: 'quiet' 72 | @testUtils.renderIntoDocument button 73 | buttonNode = button.getDOMNode() 74 | 75 | it 'should have one class', -> 76 | buttonNode.classList?.length.should.equal 1 77 | 78 | it 'should have the correct class', -> 79 | buttonNode.classList[0].should.equal 'topcoat-button--large--quiet' 80 | 81 | -------------------------------------------------------------------------------- /gulpfile.coffee: -------------------------------------------------------------------------------- 1 | gulp = require 'gulp' 2 | http = require 'http' 3 | path = require 'path' 4 | lr = require 'tiny-lr' 5 | childProcess = (require 'child_process') 6 | connect = require 'connect' 7 | es = require 'event-stream' 8 | gutil = require 'gulp-util' 9 | clean = require 'gulp-clean' 10 | mocha = require 'gulp-mocha' 11 | coffee = require 'gulp-coffee' 12 | concat = require 'gulp-concat' 13 | uglify = require 'gulp-uglify' 14 | embedlr = require 'gulp-embedlr' 15 | refresh = require 'gulp-livereload' 16 | browserify = require 'gulp-browserify' 17 | server = do lr 18 | 19 | projectPath = "#{path.resolve __dirname}" 20 | appPath = "#{projectPath}/app" 21 | buildPath = "#{projectPath}/build" 22 | distPath = "#{projectPath}/dist" 23 | 24 | jsBuildPath = "#{buildPath}/js" 25 | testBuildPath = "#{buildPath}/test" 26 | 27 | nodeModulesPath = "#{projectPath}/node_modules" 28 | 29 | port = 3000 30 | hostname = null 31 | lrPort = gutil.env.lrport or 35729 32 | 33 | browserifyOptions = 34 | debug: not gutil.env.production 35 | 36 | # Starts the webserver 37 | gulp.task 'webserver', -> 38 | application = connect() 39 | # allows import of npm resources 40 | .use connect.static nodeModulesPath 41 | # Mount the mocha tests 42 | .use connect.static testBuildPath 43 | (http.createServer application).listen port, hostname 44 | 45 | gulp.task 'build:src', -> 46 | gulp.src "#{appPath}/src/**/*.coffee" 47 | .pipe coffee bare: true 48 | .pipe gulp.dest "#{jsBuildPath}" 49 | 50 | gulp.task 'build:tests', ['build:src'], -> 51 | gulp.src "#{jsBuildPath}/test.js", read: false 52 | .pipe browserify browserifyOptions 53 | .on 'error', gutil.log 54 | .pipe gulp.dest "#{testBuildPath}/src" 55 | .pipe refresh server 56 | 57 | gulp.task 'styles', -> 58 | gulp.src "node_modules/mocha/mocha.css" 59 | .pipe gulp.dest "#{testBuildPath}/styles" 60 | .pipe refresh server 61 | 62 | gulp.task 'html', -> 63 | gulp.src "#{appPath}/index.html" 64 | .pipe embedlr() # embeds the live reload script 65 | .pipe gulp.dest "#{testBuildPath}" 66 | .pipe refresh server 67 | 68 | gulp.task 'livereload', -> 69 | server.listen lrPort, (err) -> 70 | gutil.log err if err 71 | 72 | gulp.task 'watch', -> 73 | gulp.watch "#{appPath}/src/**", ['build:tests'] 74 | gulp.watch "#{appPath}/test.html", ['html'] 75 | 76 | gulp.task 'clean', -> 77 | gulp.src ["#{buildPath}"], read: false 78 | .pipe clean force: true 79 | 80 | gulp.task 'build', [ 81 | 'build:src' 82 | 'build:tests' 83 | 'html' 84 | 'styles' 85 | 'build:tests' 86 | ] 87 | 88 | gulp.task 'test', ['test:console'] 89 | 90 | gulp.task 'test:web', [ 91 | 'styles' 92 | 'html' 93 | 'build:tests' 94 | 'webserver' 95 | 'livereload' 96 | 'watch' 97 | ] 98 | 99 | gulp.task 'test:console', ['build:src'], -> 100 | gulp.src "#{jsBuildPath}/test.js", read: false 101 | .pipe browserify browserifyOptions 102 | .on 'error', gutil.log 103 | .pipe mocha reporter: 'nyan' 104 | .on 'error', gutil.log 105 | 106 | gulp.task 'dist', ['build'], -> 107 | gulp.src ["#{jsBuildPath}/**/*", "!#{jsBuildPath}/test.js"] 108 | .pipe uglify() 109 | .pipe gulp.dest distPath 110 | 111 | gulp.task 'default', ['dist'] 112 | --------------------------------------------------------------------------------