├── .gitignore ├── .babelrc ├── dist ├── css │ ├── ProgressBar.css.map │ ├── Pagination.css.map │ ├── ProgressBar.css │ ├── ButtonGroup.css.map │ ├── Panel.css.map │ ├── Tabs.css.map │ ├── ColorPicker.css.map │ ├── Pagination.css │ ├── LoadingSpinner.css.map │ ├── ButtonGroup.css │ ├── Switch.css.map │ ├── Button.css.map │ ├── Panel.css │ ├── ColorPicker.css │ ├── Tabs.css │ ├── LoadingSpinner.css │ ├── Switch.css │ └── Button.css ├── ButtonGroup.js ├── ProgressBar.js ├── LoadingSpinner.js ├── Switch.js ├── Tabs.js ├── VimeoVideo.js ├── Button.js ├── YoutubeVideo.js ├── Panel.js ├── Pagination.js └── ColorPicker.js ├── .scss-lint.yml ├── src ├── stories │ ├── ColorPicker.js │ ├── YoutubeVideo.js │ ├── ProgressBar.js │ ├── VimeoVideo.js │ ├── Tabs.js │ ├── ButtonGroup.js │ ├── Switch.js │ ├── LoadingSpinner.js │ ├── Button.js │ ├── Panel.js │ └── Pagination.js ├── ProgressBar.jsx ├── ButtonGroup.jsx ├── LoadingSpinner.jsx ├── Switch.jsx ├── Button.jsx ├── Tabs.jsx ├── VimeoVideo.jsx ├── YoutubeVideo.jsx ├── Panel.jsx ├── Pagination.jsx └── ColorPicker.jsx ├── index.js ├── .storybook ├── webpack.config.js └── config.js ├── styles ├── ProgressBar.scss ├── mixins.scss ├── ButtonGroup.scss ├── Pagination.scss ├── Button.scss ├── Tabs.scss ├── Panel.scss ├── LoadingSpinner.scss ├── Switch.scss └── ColorPicker.scss ├── .eslintrc ├── README.md ├── Gruntfile.js ├── CHANGELOG.md └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .sass-cache 3 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { "presets": ["es2015", "react"] } 2 | -------------------------------------------------------------------------------- /dist/css/ProgressBar.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../../styles/ProgressBar.scss"],"names":[],"mappings":"AAAA;EAQE,+BAPoD;EAQpD,mBAJmC;EAKnC,aAN6B;EAO7B,iBAAgB,EAAA;EAEhB;IACE,oBAZkC;IAalC,aAAY;IACZ,iCAVgD,EAAA;EAalD;IACE,oBAjB2C;IAkB3C,iBAAgB,EAAA","file":"ProgressBar.css","sourcesContent":[null]} -------------------------------------------------------------------------------- /.scss-lint.yml: -------------------------------------------------------------------------------- 1 | linters: 2 | 3 | SelectorFormat: 4 | enabled: true 5 | convention: hyphenated_BEM 6 | 7 | Indentation: 8 | enabled: true 9 | allow_non_nested_indentation: true 10 | 11 | NameFormat: 12 | enabled: false 13 | 14 | PropertySortOrder: 15 | enabled: false 16 | 17 | ColorVariable: 18 | enabled: false 19 | 20 | ImportantRule: 21 | enabled: false 22 | -------------------------------------------------------------------------------- /dist/css/Pagination.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../../styles/Pagination.scss"],"names":[],"mappings":"AAAA;EAUE,iBAAgB;EAChB,UAAS;EACT,WAAU;EACV,mBAAkB,EAAA;EAElB;IACE,sBAAqB;IACrB,kBAhBoC,EAAA;IAkBpC;MACE,gBAAe,EAAA;EAInB;IACE,iBArBuC;IAsBvC,0BAxBiD;IAyBjD,YArBkC;IAsBlC,eAAc;IACd,iBA1BwC;IA2BxC,0BAAyB;IACzB,sBAAqB;IACrB,gBAxBsC,EAAA;EA2BxC;IACE,oBA/BiD;IAgCjD,YA9ByC,EAAA","file":"Pagination.css","sourcesContent":[null]} -------------------------------------------------------------------------------- /dist/css/ProgressBar.css: -------------------------------------------------------------------------------- 1 | .re-progress-bar { 2 | background: rgba(0, 0, 0, 0.1); 3 | border-radius: 5px; 4 | height: 10px; 5 | overflow: hidden; } 6 | .re-progress-bar__bar { 7 | background: #337ab7; 8 | height: 100%; 9 | transition: width 350ms ease-out; } 10 | .re-progress-bar--complete .re-progress-bar__bar { 11 | background: #9dda83; 12 | transition: none; } 13 | 14 | /*# sourceMappingURL=ProgressBar.css.map */ -------------------------------------------------------------------------------- /src/stories/ColorPicker.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { storiesOf, action } from '@kadira/storybook'; 3 | import ColorPicker from '../ColorPicker'; 4 | 5 | 6 | storiesOf('ColorPicker', module) 7 | .add('default', () => ( 8 | 9 | )) 10 | .add('with initial color', () => ( 11 | 13 | )); 14 | -------------------------------------------------------------------------------- /dist/css/ButtonGroup.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../../styles/ButtonGroup.scss"],"names":[],"mappings":"AAAA;EAGE,iBAAgB;EAChB,UAAS;EACT,WAAU,EAAA;EAEV;IACE,sBAAqB,EAAA;IAErB;MACE,iBAAgB,EAAA;EAKlB;IACE,6BAhB4B;IAiB5B,gCAjB4B,EAAA;EAsB9B;IACE,4BAvB4B;IAwB5B,+BAxB4B,EAAA;EA4BhC;IACE,eAAc,EAAA;IAEd;MACE,iBAAgB;MAChB,eAAc;MACd,YAAW,EAAA;EAKb;IACE,+BAxC4B;IAyC5B,gCAzC4B,EAAA;EA8C9B;IACE,4BA/C4B;IAgD5B,6BAhD4B,EAAA","file":"ButtonGroup.css","sourcesContent":[null]} -------------------------------------------------------------------------------- /src/stories/YoutubeVideo.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { storiesOf } from '@kadira/storybook'; 3 | import YoutubeVideo from '../YoutubeVideo'; 4 | 5 | 6 | storiesOf('YoutubeVideo', module) 7 | .add('default', () => ( 8 | 9 | )) 10 | .add('no controls', () => ( 11 | 13 | )); 14 | -------------------------------------------------------------------------------- /src/stories/ProgressBar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { storiesOf } from '@kadira/storybook'; 3 | import ProgressBar from '../ProgressBar'; 4 | 5 | 6 | storiesOf('ProgressBar', module) 7 | .add('25%', () => ( 8 | 9 | )) 10 | .add('50%', () => ( 11 | 12 | )) 13 | .add('75%', () => ( 14 | 15 | )) 16 | .add('100%', () => ( 17 | 18 | )) 19 | ; 20 | -------------------------------------------------------------------------------- /src/stories/VimeoVideo.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { storiesOf } from '@kadira/storybook'; 3 | import VimeoVideo from '../VimeoVideo'; 4 | 5 | 6 | storiesOf('VimeoVideo', module) 7 | .add('default', () => ( 8 | 9 | )) 10 | .add('custom colour', () => ( 11 | 13 | )) 14 | .add('autoplay', () => ( 15 | 17 | )); 18 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | exports.Button = require('./dist/Button'); 2 | exports.ButtonGroup = require('./dist/ButtonGroup'); 3 | exports.ColorPicker = require('./dist/ColorPicker'); 4 | exports.LoadingSpinner = require('./dist/LoadingSpinner'); 5 | exports.Pagination = require('./dist/Pagination'); 6 | exports.Panel = require('./dist/Panel'); 7 | exports.ProgressBar = require('./dist/ProgressBar'); 8 | exports.Switch = require('./dist/Switch'); 9 | exports.Tabs = require('./dist/Tabs'); 10 | exports.YoutubeVideo = require('./dist/YoutubeVideo'); 11 | exports.VimeoVideo = require('./dist/VimeoVideo'); 12 | -------------------------------------------------------------------------------- /dist/css/Panel.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../../styles/Panel.scss"],"names":[],"mappings":"AAAA;EAYE,iBAX0B;EAY1B,uBAXiC;EAYjC,mBAV4B;EAW5B,oBAL6B;EAM7B,0BAPmC,EAAA;EASnC;IACE,eAd6B;IAe7B,cAjBqB;IAkBrB,4BAjB0B;IAkB1B,6BAlB0B;IAmB1B,oBAjBkC,EAAA;IAmBlC;MACE,iBAAgB,EAAA;IAGlB;MACE,mBAAkB,EAAA;IAGpB;MACE,kBAAiB,EAAA;EAIrB;IACE,UAAS;IACT,WAAU,EAAA;EAGZ;IACE,cAzCqB,EAAA;IA2CrB;MACE,cAAa,EAAA;IAGf;MACE,iBAAgB,EAAA;EAIpB;IACE,eAhD6B;IAiD7B,cAtDqB;IAuDrB,+BAtD0B;IAuD1B,gCAvD0B;IAwD1B,oBArDkC,EAAA;IAuDlC;MACE,iBAAgB,EAAA;IAGlB;MACE,mBAAkB,EAAA;IAGpB;MACE,kBAAiB,EAAA","file":"Panel.css","sourcesContent":[null]} -------------------------------------------------------------------------------- /dist/css/Tabs.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../../styles/Tabs.scss"],"names":[],"mappings":"AAAA;EAUE,iBAAgB;EAChB,UAAS;EACT,WAAU;EACV,0BALiC,EAAA;EAOjC;IACE,eAAc;IACd,iBAAgB;IAChB,UAAS,EAAA;IAET;MACE,6BAnBsB;MAoBtB,4BApBsB,EAAA;IAuBxB;MACE,gCAxBsB;MAyBtB,+BAzBsB;MA0BtB,8BAA6C,EAAA;EAIjD;IACE,sBAAqB;IACrB,4BAA2C;IAC3C,6BAA4C;IAC5C,2BAA0C;IAC1C,6BAnCwB;IAoCxB,4BApCwB;IAqCxB,gBAAe;IACf,cAjCoB;IAkCpB,mBAnCwB;IAoCxB,0BAAiB;OAAjB,uBAAiB;QAAjB,sBAAiB;YAAjB,kBAAiB;IACjB,iBAxCsB,EAAA;IA0CtB;MACE,eAAc,EAAA;IAGhB;MACE,gBAAe,EAAA;IAGjB;MACE,oBAjD6B,EAAA;EAqDjC;IACE,oBAvDkC,EAAA;IAyDlC;MACE,oBA1DgC,EAAA","file":"Tabs.css","sourcesContent":[null]} -------------------------------------------------------------------------------- /src/stories/Tabs.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { storiesOf, action } from '@kadira/storybook'; 3 | import Tabs from '../Tabs'; 4 | 5 | 6 | storiesOf('Tabs', module) 7 | .add('default', () => ( 8 | 9 | Foo 10 | Bar 11 | Eggs 12 | Spam 13 | 14 | )) 15 | .add('block', () => ( 16 | 18 | Foo 19 | Bar 20 | Eggs 21 | Spam 22 | 23 | )) 24 | ; 25 | -------------------------------------------------------------------------------- /dist/css/ColorPicker.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../../styles/ColorPicker.scss"],"names":[],"mappings":"AAWE;EACE,sBAAqB;EACrB,mBAAkB;EAClB,aAZ8B;EAa9B,cAZmD;EAanD,iBAAgB;EAChB,kBAAiB,EAAA;AAGnB;EACE,gBAAe,EAAA;AAGjB;EACE,mBAAkB;EAClB,OAAM;EACN,QAAO;EACP,aA1B8B;EA2B9B,cA1BmD,EAAA;AA8BrD;EACE,mBAAkB;EAClB,YA/BoC;EAgCpC,aA/BiE;EAgCjE,wBAAuB;EACvB,OAAM;EACN,QAAO;EACP,qBAAoB;EACpB,mBAAkB;EAClB,uBAAsB;EACtB,2BAA0B,EAAA;AAG5B;EACE,mBAAkB;EAClB,sBAAqB;EACrB,YA1C4B;EA2C5B,cA5C8B;EA6C9B,uKAYC,EAAA;AAGH;EACE,gBAAe,EAAA;AAGjB;EACE,YAhE4B;EAiE5B,YAhEmC;EAiEnC,uBAhE+C;EAiE/C,wBAAuB;EACvB,mBAAkB;EAClB,OAAM;EACN,QAAO;EACP,qBAAoB,EAAA","file":"ColorPicker.css","sourcesContent":[null]} -------------------------------------------------------------------------------- /.storybook/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | plugins: [ 5 | // your custom plugins 6 | ], 7 | resolve: { 8 | extensions: ['', '.js', '.jsx'] 9 | }, 10 | module: { 11 | loaders: [ 12 | { 13 | test: /\.(js|jsx)$/, 14 | exclude: /node_modules/, 15 | loader: 'babel-loader' 16 | }, 17 | { 18 | test: /\.scss/, 19 | loader: 'style-loader!css-loader!autoprefixer-loader!sass-loader?outputStyle=expanded' 20 | }, 21 | { 22 | test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, 23 | loader: 'file-loader' 24 | } 25 | ] 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /dist/css/Pagination.css: -------------------------------------------------------------------------------- 1 | .re-pagination { 2 | list-style: none; 3 | margin: 0; 4 | padding: 0; 5 | text-align: center; } 6 | .re-pagination__item { 7 | display: inline-block; 8 | margin: 0 5px 0 0; } 9 | .re-pagination__item:last-child { 10 | margin-right: 0; } 11 | .re-pagination__item-link { 12 | background: #fff; 13 | border: 1px solid #efefef; 14 | color: #999; 15 | display: block; 16 | padding: 4px 8px; 17 | font-family: Arial, serif; 18 | text-decoration: none; 19 | font-size: 14px; } 20 | .re-pagination__item--active .re-pagination__item-link { 21 | background: #337ab7; 22 | color: #fff; } 23 | 24 | /*# sourceMappingURL=Pagination.css.map */ -------------------------------------------------------------------------------- /src/stories/ButtonGroup.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { storiesOf } from '@kadira/storybook'; 3 | import ButtonGroup from '../ButtonGroup'; 4 | import Button from '../Button'; 5 | 6 | 7 | storiesOf('ButtonGroup', module) 8 | .add('default', () => ( 9 | 10 | 11 | 12 | 13 | 14 | 15 | )) 16 | .add('stacked', () => ( 17 | 18 | 19 | 20 | 21 | 22 | 23 | )) 24 | ; 25 | -------------------------------------------------------------------------------- /src/stories/Switch.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { storiesOf, action } from '@kadira/storybook'; 3 | import Switch from '../Switch'; 4 | 5 | 6 | storiesOf('Switch', module) 7 | .add('default', () => ( 8 | getComponent() 9 | )) 10 | .add('on', () => ( 11 | getComponent(null, true) 12 | )) 13 | .add('extra small', () => ( 14 | getComponent('xs') 15 | )) 16 | .add('small', () => ( 17 | getComponent('sm') 18 | )) 19 | .add('large', () => ( 20 | getComponent('lg') 21 | )); 22 | 23 | 24 | function getComponent(size = null, value = false) { 25 | return ( 26 | 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /src/stories/LoadingSpinner.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { storiesOf } from '@kadira/storybook'; 3 | import LoadingSpinner from '../LoadingSpinner'; 4 | 5 | 6 | storiesOf('LoadingSpinner', module) 7 | .add('default', () => ( 8 | 9 | )) 10 | .add('small', () => ( 11 | 12 | )) 13 | .add('mini', () => ( 14 | 15 | )) 16 | .add('slow', () => ( 17 | 18 | )) 19 | .add('fast', () => ( 20 | 21 | )) 22 | .add('custom color', () => ( 23 | 24 | )) 25 | .add('custom background color', () => ( 26 | 27 | )); 28 | -------------------------------------------------------------------------------- /src/ProgressBar.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import classnames from 'classnames'; 3 | 4 | 5 | const ProgressBar = React.createClass({ 6 | 7 | propTypes: { 8 | progress: PropTypes.number.isRequired 9 | }, 10 | 11 | render: function() { 12 | let percentage = this.props.progress * 100; 13 | let innerStyle = { width: `${percentage}%` }; 14 | let className = classnames( 15 | 're-progress-bar', 16 | this.props.className, 17 | { 18 | 're-progress-bar--complete': percentage === 100 19 | } 20 | ); 21 | return ( 22 |
23 |
24 |
25 | ); 26 | } 27 | 28 | }); 29 | 30 | 31 | export default ProgressBar; 32 | -------------------------------------------------------------------------------- /src/ButtonGroup.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import classnames from 'classnames'; 3 | 4 | 5 | const ButtonGroup = React.createClass({ 6 | 7 | propTypes: { 8 | stacked: PropTypes.bool 9 | }, 10 | 11 | render: function() { 12 | let className = classnames( 13 | 're-btn-group', 14 | { 're-btn-group--stacked': this.props.stacked }, 15 | this.props.className 16 | ); 17 | return ( 18 |
    19 | { 20 | this.props.children.map((child, i) => { 21 | return ( 22 |
  • {child}
  • 23 | ); 24 | }) 25 | } 26 |
27 | ); 28 | } 29 | 30 | }); 31 | 32 | 33 | export default ButtonGroup; 34 | -------------------------------------------------------------------------------- /dist/css/LoadingSpinner.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../../styles/LoadingSpinner.scss"],"names":[],"mappings":"AAAA;EAME,6CAAoC;UAApC,qCAAoC;EACpC,+BAAsB;UAAtB,uBAAsB;EACtB,0CAAiC;UAAjC,kCAAiC;EACjC,4CAAmC;UAAnC,oCAAmC;EAEnC,uBAAsB;EAEtB,8CAVoD;EAWpD,2BAV6C;EAW7C,6CAZoD;EAapD,2CAboD;EAcpD,mBAf+D;EAgB/D,oBAAmB;EAEnB,gBAAe;EACf,qBAAoB;EACpB,iCAAwB;UAAxB,yBAAwB;EACxB,iBAAgB,EAAA;EAEhB;IAEE,mBAAkB;IAClB,aA3B4B;IA4B5B,YA5B4B,EAAA;EA+B9B;IAGE,kBAD+D,EAAA;IAG/D;MAEE,aAN4B;MAO5B,YAP4B,EAAA;EAWhC;IAGE,kBAD+D,EAAA;IAG/D;MAEE,aAN4B;MAO5B,YAP4B,EAAA;EAWhC;IACE,+BAAsB;YAAtB,uBAAsB,EAAA;EAGxB;IACE,gCAAuB;YAAvB,wBAAuB,EAAA;;AAI3B;EACE;IACE,gCAAuB;YAAvB,wBAAuB,EAAA;EAGzB;IACE,kCAAyB;YAAzB,0BAAyB,EAAA,EAAA;;AAN7B;EACE;IACE,gCAAuB;YAAvB,wBAAuB,EAAA;EAGzB;IACE,kCAAyB;YAAzB,0BAAyB,EAAA,EAAA","file":"LoadingSpinner.css","sourcesContent":[null]} -------------------------------------------------------------------------------- /styles/ProgressBar.scss: -------------------------------------------------------------------------------- 1 | .re-progress-bar { 2 | $re-progress-bar-track-background: rgba(0, 0, 0, .1) !default; 3 | $re-progress-bar-background: #337ab7 !default; 4 | $re-progress-bar-background-complete: #9dda83 !default; 5 | $re-progress-bar-height: 10px !default; 6 | $re-progress-bar-border-radius: 5px !default; 7 | $re-progress-bar-transition: width 350ms ease-out !default; 8 | 9 | background: $re-progress-bar-track-background; 10 | border-radius: $re-progress-bar-border-radius; 11 | height: $re-progress-bar-height; 12 | overflow: hidden; 13 | 14 | &__bar { 15 | background: $re-progress-bar-background; 16 | height: 100%; 17 | transition: $re-progress-bar-transition; 18 | } 19 | 20 | &--complete &__bar { 21 | background: $re-progress-bar-background-complete; 22 | transition: none; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.storybook/config.js: -------------------------------------------------------------------------------- 1 | import { configure } from '@kadira/storybook'; 2 | import '../styles/ColorPicker.scss'; 3 | import '../styles/Switch.scss'; 4 | import '../styles/LoadingSpinner.scss'; 5 | import '../styles/Button.scss'; 6 | import '../styles/ButtonGroup.scss'; 7 | import '../styles/Pagination.scss'; 8 | import '../styles/Panel.scss'; 9 | import '../styles/ProgressBar.scss'; 10 | import '../styles/Tabs.scss'; 11 | 12 | function loadStories() { 13 | require('../src/stories/Switch'); 14 | require('../src/stories/YoutubeVideo'); 15 | require('../src/stories/VimeoVideo'); 16 | require('../src/stories/ColorPicker'); 17 | require('../src/stories/LoadingSpinner'); 18 | require('../src/stories/Button'); 19 | require('../src/stories/ButtonGroup'); 20 | require('../src/stories/Pagination'); 21 | require('../src/stories/Panel'); 22 | require('../src/stories/ProgressBar'); 23 | require('../src/stories/Tabs'); 24 | } 25 | 26 | configure(loadStories, module); 27 | -------------------------------------------------------------------------------- /styles/mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin button-background($bg: #666, $color: #fff) { 2 | background: $bg; 3 | border-color: darken($bg, 5%); 4 | color: $color; 5 | 6 | &:hover { 7 | background: lighten($bg, 5%); 8 | border-color: $bg; 9 | } 10 | 11 | &:disabled { 12 | color: rgba($color, .55); 13 | 14 | &:hover { 15 | background: $bg; 16 | border-color: darken($bg, 5%); 17 | } 18 | } 19 | } 20 | 21 | @mixin re-switch($modifier, $width, $height, $border-width) { 22 | &--#{$modifier} { 23 | width: $width; 24 | height: $height; 25 | border-radius: $width * .5; 26 | 27 | .re-switch__switch { 28 | width: $height - ($border-width * 2); 29 | height: $height - ($border-width * 2); 30 | } 31 | 32 | .re-switch__checkbox { 33 | width: $width; 34 | height: $height; 35 | } 36 | 37 | &.re-switch--on { 38 | .re-switch__switch { 39 | left: $width - $height; 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["eslint:recommended", "plugin:react/recommended"], 3 | "rules": { 4 | "strict": 0, 5 | "indent": [ 6 | 2, 7 | 2 8 | ], 9 | "quotes": [ 10 | 2, 11 | "single" 12 | ], 13 | "linebreak-style": [ 14 | 2, 15 | "unix" 16 | ], 17 | "semi": [ 18 | 2, 19 | "always" 20 | ], 21 | "react/prop-types": [ 22 | 2, 23 | { 24 | "ignore": ["children", "className"] 25 | } 26 | ] 27 | }, 28 | "env": { 29 | "es6": true, 30 | "browser": true, 31 | "node": true, 32 | "phantomjs": true, 33 | "mocha": true 34 | }, 35 | "parser": "babel-eslint", 36 | "parserOptions": { 37 | "sourceType": "module", 38 | "ecmaVersion": 6, 39 | "ecmaFeatures": { 40 | "jsx": true, 41 | "modules": true, 42 | "arrowFunctions": true, 43 | "experimentalObjectRestSpread": true 44 | } 45 | }, 46 | "plugins": [ 47 | "react" 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /dist/css/ButtonGroup.css: -------------------------------------------------------------------------------- 1 | .re-btn-group { 2 | list-style: none; 3 | margin: 0; 4 | padding: 0; } 5 | .re-btn-group__item { 6 | display: inline-block; } 7 | .re-btn-group__item .re-btn { 8 | border-radius: 0; } 9 | .re-btn-group__item:last-child .re-btn { 10 | border-top-right-radius: 4px; 11 | border-bottom-right-radius: 4px; } 12 | .re-btn-group__item:first-child .re-btn { 13 | border-top-left-radius: 4px; 14 | border-bottom-left-radius: 4px; } 15 | .re-btn-group--stacked .re-btn-group__item { 16 | display: block; } 17 | .re-btn-group--stacked .re-btn-group__item .re-btn { 18 | border-radius: 0; 19 | display: block; 20 | width: 100%; } 21 | .re-btn-group--stacked .re-btn-group__item:last-child .re-btn { 22 | border-bottom-left-radius: 4px; 23 | border-bottom-right-radius: 4px; } 24 | .re-btn-group--stacked .re-btn-group__item:first-child .re-btn { 25 | border-top-left-radius: 4px; 26 | border-top-right-radius: 4px; } 27 | 28 | /*# sourceMappingURL=ButtonGroup.css.map */ -------------------------------------------------------------------------------- /dist/css/Switch.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../../styles/Switch.scss","../../styles/mixins.scss"],"names":[],"mappings":"AAEA;EAqBE,sBAAqB;EACrB,YAhByC;EAiBzC,aAlBuB;EAmBvB,sBAAoC;EACpC,iBAvB0B;EAwB1B,mBAAkB;EAClB,mBAzB0B;EA0B1B,kBA3B4B;EA4B5B,oBAAmB;EACnB,6EAA4E;EAC5E,uBAAsB,EAAA;ECZtB;IACE,YDX6C;ICY7C,aDbwB;ICcxB,oBAA0B,EAAA;IAE1B;MACE,YAAoC;MACpC,aAAqC,EAAA;IAGvC;MACE,YDrB2C;MCsB3C,aDvBsB,EAAA;IC2BtB;MACE,WAAsB,EAAA;EAjB5B;IACE,YDR6C;ICS7C,aDVwB;ICWxB,sBAA0B,EAAA;IAE1B;MACE,YAAoC;MACpC,aAAqC,EAAA;IAGvC;MACE,YDlB2C;MCmB3C,aDpBsB,EAAA;ICwBtB;MACE,WAAsB,EAAA;EAjB5B;IACE,YDL6C;ICM7C,aDPwB;ICQxB,sBAA0B,EAAA;IAE1B;MACE,YAAoC;MACpC,aAAqC,EAAA;IAGvC;MACE,YDf2C;MCgB3C,aDjBsB,EAAA;ICqBtB;MACE,WAAsB,EAAA;EDH5B;IACE,eAAc;IACd,YAAwD;IACxD,aAAyD;IACzD,mBAAkB;IAClB,iBAAgB;IAChB,WAAU;IACV,mBAAkB;IAClB,QAAO;IACP,kCAAiC;IACjC,yCAAuC;IACvC,uBAAsB,EAAA;EAGxB;IACE,UAAS;IACT,WAAU;IACV,mBAAkB;IAClB,WAAU;IACV,YA9CuC;IA+CvC,aAhDqB;IAiDrB,UAA6B;IAC7B,WAA8B;IAC9B,uBAAsB;IACtB,WAAU;IACV,gBAAe,EAAA;EAGjB;IACE,sBA3D0B;IA4D1B,0BA5D0B,EAAA;IA8D1B;MACE,WAA0C,EAAA","file":"Switch.css","sourcesContent":[null,null]} -------------------------------------------------------------------------------- /dist/css/Button.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../../styles/Button.scss","../../styles/mixins.scss"],"names":[],"mappings":"AAEA;EAaE,uBAAsB;EACtB,8BAA6B;EAC7B,mBAZ0B;EAa1B,gBAAe;EACf,sBAAqB;EACrB,gBAAe;EACf,iBAAgB;EAChB,wBAAuB;EACvB,iBAAgB;EAChB,kBApB0B;EAqB1B,mBAAkB;EAClB,mBAAkB;EAClB,+BAA0B;MAA1B,2BAA0B;EAC1B,0BAAiB;KAAjB,uBAAiB;MAAjB,sBAAiB;UAAjB,kBAAiB;EACjB,uBAAsB;EACtB,oBAAmB,EAAA;EAEnB;IACE,cA9ByB,EAAA;EAiC3B;IACE,UAAS;IACT,mBAAkB;IAClB,kBAAiB;IACjB,8BAA6B;IAC7B,SAAQ,EAAA;EAGV;IC3CA,oBDK2B;ICJ3B,sBAA6B;IAC7B,YDI2B,EAAA;ICF3B;MACE,kBAA4B;MAC5B,sBDDyB,EAAA;ICI3B;MACE,8BAAwB,EAAA;MAExB;QACE,oBDRuB;QCSvB,sBAA6B,EAAA;EDiCjC;IC/CA,oBDO2B;ICN3B,sBAA6B;IAC7B,YDM2B,EAAA;ICJ3B;MACE,oBAA4B;MAC5B,sBDCyB,EAAA;ICE3B;MACE,iCAAwB,EAAA;MAExB;QACE,oBDNuB;QCOvB,sBAA6B,EAAA;EDqCjC;ICnDA,oBDS0B;ICR1B,sBAA6B;IAC7B,YDQ0B,EAAA;ICN1B;MACE,oBAA4B;MAC5B,sBDGwB,EAAA;ICA1B;MACE,iCAAwB,EAAA;MAExB;QACE,oBDJsB;QCKtB,sBAA6B,EAAA;EDyCjC;ICvDA,wBDW4B;ICV5B,0BAA6B;IAC7B,YDUwB,EAAA;ICRxB;MACE,gCAA4B;MAC5B,0BDK0B,EAAA;ICF5B;MACE,2BAAwB,EAAA;MAExB;QACE,wBDFwB;QCGxB,0BAA6B,EAAA;ED6CjC;IACE,eAAc;IACd,YAAW,EAAA;EAGb;IACE,mBAAkB,EAAA","file":"Button.css","sourcesContent":[null,null]} -------------------------------------------------------------------------------- /dist/ButtonGroup.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _react = require('react'); 8 | 9 | var _react2 = _interopRequireDefault(_react); 10 | 11 | var _classnames = require('classnames'); 12 | 13 | var _classnames2 = _interopRequireDefault(_classnames); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | var ButtonGroup = _react2.default.createClass({ 18 | displayName: 'ButtonGroup', 19 | 20 | 21 | propTypes: { 22 | stacked: _react.PropTypes.bool 23 | }, 24 | 25 | render: function render() { 26 | var className = (0, _classnames2.default)('re-btn-group', { 're-btn-group--stacked': this.props.stacked }, this.props.className); 27 | return _react2.default.createElement( 28 | 'ul', 29 | { className: className }, 30 | this.props.children.map(function (child, i) { 31 | return _react2.default.createElement( 32 | 'li', 33 | { className: 're-btn-group__item', key: 'item-' + i }, 34 | child 35 | ); 36 | }) 37 | ); 38 | } 39 | 40 | }); 41 | 42 | exports.default = ButtonGroup; 43 | -------------------------------------------------------------------------------- /dist/ProgressBar.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _react = require('react'); 8 | 9 | var _react2 = _interopRequireDefault(_react); 10 | 11 | var _classnames = require('classnames'); 12 | 13 | var _classnames2 = _interopRequireDefault(_classnames); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | var ProgressBar = _react2.default.createClass({ 18 | displayName: 'ProgressBar', 19 | 20 | 21 | propTypes: { 22 | progress: _react.PropTypes.number.isRequired 23 | }, 24 | 25 | render: function render() { 26 | var percentage = this.props.progress * 100; 27 | var innerStyle = { width: percentage + '%' }; 28 | var className = (0, _classnames2.default)('re-progress-bar', this.props.className, { 29 | 're-progress-bar--complete': percentage === 100 30 | }); 31 | return _react2.default.createElement( 32 | 'div', 33 | { className: className }, 34 | _react2.default.createElement('div', { className: 're-progress-bar__bar', style: innerStyle }) 35 | ); 36 | } 37 | 38 | }); 39 | 40 | exports.default = ProgressBar; 41 | -------------------------------------------------------------------------------- /src/stories/Button.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { storiesOf } from '@kadira/storybook'; 3 | import Button from '../Button'; 4 | 5 | 6 | storiesOf('Button', module) 7 | .add('default', () => ( 8 | 9 | )) 10 | .add('disabled', () => ( 11 | 12 | )) 13 | .add('primary', () => ( 14 | 15 | )) 16 | .add('danger', () => ( 17 | 18 | )) 19 | .add('link', () => ( 20 | 21 | )) 22 | .add('block', () => ( 23 | 24 | )) 25 | .add('default - processing', () => ( 26 | 28 | )) 29 | .add('primary - processing', () => ( 30 | 32 | )) 33 | .add('danger - processing', () => ( 34 | 36 | )) 37 | .add('block - processing', () => ( 38 | 41 | )) 42 | ; 43 | -------------------------------------------------------------------------------- /dist/css/Panel.css: -------------------------------------------------------------------------------- 1 | .re-panel { 2 | background: #fff; 3 | border: 1px solid #eee; 4 | border-radius: 4px; 5 | margin-bottom: 20px; 6 | font-family: Arial, serif; } 7 | .re-panel__header { 8 | color: inherit; 9 | padding: 15px; 10 | border-top-left-radius: 4px; 11 | border-top-right-radius: 4px; 12 | background: #e7e7e7; } 13 | .re-panel__header--text-left { 14 | text-align: left; } 15 | .re-panel__header--text-center { 16 | text-align: center; } 17 | .re-panel__header--text-right { 18 | text-align: right; } 19 | .re-panel__header-heading { 20 | margin: 0; 21 | padding: 0; } 22 | .re-panel__content { 23 | padding: 15px; } 24 | .re-panel__content p { 25 | margin-top: 0; } 26 | .re-panel__content p:last-child { 27 | margin-bottom: 0; } 28 | .re-panel__footer { 29 | color: inherit; 30 | padding: 15px; 31 | border-bottom-left-radius: 4px; 32 | border-bottom-right-radius: 4px; 33 | background: #e7e7e7; } 34 | .re-panel__footer--text-left { 35 | text-align: left; } 36 | .re-panel__footer--text-center { 37 | text-align: center; } 38 | .re-panel__footer--text-right { 39 | text-align: right; } 40 | 41 | /*# sourceMappingURL=Panel.css.map */ -------------------------------------------------------------------------------- /src/LoadingSpinner.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import classnames from 'classnames'; 3 | 4 | 5 | const LoadingSpinner = React.createClass({ 6 | 7 | propTypes: { 8 | mini: PropTypes.bool, 9 | small: PropTypes.bool, 10 | slow: PropTypes.bool, 11 | fast: PropTypes.bool, 12 | color: PropTypes.string, 13 | backgroundColor: PropTypes.string 14 | }, 15 | 16 | render: function() { 17 | let className = classnames( 18 | 're-loading-spinner', 19 | { 20 | 're-loading-spinner--mini': this.props.mini, 21 | 're-loading-spinner--small': this.props.small, 22 | 're-loading-spinner--slow': this.props.slow, 23 | 're-loading-spinner--fast': this.props.fast 24 | }, 25 | this.props.className 26 | ); 27 | let style = {}; 28 | if (this.props.color) style.borderLeftColor = this.props.color; 29 | if (this.props.backgroundColor) { 30 | style.borderBottomColor = this.props.backgroundColor; 31 | style.borderRightColor = this.props.backgroundColor; 32 | style.borderTopColor = this.props.backgroundColor; 33 | } 34 | return( 35 |
Loading
36 | ); 37 | } 38 | 39 | }); 40 | 41 | 42 | export default LoadingSpinner; 43 | -------------------------------------------------------------------------------- /styles/ButtonGroup.scss: -------------------------------------------------------------------------------- 1 | .re-btn-group { 2 | $re-btn-group-border-radius: 4px !default; 3 | 4 | list-style: none; 5 | margin: 0; 6 | padding: 0; 7 | 8 | &__item { 9 | display: inline-block; 10 | 11 | .re-btn { 12 | border-radius: 0; 13 | } 14 | } 15 | 16 | &__item:last-child { 17 | .re-btn { 18 | border-top-right-radius: $re-btn-group-border-radius; 19 | border-bottom-right-radius: $re-btn-group-border-radius; 20 | } 21 | } 22 | 23 | &__item:first-child { 24 | .re-btn { 25 | border-top-left-radius: $re-btn-group-border-radius; 26 | border-bottom-left-radius: $re-btn-group-border-radius; 27 | } 28 | } 29 | 30 | &--stacked &__item { 31 | display: block; 32 | 33 | .re-btn { 34 | border-radius: 0; 35 | display: block; 36 | width: 100%; 37 | } 38 | } 39 | 40 | &--stacked &__item:last-child { 41 | .re-btn { 42 | border-bottom-left-radius: $re-btn-group-border-radius; 43 | border-bottom-right-radius: $re-btn-group-border-radius; 44 | } 45 | } 46 | 47 | &--stacked &__item:first-child { 48 | .re-btn { 49 | border-top-left-radius: $re-btn-group-border-radius; 50 | border-top-right-radius: $re-btn-group-border-radius; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /styles/Pagination.scss: -------------------------------------------------------------------------------- 1 | .re-pagination { 2 | $re-pagination-item-margin: 0 5px 0 0 !default; 3 | $re-pagination-item-link-border: 1px solid #efefef !default; 4 | $re-pagination-item-link-padding: 4px 8px !default; 5 | $re-pagination-item-link-background: #fff !default; 6 | $re-pagination-item-link-background-active: #337ab7 !default; 7 | $re-pagination-item-link-color: #999 !default; 8 | $re-pagination-item-link-color-active: #fff !default; 9 | $re-pagination-item-link-font-size: 14px !default; 10 | 11 | list-style: none; 12 | margin: 0; 13 | padding: 0; 14 | text-align: center; 15 | 16 | &__item { 17 | display: inline-block; 18 | margin: $re-pagination-item-margin; 19 | 20 | &:last-child { 21 | margin-right: 0; 22 | } 23 | } 24 | 25 | &__item-link { 26 | background: $re-pagination-item-link-background; 27 | border: $re-pagination-item-link-border; 28 | color: $re-pagination-item-link-color; 29 | display: block; 30 | padding: $re-pagination-item-link-padding; 31 | font-family: Arial, serif; 32 | text-decoration: none; 33 | font-size: $re-pagination-item-link-font-size; 34 | } 35 | 36 | &__item--active &__item-link { 37 | background: $re-pagination-item-link-background-active; 38 | color: $re-pagination-item-link-color-active; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /dist/css/ColorPicker.css: -------------------------------------------------------------------------------- 1 | .re-color-picker__sb-picker { 2 | display: inline-block; 3 | position: relative; 4 | width: 128px; 5 | height: 128px; 6 | overflow: hidden; 7 | margin-right: 3px; } 8 | .re-color-picker__sb-picker--dragging { 9 | cursor: pointer; } 10 | .re-color-picker__sb-picker-layer { 11 | position: absolute; 12 | top: 0; 13 | left: 0; 14 | width: 128px; 15 | height: 128px; } 16 | .re-color-picker__sb-picker-cursor { 17 | position: absolute; 18 | width: 14px; 19 | height: 14px; 20 | background: transparent; 21 | top: 0; 22 | left: 0; 23 | pointer-events: none; 24 | border-radius: 50%; 25 | border: 1px solid #fff; 26 | box-shadow: 0 0 0 1px #000; } 27 | .re-color-picker__h-picker { 28 | position: relative; 29 | display: inline-block; 30 | width: 26px; 31 | height: 128px; 32 | background: linear-gradient(red 0%, #ff9500 10%, #d0ff00 20%, #37ff00 30%, #00ff62 40%, #00fffb 50%, #006aff 60%, #3300ff 70%, #cc00ff 80%, #ff0099 90%, #ff0004 100%); } 33 | .re-color-picker__h-picker--dragging { 34 | cursor: pointer; } 35 | .re-color-picker__h-picker-cursor { 36 | width: 26px; 37 | height: 3px; 38 | border: 1px solid #fff; 39 | background: transparent; 40 | position: absolute; 41 | top: 0; 42 | left: 0; 43 | pointer-events: none; } 44 | 45 | /*# sourceMappingURL=ColorPicker.css.map */ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Elements 2 | 3 | A library of reusable React components consisting of the following: 4 | 5 | ```HTML 6 | 53 | ); 54 | } 55 | 56 | }); 57 | 58 | 59 | export default Button; 60 | -------------------------------------------------------------------------------- /styles/Button.scss: -------------------------------------------------------------------------------- 1 | @import 'mixins'; 2 | 3 | .re-btn { 4 | $re-btn-focus-outline: none !default; 5 | $re-btn-padding: 6px 12px !default; 6 | $re-btn-border-radius: 4px !default; 7 | $re-btn-default-bg: #f7f7f7 !default; 8 | $re-btn-default-color: #444 !default; 9 | $re-btn-primary-bg: #337ab7 !default; 10 | $re-btn-primary-color: #fff !default; 11 | $re-btn-danger-bg: #d9534f !default; 12 | $re-btn-danger-color: #fff !default; 13 | $re-btn-link-bg: transparent !default; 14 | $re-btn-link-color: #000 !default; 15 | 16 | background-image: none; 17 | border: 1px solid transparent; 18 | border-radius: $re-btn-border-radius; 19 | cursor: pointer; 20 | display: inline-block; 21 | font-size: 14px; 22 | font-weight: 400; 23 | line-height: 1.42857143; 24 | margin-bottom: 0; 25 | padding: $re-btn-padding; 26 | position: relative; 27 | text-align: center; 28 | touch-action: manipulation; 29 | user-select: none; 30 | vertical-align: middle; 31 | white-space: nowrap; 32 | 33 | &:focus { 34 | outline: $re-btn-focus-outline; 35 | } 36 | 37 | &__spinner { 38 | left: 50%; 39 | margin-left: -10px; 40 | margin-top: -10px; 41 | position: absolute !important; 42 | top: 50%; 43 | } 44 | 45 | &--default { 46 | @include button-background($re-btn-default-bg, $re-btn-default-color); 47 | } 48 | 49 | &--primary { 50 | @include button-background($re-btn-primary-bg, $re-btn-primary-color); 51 | } 52 | 53 | &--danger { 54 | @include button-background($re-btn-danger-bg, $re-btn-danger-color); 55 | } 56 | 57 | &--link { 58 | @include button-background($re-btn-link-bg, $re-btn-link-color); 59 | } 60 | 61 | &--block { 62 | display: block; 63 | width: 100%; 64 | } 65 | 66 | &--processing &__content { 67 | visibility: hidden; 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /styles/Tabs.scss: -------------------------------------------------------------------------------- 1 | .re-tabs { 2 | $re-tab-border-color: #eee !default; 3 | $re-tab-border-radius: 4px !default; 4 | $re-tab-background: #fff !default; 5 | $re-tab-background-selected: #e7e7e7 !default; 6 | $re-tab-background-hover: #f7f7f7 !default; 7 | $re-tab-padding: .5em 1em !default; 8 | $re-tab-margin: 0 2px !default; 9 | $re-tab-font-family: Arial, serif !default; 10 | 11 | list-style: none; 12 | margin: 0; 13 | padding: 0; 14 | font-family: $re-tab-font-family; 15 | 16 | &--block &__tab { 17 | display: block; 18 | border-radius: 0; 19 | margin: 0; 20 | 21 | &:first-child { 22 | border-top-right-radius: $re-tab-border-radius; 23 | border-top-left-radius: $re-tab-border-radius; 24 | } 25 | 26 | &:last-child { 27 | border-bottom-right-radius: $re-tab-border-radius; 28 | border-bottom-left-radius: $re-tab-border-radius; 29 | border-bottom: 1px solid $re-tab-border-color; 30 | } 31 | } 32 | 33 | &__tab { 34 | display: inline-block; 35 | border-left: 1px solid $re-tab-border-color; 36 | border-right: 1px solid $re-tab-border-color; 37 | border-top: 1px solid $re-tab-border-color; 38 | border-top-right-radius: $re-tab-border-radius; 39 | border-top-left-radius: $re-tab-border-radius; 40 | cursor: pointer; 41 | margin: $re-tab-margin; 42 | padding: $re-tab-padding; 43 | user-select: none; 44 | background: $re-tab-background; 45 | 46 | &:first-child { 47 | margin-left: 0; 48 | } 49 | 50 | &:last-child { 51 | margin-right: 0; 52 | } 53 | 54 | &:hover { 55 | background: $re-tab-background-hover; 56 | } 57 | } 58 | 59 | &__tab--selected { 60 | background: $re-tab-background-selected; 61 | 62 | &:hover { 63 | background: $re-tab-background-selected; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-elements", 3 | "version": "1.3.1", 4 | "description": "A library of reusable React components.", 5 | "main": "index.js", 6 | "homepage": "https://github.com/willdady/react-elements", 7 | "repository": { 8 | "type": "git", 9 | "url": "git@github.com:willdady/react-elements.git" 10 | }, 11 | "scripts": { 12 | "storybook": "start-storybook -p 9001", 13 | "deploy-storybook": "storybook-to-ghpages" 14 | }, 15 | "keywords": [ 16 | "react", 17 | "react-component", 18 | "color picker", 19 | "video", 20 | "input", 21 | "loading spinner", 22 | "pagination", 23 | "panel", 24 | "progress bar", 25 | "switch", 26 | "tabs" 27 | ], 28 | "author": "Will Dady", 29 | "license": "MIT", 30 | "dependencies": { 31 | "classnames": "^2.2.3", 32 | "lodash": "^4.11.1", 33 | "react": "^15.0.1", 34 | "react-dom": "^15.0.1", 35 | "tinycolor2": "^1.0.0" 36 | }, 37 | "peerDependencies": { 38 | "react": ">=0.14.0" 39 | }, 40 | "devDependencies": { 41 | "@kadira/storybook": "^1.27.0", 42 | "@kadira/storybook-deployer": "^1.0.0", 43 | "autoprefixer": "^6.0.3", 44 | "autoprefixer-loader": "^3.2.0", 45 | "babel-cli": "^6.7.5", 46 | "babel-core": "^6.7.6", 47 | "babel-eslint": "^6.0.4", 48 | "babel-loader": "^6.2.4", 49 | "babel-preset-es2015": "^6.6.0", 50 | "babel-preset-react": "^6.5.0", 51 | "css-loader": "^0.23.1", 52 | "eslint": "^2.10.2", 53 | "eslint-plugin-react": "^5.1.1", 54 | "file-loader": "^0.8.5", 55 | "grunt": "^0.4.5", 56 | "grunt-babel": "^6.0.0", 57 | "grunt-contrib-clean": "^1.0.0", 58 | "grunt-contrib-copy": "^1.0.0", 59 | "grunt-contrib-sass": "^0.9.2", 60 | "grunt-postcss": "^0.7.0", 61 | "load-grunt-tasks": "^3.3.0", 62 | "node-sass": "^3.3.3", 63 | "sass-loader": "^3.2.0", 64 | "style-loader": "^0.13.1" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /styles/Panel.scss: -------------------------------------------------------------------------------- 1 | .re-panel { 2 | $re-panel-background: #fff !default; 3 | $re-panel-border: 1px solid #eee !default; 4 | $re-panel-padding: 15px !default; 5 | $re-panel-border-radius: 4px !default; 6 | $re-panel-header-color: inherit !default; 7 | $re-panel-header-background: #e7e7e7 !default; 8 | $re-panel-footer-background: #e7e7e7 !default; 9 | $re-panel-footer-color: inherit !default; 10 | $re-panel-font-family: Arial, serif !default; 11 | $re-panel-margin-bottom: 20px !default; 12 | 13 | background: $re-panel-background; 14 | border: $re-panel-border; 15 | border-radius: $re-panel-border-radius; 16 | margin-bottom: $re-panel-margin-bottom; 17 | font-family: $re-panel-font-family; 18 | 19 | &__header { 20 | color: $re-panel-header-color; 21 | padding: $re-panel-padding; 22 | border-top-left-radius: $re-panel-border-radius; 23 | border-top-right-radius: $re-panel-border-radius; 24 | background: $re-panel-header-background; 25 | 26 | &--text-left { 27 | text-align: left; 28 | } 29 | 30 | &--text-center { 31 | text-align: center; 32 | } 33 | 34 | &--text-right { 35 | text-align: right; 36 | } 37 | } 38 | 39 | &__header-heading { 40 | margin: 0; 41 | padding: 0; 42 | } 43 | 44 | &__content { 45 | padding: $re-panel-padding; 46 | 47 | p { 48 | margin-top: 0; 49 | } 50 | 51 | p:last-child { 52 | margin-bottom: 0; 53 | } 54 | } 55 | 56 | &__footer { 57 | color: $re-panel-footer-color; 58 | padding: $re-panel-padding; 59 | border-bottom-left-radius: $re-panel-border-radius; 60 | border-bottom-right-radius: $re-panel-border-radius; 61 | background: $re-panel-footer-background; 62 | 63 | &--text-left { 64 | text-align: left; 65 | } 66 | 67 | &--text-center { 68 | text-align: center; 69 | } 70 | 71 | &--text-right { 72 | text-align: right; 73 | } 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/Tabs.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import classnames from 'classnames'; 3 | 4 | 5 | const Tab = React.createClass({ 6 | 7 | propTypes: { 8 | tabIndex: PropTypes.number, 9 | selected: PropTypes.bool, 10 | onClick: PropTypes.func.isRequired 11 | }, 12 | 13 | onClick: function () { 14 | this.props.onClick(this.props.tabIndex); 15 | }, 16 | 17 | render: function() { 18 | let className = classnames( 19 | 're-tabs__tab', 20 | { 21 | 're-tabs__tab--selected': this.props.selected 22 | } 23 | ); 24 | return ( 25 |
  • 26 | {this.props.children} 27 |
  • 28 | ); 29 | } 30 | 31 | }); 32 | 33 | 34 | const Tabs = React.createClass({ 35 | 36 | propTypes: { 37 | initialIndex: PropTypes.number, 38 | block: PropTypes.bool, 39 | onChange: PropTypes.func.isRequired, 40 | children: PropTypes.arrayOf(PropTypes.element).isRequired 41 | }, 42 | 43 | getInitialState: function () { 44 | return { 45 | selectedIndex: this.props.initialIndex || 0 46 | }; 47 | }, 48 | 49 | onTabClick: function (selectedIndex) { 50 | this.setState({ selectedIndex }, () => this.props.onChange(selectedIndex)); 51 | }, 52 | 53 | render: function () { 54 | let tabs = this.props.children.map((child, i) => { 55 | return ( 56 | 62 | {child} 63 | 64 | ); 65 | }); 66 | 67 | let className = classnames( 68 | 're-tabs', 69 | { 70 | 're-tabs--block': this.props.block 71 | }, 72 | this.props.className 73 | ); 74 | return ( 75 |
      76 | {tabs} 77 |
    78 | ); 79 | } 80 | 81 | 82 | }); 83 | 84 | 85 | export default Tabs; 86 | -------------------------------------------------------------------------------- /dist/Switch.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _react = require('react'); 8 | 9 | var _react2 = _interopRequireDefault(_react); 10 | 11 | var _classnames = require('classnames'); 12 | 13 | var _classnames2 = _interopRequireDefault(_classnames); 14 | 15 | var _values = require('lodash/values'); 16 | 17 | var _values2 = _interopRequireDefault(_values); 18 | 19 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 20 | 21 | var SIZES = { 22 | EXTRA_SMALL: 'xs', 23 | SMALL: 'sm', 24 | LARGE: 'lg' 25 | }; 26 | 27 | var Switch = _react2.default.createClass({ 28 | displayName: 'Switch', 29 | 30 | 31 | propTypes: { 32 | name: _react.PropTypes.string, 33 | value: _react.PropTypes.bool.isRequired, 34 | size: _react.PropTypes.oneOf((0, _values2.default)(SIZES)), 35 | onClick: _react.PropTypes.func 36 | }, 37 | 38 | onClick: function onClick() { 39 | if (!this.props.onClick) return; 40 | this.props.onClick(this.props.value, this.props.name); 41 | }, 42 | 43 | render: function render() { 44 | var className = (0, _classnames2.default)({ 45 | 're-switch': true, 46 | 're-switch--on': this.props.value, 47 | 're-switch--xs': this.props.size === SIZES.EXTRA_SMALL, 48 | 're-switch--sm': this.props.size === SIZES.SMALL, 49 | 're-switch--lg': this.props.size === SIZES.LARGE 50 | }); 51 | return _react2.default.createElement( 52 | 'span', 53 | { className: className }, 54 | _react2.default.createElement('input', { 55 | type: 'checkbox', 56 | name: this.props.name, 57 | className: 're-switch__checkbox', 58 | checked: this.props.value, 59 | onClick: this.onClick, 60 | readOnly: true 61 | }), 62 | _react2.default.createElement('span', { className: 're-switch__switch' }) 63 | ); 64 | } 65 | }); 66 | 67 | exports.default = Switch; 68 | -------------------------------------------------------------------------------- /styles/LoadingSpinner.scss: -------------------------------------------------------------------------------- 1 | .re-loading-spinner { 2 | $re-loading-spinner-size: 80px !default; 3 | $re-loading-spinner-border-width: $re-loading-spinner-size * .2 !default; 4 | $re-loading-spinner-background-color: rgba(#ccc, .2) !default; 5 | $re-loading-spinner-foreground-color: #337ab7 !default; 6 | 7 | animation-name: re-spinner-animation; 8 | animation-duration: 1s; 9 | animation-timing-function: linear; 10 | animation-iteration-count: infinite; 11 | 12 | box-sizing: border-box; 13 | 14 | border-bottom-color: $re-loading-spinner-background-color; 15 | border-left-color: $re-loading-spinner-foreground-color; 16 | border-right-color: $re-loading-spinner-background-color; 17 | border-top-color: $re-loading-spinner-background-color; 18 | border-width: $re-loading-spinner-border-width; 19 | border-style: solid; 20 | 21 | font-size: 10px; 22 | text-indent: -9999em; 23 | transform: translateZ(0); 24 | overflow: hidden; 25 | 26 | &, 27 | &::after { 28 | border-radius: 50%; 29 | height: $re-loading-spinner-size; 30 | width: $re-loading-spinner-size; 31 | } 32 | 33 | &--small { 34 | $re-loading-spinner-size: 40px; 35 | $re-loading-spinner-border-width: $re-loading-spinner-size * .2; 36 | border-width: $re-loading-spinner-border-width; 37 | 38 | &, 39 | &::after { 40 | height: $re-loading-spinner-size; 41 | width: $re-loading-spinner-size; 42 | } 43 | } 44 | 45 | &--mini { 46 | $re-loading-spinner-size: 20px; 47 | $re-loading-spinner-border-width: $re-loading-spinner-size * .2; 48 | border-width: $re-loading-spinner-border-width; 49 | 50 | &, 51 | &::after { 52 | height: $re-loading-spinner-size; 53 | width: $re-loading-spinner-size; 54 | } 55 | } 56 | 57 | &--slow { 58 | animation-duration: 2s; 59 | } 60 | 61 | &--fast { 62 | animation-duration: .5s; 63 | } 64 | } 65 | 66 | @keyframes re-spinner-animation { 67 | 0% { 68 | transform: rotate(0deg); 69 | } 70 | 71 | 100% { 72 | transform: rotate(360deg); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /dist/css/LoadingSpinner.css: -------------------------------------------------------------------------------- 1 | .re-loading-spinner { 2 | -webkit-animation-name: re-spinner-animation; 3 | animation-name: re-spinner-animation; 4 | -webkit-animation-duration: 1s; 5 | animation-duration: 1s; 6 | -webkit-animation-timing-function: linear; 7 | animation-timing-function: linear; 8 | -webkit-animation-iteration-count: infinite; 9 | animation-iteration-count: infinite; 10 | box-sizing: border-box; 11 | border-bottom-color: rgba(204, 204, 204, 0.2); 12 | border-left-color: #337ab7; 13 | border-right-color: rgba(204, 204, 204, 0.2); 14 | border-top-color: rgba(204, 204, 204, 0.2); 15 | border-width: 16px; 16 | border-style: solid; 17 | font-size: 10px; 18 | text-indent: -9999em; 19 | -webkit-transform: translateZ(0); 20 | transform: translateZ(0); 21 | overflow: hidden; } 22 | .re-loading-spinner, .re-loading-spinner::after { 23 | border-radius: 50%; 24 | height: 80px; 25 | width: 80px; } 26 | .re-loading-spinner--small { 27 | border-width: 8px; } 28 | .re-loading-spinner--small, .re-loading-spinner--small::after { 29 | height: 40px; 30 | width: 40px; } 31 | .re-loading-spinner--mini { 32 | border-width: 4px; } 33 | .re-loading-spinner--mini, .re-loading-spinner--mini::after { 34 | height: 20px; 35 | width: 20px; } 36 | .re-loading-spinner--slow { 37 | -webkit-animation-duration: 2s; 38 | animation-duration: 2s; } 39 | .re-loading-spinner--fast { 40 | -webkit-animation-duration: .5s; 41 | animation-duration: .5s; } 42 | 43 | @-webkit-keyframes re-spinner-animation { 44 | 0% { 45 | -webkit-transform: rotate(0deg); 46 | transform: rotate(0deg); } 47 | 100% { 48 | -webkit-transform: rotate(360deg); 49 | transform: rotate(360deg); } } 50 | 51 | @keyframes re-spinner-animation { 52 | 0% { 53 | -webkit-transform: rotate(0deg); 54 | transform: rotate(0deg); } 55 | 100% { 56 | -webkit-transform: rotate(360deg); 57 | transform: rotate(360deg); } } 58 | 59 | /*# sourceMappingURL=LoadingSpinner.css.map */ -------------------------------------------------------------------------------- /src/VimeoVideo.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import assign from 'lodash/assign'; 3 | 4 | 5 | const DEFAULT_VIMEO_PARAMS = { 6 | autopause: 1, 7 | autoplay: 0, 8 | badge: 1, 9 | byline: 1, 10 | color: '00adef', 11 | loop: 0, 12 | player_id: null, 13 | portrait: 1, 14 | title: 1 15 | }; 16 | 17 | 18 | const VimeoVideo = React.createClass({ 19 | 20 | getDefaultProps: function() { 21 | return assign( 22 | { 23 | width: 500, 24 | height: 281, 25 | frameBorder: 0, 26 | protocol: null 27 | }, 28 | DEFAULT_VIMEO_PARAMS 29 | ); 30 | }, 31 | 32 | propTypes: { 33 | src: PropTypes.string.isRequired, 34 | width: PropTypes.number, 35 | height: PropTypes.number, 36 | frameBorder: PropTypes.number, 37 | protocol: PropTypes.oneOf(['http', 'https']) 38 | }, 39 | 40 | getCleanedSrc: function() { 41 | var matches, vidID, src, protocol; 42 | 43 | src = this.props.src.trim(); 44 | protocol = this.props.protocol ? this.props.protocol + ':' : ''; 45 | 46 | // Extract video id from src. 47 | var pageURLRegexp = /.*vimeo\.com\/(\w+)$/g; 48 | matches = pageURLRegexp.exec(src); 49 | if (matches) { 50 | vidID = matches[1]; 51 | } else { 52 | var embedURLRegexp = /.*video\/(\w+)$/g; 53 | matches = embedURLRegexp.exec(src); 54 | if (matches) { 55 | vidID = matches[1]; 56 | } 57 | } 58 | if (!vidID) throw 'Unable to extract Video ID from URL.'; 59 | // Build URL parameters 60 | var params = ''; 61 | for (var k in DEFAULT_VIMEO_PARAMS) { 62 | if (this.props[k] !== DEFAULT_VIMEO_PARAMS[k]) { 63 | params += '&' + k + '=' + String(this.props[k]); 64 | } 65 | } 66 | params = params.replace('&', '?'); 67 | 68 | return protocol + '//player.vimeo.com/video/' + vidID + params; 69 | }, 70 | 71 | render: function() { 72 | return ( 73 |