├── .babelrc ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── docs ├── .DS_Store ├── README.md ├── components │ ├── About.js │ ├── Base.js │ ├── Code.js │ ├── Column.js │ ├── Configuration.js │ ├── FormComponents.js │ ├── GettingStarted.js │ ├── Home.js │ ├── Philosophy.js │ ├── components │ │ ├── ButtonDocumentation.js │ │ ├── CardDocumentation.js │ │ ├── ChoiceDocumentation.js │ │ ├── ComboBoxDocumentation.js │ │ ├── DatePickerDocumentation.js │ │ ├── OptionDocumentation.js │ │ ├── PlaceholderDocumentation.js │ │ ├── RatingDocumentation.js │ │ ├── SelectDocumentation.js │ │ ├── SeparatorDocumentation.js │ │ ├── SpinnerDocumentation.js │ │ ├── TextInputDocumentation.js │ │ └── ToggleDocumentation.js │ ├── guides │ │ └── IntroducingBelle.js │ └── routes.js ├── css │ ├── normalize.css │ └── style.css ├── icon │ ├── apple-touch-icon-114x114.png │ ├── apple-touch-icon-120x120.png │ ├── apple-touch-icon-144x144.png │ ├── apple-touch-icon-152x152.png │ ├── apple-touch-icon-57x57.png │ ├── apple-touch-icon-60x60.png │ ├── apple-touch-icon-72x72.png │ ├── apple-touch-icon-76x76.png │ ├── favicon-128.png │ ├── favicon-16x16.png │ ├── favicon-196x196.png │ ├── favicon-32x32.png │ ├── favicon-96x96.png │ ├── favicon.ico │ ├── mstile-144x144.png │ ├── mstile-150x150.png │ ├── mstile-310x150.png │ ├── mstile-310x310.png │ └── mstile-70x70.png ├── images │ ├── abyssinian.jpg │ ├── albatross.jpg │ ├── angelfish.jpg │ ├── ant.jpg │ ├── antelope.jpg │ ├── asian_elephant.jpg │ ├── belle_logo.png │ ├── croatia_100.jpg │ ├── croatia_original.jpg │ ├── ngorongoro_caldera_small.jpg │ ├── overview.png │ ├── santorini_100.jpg │ ├── santorini_original.jpg │ ├── vjeux.jpeg │ ├── yosemite_100.jpg │ └── yosemite_original.jpg ├── index.html ├── index.js ├── package.json ├── server.js ├── style.js ├── theme │ ├── ThemeSwitch.js │ ├── belle-with-classic-focus.js │ ├── bootstrap-3.js │ └── initialize.js ├── webpack.config.js └── webpack.config.production.js ├── examples ├── README.md ├── components │ ├── ButtonPlayground.js │ ├── CardPlayground.js │ ├── ComboBoxPlayground.js │ ├── DatePickerPlayground.js │ ├── RatingPlayground.js │ ├── SelectPlayground.js │ ├── SpinnerPlayground.js │ ├── TextInputPlayground.js │ └── TogglePlayground.js ├── css │ ├── normalize.css │ └── style.css ├── index.html ├── index.js ├── package.json ├── server.js └── webpack.config.js ├── package.json ├── scripts └── publish_gh_pages.sh └── src ├── __tests__ ├── Button-test.js ├── Card-test.js ├── ComboBox-test.js ├── DatePicker-test.js ├── Option-test.js ├── Placeholder-test.js ├── Rating-test.js ├── Select-test.js ├── Separator-test.js ├── Spinner-test.js ├── TextInput-test.js ├── date-helpers-test.js ├── helpers-test.js └── union-class-names-test.js ├── components ├── ActionArea.js ├── Button.js ├── Card.js ├── Choice.js ├── ComboBox.js ├── ComboBoxItem.js ├── DatePicker.js ├── Day.js ├── DisabledDay.js ├── Option.js ├── Placeholder.js ├── Rating.js ├── Select.js ├── SelectItem.js ├── Separator.js ├── Spinner.js ├── TextInput.js └── Toggle.js ├── config ├── button.js ├── datePicker.js ├── i18n.js ├── rating.js ├── select.js └── toggle.js ├── index.js ├── style ├── actionArea.js ├── animations.js ├── button.js ├── card.js ├── combo-box.js ├── date-picker.js ├── option.js ├── placeholder.js ├── rating.js ├── select.js ├── separator.js ├── spinner.js ├── text-input.js └── toggle.js └── utils ├── animation-frame-management.js ├── calculate-textarea-height.js ├── date-helpers.js ├── helpers.js ├── inject-style.js ├── is-component-of-type.js └── union-class-names.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react", "es2015", "stage-0"], 3 | "env": { 4 | "development": { 5 | "presets": ["react-hmre"] 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/node_modules/** 2 | lib/** 3 | scripts/** 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": "airbnb", 4 | "rules": { 5 | "react/prefer-stateless-function": 0, 6 | "max-len": 0, 7 | "comma-dangle": 0, 8 | "react/jsx-no-bind": 0, // TODO remove this 9 | "react/prefer-es6-class": 0, // TODO remove this 10 | "react/sort-comp": [2, { // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-comp.md 11 | "order": [ 12 | "constructor", 13 | "displayName", 14 | "propTypes", 15 | "contextTypes", 16 | "childContextTypes", 17 | "mixins", 18 | "statics", 19 | "defaultProps", 20 | "getDefaultProps", 21 | "state", 22 | "getInitialState", 23 | "getChildContext", 24 | "componentWillMount", 25 | "componentDidMount", 26 | "componentWillReceiveProps", 27 | "shouldComponentUpdate", 28 | "componentWillUpdate", 29 | "componentDidUpdate", 30 | "componentWillUnmount", 31 | "/^_on.+$/", 32 | "/^_get.+$/", 33 | "/^_trigger.+$/", 34 | "/^_.+$/", 35 | "/^_render.+$/", 36 | "render" 37 | ] 38 | }] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependency directory 2 | # Commenting this out is preferred by some people, see 3 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 4 | node_modules 5 | 6 | # Browserify cache & build files 7 | bundle.js 8 | .bundle.js 9 | 10 | # Belle build with babel 11 | /lib/ 12 | 13 | # Belle docs after npm install 14 | /docs/css/googlecode.css 15 | 16 | # NPM debug 17 | npm-debug.log 18 | npm-debug.log* 19 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Dependency directory 2 | # Commenting this out is preferred by some people, see 3 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 4 | node_modules 5 | 6 | # Browserify cache & build files 7 | bundle.js 8 | .bundle.js 9 | 10 | # Belle sources 11 | /src/ 12 | /examples/ 13 | 14 | # NPM debug 15 | npm-debug.log 16 | 17 | tests 18 | docs 19 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "5" 4 | sudo: false 5 | script: 6 | - npm test 7 | - npm run lint 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Nikolaus Graf 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Belle 2 | 3 | Configurable React Components with great UX. 4 | 5 | Website & Documentation: [http://nikgraf.github.io/belle/](http://nikgraf.github.io/belle/) 6 | 7 | [](http://nikgraf.github.io/belle/) 8 | 9 | [![Build Status](https://travis-ci.org/nikgraf/belle.svg)](https://travis-ci.org/nikgraf/belle) 10 | [![Dependency Status](https://david-dm.org/nikgraf/belle.svg)](https://david-dm.org/nikgraf/belle) 11 | [![peerDependency Status](https://david-dm.org/nikgraf/belle/peer-status.svg)](https://david-dm.org/nikgraf/belle#info=peerDependencies) 12 | 13 | ## Getting Started 14 | 15 | Belle is available as [npm](http://npmjs.org) package. Once you have npm you can install Belle in your project folder with: 16 | 17 | ``` 18 | npm install belle 19 | ``` 20 | 21 | ### Import & use Belle Components 22 | 23 | We recommend you to get started with [React](https://facebook.github.io/react/) first. Once you have a simple application setup you can import any Belle component and use it right away. No stylesheets, font or any other prerequisite needed. 24 | 25 | ```html 26 | 27 | 28 | 29 | 30 | 31 | 32 |
33 | 37 | 38 | 39 | 40 | ``` 41 | 42 | ```javascript 43 | var React = require('react'); 44 | var belle = require('belle'); 45 | var TextInput = belle.TextInput; 46 | 47 | var App = React.createClass({ 48 | 49 | render: function() { 50 | return ( 51 |
52 | 53 |
54 | ); 55 | } 56 | }); 57 | 58 | React.render(, document.getElementById('react-root')); 59 | ``` 60 | 61 | ### Learn more 62 | 63 | In addition you can dig through the [documentation](http://nikgraf.github.io/belle/) to learn about how to modify Belle components. 64 | 65 | ## Browser Support 66 | 67 | - Chrome (mobile and desktop) 68 | - Safari (mobile and desktop) 69 | - Firefox 70 | - Internet Explorer 9, 10, 11 71 | 72 | ## Philosophy 73 | 74 | "Great UX starts with a good UI" 75 | 76 | With Belle I'm aiming to provide a library that follows a couple well established 77 | principles. While some of them might not be consider best practice today 78 | We believe they will become some day in the near future. 79 | 80 | ### Easy to use 81 | 82 | The most important attribute of any great experience is that there was no hassle to achieve 83 | the initial goals. 84 | 85 | ### Consistent Behavior 86 | 87 | Every object someone interacts with has it's own little language. This language 88 | must be learned by everyone getting in touch with a new set of object. In order 89 | to provide a great experience the amount to learn should be reduced to a minimum. 90 | 91 | There are two major personalities to target with Belle. One is the developer. 92 | For him/her APIs should be provided in a consistent way through all components. 93 | The other and more important is the users of the components. Every color, 94 | animation or behavior should be aligned with the other components to provide 95 | a great experience. 96 | 97 | ### Encapsulate Styles 98 | 99 | There is no reason while a style designed one specific element should affect 100 | others. In CSS styles are often defined by overwriting previous ones and introducing 101 | deeper and deeper nesting. Once nesting is introduced resolution of styles for one 102 | specific element is not a trivial task anymore. Due this managing CSS dependencies 103 | is hard. It is hard to predict how an application looks like after updating or 104 | removing dependency. 105 | 106 | That's why with Belle styles should apply to the components themselves in the DOM. 107 | By doing so the visual appearance and business logic are combined in location. 108 | 109 | ### Every Interaction is followed up with Feedback 110 | 111 | Let people know how their behavior affects the system. It assures them that 112 | their input was acknowledged which provides them with a feeling of control over 113 | the system. 114 | 115 | ### High Performance 116 | 117 | The user should see affects of their actions instantly. Any delay can cause confusion 118 | and frustration. While instant certainly is not always possible Belle strives to 119 | provide an experience close to instant. 120 | 121 | ## Development 122 | 123 | You can install the development environment with 124 | 125 | ``` 126 | npm install 127 | ``` 128 | 129 | `npm run build` will trigger a build into the `lib` folder. To develop a component it's convenient to use the examples or docs application. 130 | 131 | ### Run the examples or docs application 132 | 133 | To run the examples or docs you go into the folder `docs` or `examples` and run `npm install` and `npm start`. The app will run with hot reloading on `http://localhost:3000`. 134 | 135 | ### Tests 136 | 137 | In order to run the tests use 138 | 139 | ``` 140 | npm test 141 | ``` 142 | 143 | To run the test continuously you can use `npm run test:watch`. 144 | 145 | ## Discussion or need help? 146 | 147 | In addition you can ask the community by [posting your question to StackOverflow with the **belle** tag.](http://stackoverflow.com/questions/ask?tags=belle). 148 | 149 | ## Future Plans 150 | 151 | - Components to add: Dateformatter, Datepicker, Tooltip, Popover, Modal, Navigation Menu, NumberInput, EmailInput, Anchor, DropZone 152 | 153 | ## Special Thanks 154 | 155 | Thanks to [Andrey Popp](https://github.com/andreypopp) & [Eugene](https://github.com/eugene1g) for their inspiring work on [React TextArea Autosize](https://github.com/andreypopp/react-textarea-autosize) which kind of ignited the idea of Belle. 156 | 157 | Thanks to Christian Steiner from [http://www.cropd.at/](http://cropd.at) for creating the logo and helping out with the design. 158 | 159 | Special thanks to [Jyoti Puri](https://github.com/jpuri) for the tremendous amount of work she put into this endeavor. 160 | 161 | ## License 162 | 163 | MIT 164 | -------------------------------------------------------------------------------- /docs/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/.DS_Store -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | Belle Documentation 2 | ================ 3 | 4 | ## Install 5 | 6 | ``` 7 | npm install 8 | ``` 9 | 10 | Make sure you ran `npm install` in the root folder of Belle. 11 | 12 | ## Run 13 | 14 | ``` 15 | npm start 16 | ``` 17 | 18 | The app will run with hot reloading on `http://localhost:3000`. 19 | -------------------------------------------------------------------------------- /docs/components/About.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | export default class FuturePlans extends Component { 4 | 5 | render() { 6 | return (
7 |

Discussion or need help?

8 | 9 |

10 | Join us at the #belle channel of the Reactiflux Slack community or our Gitter room. 11 |

12 | 13 |

14 | In addition you can ask the community by posting your question to StackOverflow with the belle tag. 15 |

16 | 17 |

Special Thanks

18 | 19 |

20 | Thanks to Andrey Popp & Eugene for their inspiring work on 21 | React TextArea Autosize which 22 | kind of ignited the idea of Belle. 23 |

24 |

25 | Thanks to Christian Steiner from cropd.at for creating 26 | the logo and helping out with the design. 27 |

28 | 29 |

30 | Special thanks to Jyoti Puri for the tremendous amount of work she put into this endeavor. 31 |

32 | 33 |

Future Plans

34 | 35 |

Components to add: Dateformatter, Datepicker, Tooltip, Popover, Modal, Navigation Menu, NumberInput, EmailInput, Anchor, DropZone 36 |

37 |
); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /docs/components/Code.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import ReactDOM from 'react-dom'; 4 | import highlightJs from 'highlight.js'; 5 | import { isEqual, omit, extend } from 'underscore'; 6 | 7 | const defaultStyle = { 8 | fontFamily: 'Consolas, "Liberation Mono", Menlo, Courier, monospace', 9 | background: '#F5F5F5', 10 | whiteSpace: 'pre-wrap', 11 | padding: 10, 12 | }; 13 | 14 | export default class Code extends Component { 15 | 16 | constructor(properties) { 17 | super(properties); 18 | this.childProperties = omit(properties, 'style'); 19 | } 20 | 21 | componentDidMount() { 22 | highlightJs.highlightBlock(ReactDOM.findDOMNode(this)); 23 | } 24 | 25 | componentWillReceiveProps(properties) { 26 | this.childProperties = omit(properties, 'style'); 27 | } 28 | 29 | shouldComponentUpdate(nextProps) { 30 | if (nextProps.value === this.props.value && isEqual(nextProps.style, this.props.style)) { 31 | return false; 32 | } 33 | 34 | return true; 35 | } 36 | 37 | componentDidUpdate() { 38 | highlightJs.highlightBlock(ReactDOM.findDOMNode(this)); 39 | } 40 | 41 | render() { 42 | const style = extend({}, defaultStyle, this.props.style); 43 | 44 | return (
45 |         
46 |           { this.props.value }
47 |         
48 |       
); 49 | } 50 | } 51 | 52 | Code.propTypes = { 53 | value: PropTypes.string.isRequired, 54 | style: PropTypes.object, 55 | }; 56 | -------------------------------------------------------------------------------- /docs/components/Column.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { omit } from 'underscore'; 4 | 5 | export default React.createClass({ 6 | 7 | propTypes: { 8 | smallScreenStyle: PropTypes.object.isRequired, 9 | mediumScreenStyle: PropTypes.object.isRequired, 10 | children: PropTypes.any, 11 | }, 12 | 13 | contextTypes: { 14 | viewport: PropTypes.any, 15 | }, 16 | 17 | getInitialState() { 18 | this.childProperties = omit(this.props, [ 19 | 'style', 20 | 'smallScreenStyle', 21 | 'mediumScreenStyle', 22 | ]); 23 | return {}; 24 | }, 25 | 26 | componentWillReceiveProps(properties) { 27 | this.childProperties = omit(properties, [ 28 | 'style', 29 | 'smallScreenStyle', 30 | 'mediumScreenStyle', 31 | ]); 32 | }, 33 | 34 | render() { 35 | const style = (this.context.viewport.width <= 480) ? this.props.smallScreenStyle : this.props.mediumScreenStyle; 36 | 37 | return ( 38 |
39 | { this.props.children } 40 |
41 | ); 42 | }, 43 | }); 44 | -------------------------------------------------------------------------------- /docs/components/FormComponents.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import Code from './Code'; 3 | 4 | const controlledComponentCodeOne = ` 5 | render: function() { 6 | return ; 7 | }`; 8 | 9 | const controlledComponentCodeTwo = ` 10 | getInitialState: function() { 11 | return {value: 'Hello!'}; 12 | }, 13 | handleChange: function(obj) { 14 | this.setState({value: obj.value}); 15 | }, 16 | render: function() { 17 | var value = this.state.value; 18 | return ; 19 | }`; 20 | 21 | const uncontrolledComponentCode = ` 22 | render: function() { 23 | return ; 24 | }`; 25 | 26 | const reactLinkCode = `var WithLink = React.createClass({ 27 | mixins: [LinkedStateMixin], 28 | getInitialState: function() { 29 | return {message: 'Hello!'}; 30 | }, 31 | render: function() { 32 | return ; 33 | } 34 | });`; 35 | 36 | export default class FormComponents extends Component { 37 | 38 | render() { 39 | return (
40 |

Form Components

41 | 42 |

43 | Belle has many Form Components: ComboBox, Select, Rating, TextInput and Toggle. 44 | They differ from other components because they can be mutated via user interactions. 45 |

46 | 47 |

onUpdate Prop

48 | 49 |

50 | Form components allow listening for changes by setting a callback to the onUpdate property. 51 | The callback receives an object as parameter containing a field 'value' which is the value entered by the user. 52 |

53 | 54 |

Controlled Components

55 | 56 |

57 | An Form Component with value set is a controlled component. In a controlled component, 58 | the value of the rendered element will always reflect the value prop. For example: 59 |

60 | 61 | 62 | 63 |

64 | This will render a TextInput that always has a value of Hello!. Any user input will have no effect on the rendered element 65 | because React has declared the value to be Hello!. If you wanted to update the value in response to user input, you 66 | could use the onUpdate event: 67 |

68 | 69 | 70 | 71 |

This pattern makes it easy to implement interfaces that respond to or validate user interactions.

72 | 73 |

Uncontrolled Components

74 | 75 |

A component that does not supply a value is an uncontrolled component. 76 | In an uncontrolled component, the value of the rendered element will reflect the user's input. For example: 77 |

78 | 79 | 80 | 81 |

82 | This will render an input that starts off with an empty value. Any user input will be immediately reflected by the rendered element. 83 | If you wanted to listen to updates to the value, you could use the onUpdate event just like you can with controlled components. 84 | If you want to initialize the component with a non-empty value, you can supply a defaultValue prop. 85 |

86 | 87 |

Two-Way Binding Helpers

88 | 89 |

Two-way binding is implicitly enforcing that some value in the DOM is always consistent with some React state. 90 | Like React form components Belle form components also provide ReactLink: its syntactic sugar for setting up the common 91 | data flow loop pattern, or "linking" some data source to React state. 92 |

93 | 94 | 95 | 96 |

Note:
97 | ReactLink is just a thin wrapper and convention around the onUpdate/setState() pattern. It doesn't fundamentally change how data 98 | flows in your React application.

99 | 100 |

References

101 |

102 | React Forms 103 |

104 |

105 | Two-Way Binding Helpers 106 |

107 | 108 |
); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /docs/components/GettingStarted.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import Code from './Code'; 3 | 4 | const installCommand = 'npm install belle'; 5 | 6 | const usageExampleHtml = ` 7 | 8 | 9 | 10 | 11 | 12 |
13 | 17 | 18 | 19 | 20 | `; 21 | 22 | const usageExampleJavaScript = `var React = require('react'); 23 | var belle = require('belle'); 24 | var TextInput = belle.TextInput; 25 | 26 | var App = React.createClass({ 27 | 28 | render: function() { 29 | return ( 30 |
31 | 32 |
33 | ); 34 | } 35 | }); 36 | 37 | React.render(, document.getElementById('react-root'));`; 38 | 39 | export default class GettingStarted extends Component { 40 | 41 | render() { 42 | return (
43 |

Getting Started

44 | 45 |

46 | Belle is available as npm package. Once you have npm you can install Belle in your project folder with: 47 |

48 | 49 | 50 | 51 |

Import & use Belle Components

52 | 53 |

54 | We recommend you to get started with React first. Once you have a simple application setup you can import any Belle component and use it right away. No stylesheets, font or any other prerequisite needed. 55 |

56 | 57 | 58 | 59 | 60 | 61 |

Discussion or need help?

62 | 63 |

64 | Join us at the #belle channel of the Reactiflux Slack community or our Gitter room. 65 |

66 | 67 |
); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /docs/components/Home.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import ThemeSwitch from '../theme/ThemeSwitch'; 3 | import GettingStarted from './GettingStarted'; 4 | import { Card } from 'belle'; 5 | 6 | export default class Home extends Component { 7 | 8 | render() { 9 | return ( 10 |
11 |

12 | Belle provides you with a set of React components like Toggle, ComboBox, Rating, TextInput, Button, Card, Select and soon many more. 13 |

14 | 15 |

16 | All of the components are optimized to work both on mobile & desktop devices. The styles are highly customizable on two levels. You can configure the base styles of all the components as well as modify each one of them individually. 17 |

18 | 19 |

Overview

20 | 21 | 22 | 26 | 27 | 28 |
29 |

33 | 34 | This is so good. I like the effort you put into tweaking the UX. 35 | 42 |

43 |
44 | 50 |
Christopher Chedeau (Vjeux)
53 |
React Core Team
56 |
57 |
58 |
59 | 60 |

Browser Support

61 |
    62 |
  • Chrome (mobile and desktop)
  • 63 |
  • Safari (mobile and desktop)
  • 64 |
  • Firefox
  • 65 |
  • Internet Explorer 9, 10, 11
  • 66 |
67 | 68 |

Theme Support

69 | 70 | As mentioned above the styles are highly configurable and for demonstration purposes you can view this website with the Boostrap3 theme. 71 | 72 | 73 | 74 |

75 | 76 | 77 | 78 |
79 | ); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /docs/components/Philosophy.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | export default class Philosophy extends Component { 4 | 5 | render() { 6 | return (
7 |

Philosophy

8 | 9 |

“Great UX starts with a good UI”

10 | 11 |

12 | With Belle I'm aiming to provide a library that follows a couple well established 13 | principles. While some of them might not be consider best practice today 14 | We believe they will become some day in the near future. 15 |

16 | 17 |

This is an early draft & any improvement you can think of is very welcome.

18 | 19 |

Principles

20 | 21 |

Easy to use

22 | 23 |

24 | The most important attribute of any great experience is that there was no hassle to achieve 25 | the initial goals. 26 |

27 | 28 |

Consistent Behavior

29 | 30 |

31 | Every object someone interacts with has it's own little language. This language 32 | must be learned by everyone getting in touch with a new set of object. In order 33 | to provide a great experience the amount to learn should be reduced to a minimum. 34 |

35 | 36 |

37 | There are two major personalities to target with Belle. One is the developer. 38 | For him/her APIs should be provided in a consistent way through all components. 39 | The other and more important is the users of the components. Every color, 40 | animation or behavior should be aligned with the other components to provide 41 | a great experience. 42 |

43 | 44 |

Encapsulate Styles

45 | 46 |

47 | There is no reason while a style designed one specific element should affect 48 | others. In CSS styles are often defined by overwriting previous ones and introducing 49 | deeper and deeper nesting. Once nesting is introduced resolution of styles for one 50 | specific element is not a trivial task anymore. Due this managing CSS dependencies 51 | is hard. It is hard to predict how an application looks like after updating or 52 | removing dependency. 53 |

54 | 55 |

56 | That's why with Belle styles should apply to the components themselves in the DOM. 57 | By doing so the visual appearance and business logic are combined in location. 58 |

59 | 60 |

Every Interaction is followed up with Feedback

61 | 62 |

63 | Let people know how their behavior affects the system. It assures them that 64 | their input was acknowledged which provides them with a feeling of control over 65 | the system. 66 |

67 | 68 |

High Performance

69 | 70 |

71 | The user should see affects of his actions instantly. Any delay can cause confusion 72 | and frustration. While instant certainly is not always possible Belle strives to 73 | provide an experience close to instant. 74 |

75 | 76 |
); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /docs/components/components/CardDocumentation.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Card } from 'belle'; 3 | import Code from '../Code'; 4 | 5 | const basicCodeExample = ` 6 | 7 | Add any content here like paragraphs, images or other components … 8 | `; 9 | 10 | const imageCodeExample = ` 11 | 14 | 16 | `; 17 | 18 | export default class CardDocumentation extends Component { 19 | 20 | render() { 21 | return ( 22 |
23 |

Card

24 | 25 | 26 | Add any content here like paragraphs, images or other components … 27 | 28 | 29 | 30 | 31 |

32 | Note: The card is designed to work on non-white areas. To provide a 33 | nice appearance on white areas please change the box-shadow or borders. 34 |

35 | 36 |

Properties

37 | 38 |

39 | Any property valid for a HTML div like 40 | style, id, className, … 41 |

42 | 43 |

More Examples

44 | 45 |

Card with a full-width image

46 | 47 | 52 | 56 | 57 | 58 | 59 |
60 | ); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /docs/components/components/ChoiceDocumentation.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Choice, Toggle } from 'belle'; 3 | import Code from '../Code'; 4 | import { propertyNameStyle, propertyDescriptionStyle } from '../../style'; 5 | 6 | const choiceCodeExample = ` 7 | 8 | On 9 | Off 10 | `; 11 | 12 | export default class ChoiceDocumentation extends Component { 13 | 14 | render() { 15 | return (
16 | 17 |

Choice

18 | 19 | 20 | On 21 | Off 22 | 23 | 24 | 25 | 26 |

Properties

27 | 28 | 29 | 30 | 31 | 34 | 35 | 36 | 45 | 46 | 47 |
32 | value 33 |
37 |

38 | Boolean 39 |
40 | required

41 |

42 | The value to be set in case this Choice is set. 43 |

44 |
48 | 49 |

50 | Any property valid for a HTML div like 51 | style, id, className, … 52 |

53 | 54 |
); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /docs/components/components/OptionDocumentation.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Option, Select } from 'belle'; 3 | import Code from '../Code'; 4 | import { propertyNameStyle, propertyDescriptionStyle } from '../../style'; 5 | 6 | const basicCodeExample = ` 7 | `; 12 | 13 | export default class OptionDocumentation extends Component { 14 | 15 | render() { 16 | return (
17 | 18 |

Option

19 | 20 | 25 | 26 | 27 | 28 |

Properties

29 | 30 | 31 | 32 | 33 | 36 | 37 | 38 | 49 | 50 | 51 | 52 | 55 | 56 | 57 | 69 | 70 | 71 |
34 | value 35 |
39 |

40 | String, Boolean, Number 41 |
42 | required

43 |

44 | The value to be set in case this Option is selected. The value must be 45 | unique for all Options within one Select. It can be of type Boolean, String or 46 | Number. 47 |

48 |
53 | hoverStyle 54 |
58 |

59 | Object 60 |
61 | optional 62 |

63 |

64 | Works like React's built-in style property. 65 | Becomes active once the user hovers over the Option with the cursor or focus 66 | on it by leveragin the key board inputs like Arrow-down or Arrow-up. 67 |

68 |
72 | 73 |

74 | Any property valid for a HTML div like 75 | style, id, className, … 76 |

77 | 78 |
); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /docs/components/components/PlaceholderDocumentation.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Option, Placeholder, Select } from 'belle'; 3 | import Code from '../Code'; 4 | 5 | const basicCodeExample = ` 6 | `; 11 | 12 | export default class PlaceholderDocumentation extends Component { 13 | 14 | render() { 15 | return (
16 | 17 |

Placeholder

18 | 19 | 24 | 25 | 26 | 27 |

Properties

28 | 29 |

30 | Any property valid for a HTML div like 31 | style, id, className, … 32 |

33 | 34 |
); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /docs/components/components/SeparatorDocumentation.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Option, Select, Separator } from 'belle'; 3 | import Code from '../Code'; 4 | 5 | const basicCodeExample = ` 6 | `; 19 | 20 | export default class SeparatorDocumentation extends Component { 21 | 22 | render() { 23 | return (
24 | 25 |

Separator

26 | 27 | 40 | 41 | 42 | 43 |

Properties

44 | 45 |

46 | Any property valid for a HTML div like 47 | style, id, className, … 48 |

49 | 50 |
); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /docs/components/components/SpinnerDocumentation.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button, Card, Spinner } from 'belle'; 3 | import Code from '../Code'; 4 | import { propertyNameStyle, propertyDescriptionStyle } from '../../style'; 5 | 6 | const basicCodeExample = ` 7 | `; 8 | 9 | const buttonCodeExample = ` 10 | 13 | 14 | `; 17 | 18 | const cardCodeExample = ` 19 | 24 | Loading 25 | `; 26 | 27 | const SpinnerDocumentation = () => ( 28 |
29 |

Spinner

30 | 31 | 32 | 33 | 34 | 35 |

Properties

36 | 37 | 38 | 39 | 42 | 43 | 44 | 55 | 56 |
40 | characterStyle 41 |
45 |

46 | Object 47 |
48 | optional 49 |

50 |

51 | The property can be used to specify styling for the spans wrapping 52 | the dots. Behaves like Reacts built-in style property. 53 |

54 |
57 | 58 |

59 | Any property valid for a HTML div like 60 | style, id, className, … 61 |

62 | 63 |

More Examples

64 | 65 |

Button while loading

66 | 67 | 70 | 71 | 74 | 75 | 76 | 77 |

Card with a loading indicator

78 | 79 | 85 | Loading 86 | 87 | 88 | 89 |
90 | ); 91 | 92 | export default SpinnerDocumentation; 93 | -------------------------------------------------------------------------------- /docs/components/guides/IntroducingBelle.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Card, Toggle } from 'belle'; 3 | import Code from '../Code'; 4 | 5 | const basicToggleExample = ` 6 | `; 7 | 8 | const selectExample = ` 9 | `; 20 | 21 | export default class Why extends Component { 22 | 23 | render() { 24 | return (
25 |

Nik Graf, 15th July 2015

26 | 27 |

Introducing Belle

28 | 29 | 30 | 34 | 35 | 36 |

37 | Belle is a set of React components including Toggle, ComboBox, Rating, TextInput, Button, Card & Select. Many more like DatePicker, NumberInput, DropZone & Menu will come soon. As of today we hit version 1.0.0 :) 38 |

39 | 40 |

Wait, but why yet another component library?

41 | 42 |

43 | The web platform is a fantastic environment. Still it has certain limitations that are holding you back as a developer. React opened up new opportunities and I finally had tools in my hand to make the kind of UI components I always wanted to. 44 |

45 |

Don't get me wrong. There are a ton of really great UI libraries out there like jQuery UI, Bootstrap, Polymer, you name it. They are super useful and to me often a source for inspiration. Through them I learned a lot about the details to take care of when developing user interface elements. Nevertheless always some feature was missing or the UX not as good as we imagined it. That’s why Jyoti & I started to research and explore building our own components. Quickly it became clear others might benefit from sharing our lessons learned and our endeavour shifted to creating Belle - a set of configurable components with all these features included: 46 |

47 |
    48 |
  • Encapsulated components
  • 49 |
  • Mobile support built-in
  • 50 |
  • ARIA Support
  • 51 |
  • Customizable styles / themes (right now there is Belle & Bootstrap 3)
  • 52 |
  • Advanced localized styling for each individual component
  • 53 |
54 | 55 |

56 | With Belle we aim to provide the best possible UX while making the components highly configurable to allow users applying their own theme. For demonstration purposes Belle comes with two themes (Belle, Bootstrap3) and we aim to add more like Elemental UI or Material Design soon. 57 |

58 | 59 |
60 |

65 | 66 | This is so good. I like the effort you put into tweaking the UX. 67 | 74 |

75 |
76 | 82 |
85 | Christopher Chedeau (Vjeux) 86 |
87 |
90 | React Core Team 91 |
92 |
93 |
94 |
95 | 96 |

Let’s have a look at two of the components and walk you through some of the details we took care of.

97 | 98 |

Toggle

99 | 100 |

The handle can be grabbed and dragged on mobile as well as on desktop devices. In addition a simple tap or click also initiates switching the state. As like with the native iOS Toggle it is possible to slightly leave the bounding area while continuing to slide. In order to prevent shaky page behaviour and delayed animations is scrolling is prevented while the Toggle is active. 101 |

102 | 103 |
104 | 105 |
106 | 107 |
108 |
109 | 110 | With custom Styles 111 |
112 | 113 |
114 | 115 | Bootstrap Styles
116 | 117 | 118 |
119 | 120 | Try it yourself here: 121 |

122 | 123 | 124 | 125 | 126 |

127 | Let’s look at another component. 128 |

129 | 130 |

Select

131 | 132 |

133 | While the HTML native select-tag is a great component it’s styling capabilities are very limited. Adding images is not possible. That’s why we built a Select component allowing you to modify its appearance. 134 |

135 | 136 | 137 | 138 |

Select on Mobile

139 | 140 |

141 | As promised before the Select component even works well on mobile devices. Even if scrolling is involved. You will notice that the menu will always positioned in a way that the focused Option is always visible and right above the selected one. 142 |

143 | 144 |
145 | 146 |
147 | 148 | 149 | 150 |

151 | I hope Belle caught your interest. In case you want to give it a try please checkout our example projects like react-starter-with-belle or react-server-example. We look forward to your feedback. Feel free to reach out to us via Twitter @nikgraf & 152 | @jyopur. 153 |

154 | 155 |
156 | Tweet 157 | 158 |
159 |
160 |
161 |
162 | 163 | 164 |
); 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /docs/components/routes.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { IndexRoute, Route } from 'react-router'; 3 | 4 | import Base from './Base'; 5 | import ComboBoxDocumentation from './components/ComboBoxDocumentation'; 6 | import DatePickerDocumentation from './components/DatePickerDocumentation'; 7 | import ButtonDocumentation from './components/ButtonDocumentation'; 8 | import CardDocumentation from './components/CardDocumentation'; 9 | import ChoiceDocumentation from './components/ChoiceDocumentation'; 10 | import Configuration from './Configuration'; 11 | import GettingStarted from './GettingStarted'; 12 | import About from './About'; 13 | import Home from './Home'; 14 | import OptionDocumentation from './components/OptionDocumentation'; 15 | import Philosophy from './Philosophy'; 16 | import PlaceholderDocumentation from './components/PlaceholderDocumentation'; 17 | import RatingDocumentation from './components/RatingDocumentation'; 18 | import SelectDocumentation from './components/SelectDocumentation'; 19 | import SeparatorDocumentation from './components/SeparatorDocumentation'; 20 | import SpinnerDocumentation from './components/SpinnerDocumentation'; 21 | import TextInputDocumentation from './components/TextInputDocumentation'; 22 | import ToggleDocumentation from './components/ToggleDocumentation'; 23 | import FormComponents from './FormComponents'; 24 | import IntroducingBelleGuide from './guides/IntroducingBelle'; 25 | 26 | const routes = ( 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | ); 50 | 51 | module.exports = routes; 52 | -------------------------------------------------------------------------------- /docs/css/style.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | } 4 | 5 | *, *:before, *:after { 6 | box-sizing: inherit; 7 | } 8 | 9 | body { 10 | font-size: 15px; 11 | line-height: 1.6; 12 | font-family: "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; 13 | color: #444; 14 | background: #F7F7F7; 15 | } 16 | 17 | h3 { 18 | margin-top: 60px; 19 | } 20 | 21 | a, a:visited { 22 | color: #888; 23 | text-decoration: none; 24 | } 25 | 26 | a:hover { 27 | color: #aaa; 28 | } 29 | 30 | a:active { 31 | color: #444; 32 | } 33 | 34 | .navigation a, .navigation a:visited { 35 | color: #0A202D; 36 | } 37 | 38 | .navigation a:hover { 39 | color: #34A1CA; 40 | } 41 | 42 | .navigation a:active { 43 | color: #444; 44 | } 45 | -------------------------------------------------------------------------------- /docs/icon/apple-touch-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/icon/apple-touch-icon-114x114.png -------------------------------------------------------------------------------- /docs/icon/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/icon/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /docs/icon/apple-touch-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/icon/apple-touch-icon-144x144.png -------------------------------------------------------------------------------- /docs/icon/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/icon/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /docs/icon/apple-touch-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/icon/apple-touch-icon-57x57.png -------------------------------------------------------------------------------- /docs/icon/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/icon/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /docs/icon/apple-touch-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/icon/apple-touch-icon-72x72.png -------------------------------------------------------------------------------- /docs/icon/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/icon/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /docs/icon/favicon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/icon/favicon-128.png -------------------------------------------------------------------------------- /docs/icon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/icon/favicon-16x16.png -------------------------------------------------------------------------------- /docs/icon/favicon-196x196.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/icon/favicon-196x196.png -------------------------------------------------------------------------------- /docs/icon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/icon/favicon-32x32.png -------------------------------------------------------------------------------- /docs/icon/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/icon/favicon-96x96.png -------------------------------------------------------------------------------- /docs/icon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/icon/favicon.ico -------------------------------------------------------------------------------- /docs/icon/mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/icon/mstile-144x144.png -------------------------------------------------------------------------------- /docs/icon/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/icon/mstile-150x150.png -------------------------------------------------------------------------------- /docs/icon/mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/icon/mstile-310x150.png -------------------------------------------------------------------------------- /docs/icon/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/icon/mstile-310x310.png -------------------------------------------------------------------------------- /docs/icon/mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/icon/mstile-70x70.png -------------------------------------------------------------------------------- /docs/images/abyssinian.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/images/abyssinian.jpg -------------------------------------------------------------------------------- /docs/images/albatross.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/images/albatross.jpg -------------------------------------------------------------------------------- /docs/images/angelfish.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/images/angelfish.jpg -------------------------------------------------------------------------------- /docs/images/ant.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/images/ant.jpg -------------------------------------------------------------------------------- /docs/images/antelope.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/images/antelope.jpg -------------------------------------------------------------------------------- /docs/images/asian_elephant.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/images/asian_elephant.jpg -------------------------------------------------------------------------------- /docs/images/belle_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/images/belle_logo.png -------------------------------------------------------------------------------- /docs/images/croatia_100.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/images/croatia_100.jpg -------------------------------------------------------------------------------- /docs/images/croatia_original.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/images/croatia_original.jpg -------------------------------------------------------------------------------- /docs/images/ngorongoro_caldera_small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/images/ngorongoro_caldera_small.jpg -------------------------------------------------------------------------------- /docs/images/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/images/overview.png -------------------------------------------------------------------------------- /docs/images/santorini_100.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/images/santorini_100.jpg -------------------------------------------------------------------------------- /docs/images/santorini_original.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/images/santorini_original.jpg -------------------------------------------------------------------------------- /docs/images/vjeux.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/images/vjeux.jpeg -------------------------------------------------------------------------------- /docs/images/yosemite_100.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/images/yosemite_100.jpg -------------------------------------------------------------------------------- /docs/images/yosemite_original.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikgraf/belle/e0f561d6ad704b5e3d66a38752de29f938b065af/docs/images/yosemite_original.jpg -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Belle - Configurable React Components with great UX 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /docs/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import routes from './components/routes'; 4 | import { Router, hashHistory } from 'react-router'; 5 | import initializeTheme from './theme/initialize'; 6 | 7 | // export for http://fb.me/react-devtools 8 | window.React = React; 9 | 10 | initializeTheme(); 11 | const rootComponent = ; 12 | 13 | ReactDOM.render(rootComponent, document.getElementById('react')); 14 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "belleDocumentation", 3 | "version": "3.0.2", 4 | "description": "Docuemtation for Belle", 5 | "author": { 6 | "name": "Nik Graf", 7 | "email": "nik@nikgraf.com", 8 | "url": "http://www.nikgraf.com" 9 | }, 10 | "main": "js/App.jsx", 11 | "repository": { 12 | "type": "git", 13 | "url": "http://github.com/nikgraf/belle.git" 14 | }, 15 | "dependencies": { 16 | "highlight.js": "=9.2.0", 17 | "history": "^2.0.1", 18 | "react": "^=15.4.1", 19 | "react-addons-linked-state-mixin": "^=15.4.1", 20 | "react-dom": "^=15.4.1", 21 | "react-router": "=v2.5.2", 22 | "uglify-js": "=2.6.2", 23 | "underscore": "=1.8.3" 24 | }, 25 | "devDependencies": { 26 | "babel-core": "^6.7.4", 27 | "babel-loader": "^6.2.4", 28 | "eslint": "^2.5.3", 29 | "eslint-config-airbnb": "^6.2.0", 30 | "eslint-plugin-react": "^4.2.3", 31 | "express": "^4.13.4", 32 | "node-libs-browser": "^1.0.0", 33 | "webpack": "^1.12.14" 34 | }, 35 | "scripts": { 36 | "start": "node server.js", 37 | "build": "NODE_ENV=production webpack -p --config webpack.config.production.js", 38 | "postinstall": "cp node_modules/highlight.js/styles/googlecode.css css/googlecode.css" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /docs/server.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-var, no-console */ 2 | 3 | var path = require('path'); 4 | var express = require('express'); 5 | var webpack = require('webpack'); 6 | var config = require('./webpack.config'); 7 | var app = express(); 8 | var compiler = webpack(config); 9 | 10 | app.use('/css', express.static('css')); 11 | app.use('/icon', express.static('icon')); 12 | app.use('/images', express.static('images')); 13 | 14 | app.use(require('webpack-dev-middleware')(compiler, { 15 | noInfo: true, 16 | publicPath: config.output.publicPath, 17 | })); 18 | 19 | app.use(require('webpack-hot-middleware')(compiler)); 20 | 21 | app.get('*', (req, res) => { 22 | res.sendFile(path.join(__dirname, 'index.html')); 23 | }); 24 | 25 | app.listen(3000, 'localhost', (err) => { 26 | if (err) { 27 | console.log(err); 28 | return; 29 | } 30 | 31 | console.log('Listening at http://localhost:3000'); 32 | }); 33 | -------------------------------------------------------------------------------- /docs/style.js: -------------------------------------------------------------------------------- 1 | const style = { 2 | propertyNameStyle: { 3 | padding: '0 20px 0 0', 4 | textAlign: 'left', 5 | verticalAlign: 'top', 6 | color: 'grey', 7 | }, 8 | 9 | propertyDescriptionStyle: { 10 | padding: 0, 11 | textAlign: 'left', 12 | verticalAlign: 'top', 13 | paddingBottom: 30, 14 | }, 15 | }; 16 | 17 | export default style; 18 | -------------------------------------------------------------------------------- /docs/theme/ThemeSwitch.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Button } from 'belle'; 4 | 5 | export default React.createClass({ 6 | 7 | contextTypes: { 8 | location: PropTypes.object, 9 | }, 10 | 11 | _onSwitchTheme(name) { 12 | window.location.hash = `${this.context.location.pathname}\?theme=${name}`; 13 | window.location.reload(); 14 | }, 15 | 16 | render() { 17 | // TODO 18 | const currentTheme = undefined; 19 | 20 | return ( 21 |
22 |

23 | You choose between one of the themes below 24 |

25 | 26 |
27 | 34 | 42 | 50 |
51 |
52 | ); 53 | }, 54 | }); 55 | -------------------------------------------------------------------------------- /docs/theme/belle-with-classic-focus.js: -------------------------------------------------------------------------------- 1 | const belleWithClassicFocus = { 2 | 3 | config: { 4 | button: { 5 | preventFocusStyleForTouchAndClick: false, 6 | }, 7 | rating: { 8 | preventFocusStyleForTouchAndClick: false, 9 | }, 10 | toggle: { 11 | preventFocusStyleForTouchAndClick: false, 12 | }, 13 | datePicker: { 14 | preventFocusStyleForTouchAndClick: false, 15 | }, 16 | }, 17 | 18 | style: { 19 | button: { 20 | focusStyle: { 21 | boxShadow: '0 0 0 3px rgba(140, 224, 255, 0.6)', 22 | outline: 0, 23 | }, 24 | primaryFocusStyle: { 25 | boxShadow: '0 0 0 3px rgba(140, 224, 255, 0.6)', 26 | outline: 0, 27 | }, 28 | }, 29 | rating: { 30 | focusStyle: { 31 | boxShadow: '0 0 0 3px rgba(140, 224, 255, 0.6)', 32 | outline: 0, 33 | borderRadius: 3, 34 | }, 35 | }, 36 | toggle: { 37 | focusStyle: { 38 | boxShadow: '0 0 0 3px rgba(140, 224, 255, 0.6)', 39 | outline: 0, 40 | }, 41 | }, 42 | datePicker: { 43 | focusStyle: { 44 | boxShadow: '0 0 0 3px rgba(140, 224, 255, 0.6)', 45 | outline: 0, 46 | }, 47 | }, 48 | }, 49 | 50 | }; 51 | 52 | export default belleWithClassicFocus; 53 | -------------------------------------------------------------------------------- /docs/theme/initialize.js: -------------------------------------------------------------------------------- 1 | import belle from 'belle'; 2 | import bootstrap3Theme from './bootstrap-3'; 3 | import belleWithClassicFocusTheme from './belle-with-classic-focus'; 4 | 5 | /** 6 | * Get a URL query parameter from the hash. 7 | */ 8 | export function getParameterByName(name) { 9 | const parsedName = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]'); 10 | const regex = new RegExp(`[\\?&]${parsedName}=([^&#]*)`); 11 | const results = regex.exec(location.hash); 12 | return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' ')); 13 | } 14 | 15 | /** 16 | * Updates the deepest structure while keeping the original reference of the outer objects. 17 | */ 18 | function updateStructure(targetObject, object) { 19 | for (const componentName in object) { 20 | if (object.hasOwnProperty(componentName)) { 21 | for (const styleName in object[componentName]) { 22 | if (object[componentName].hasOwnProperty(styleName)) { 23 | targetObject[componentName][styleName] = object[componentName][styleName]; // eslint-disable-line no-param-reassign 24 | } 25 | } 26 | } 27 | } 28 | } 29 | 30 | function initializeTheme() { 31 | const theme = getParameterByName('theme'); 32 | 33 | if (theme === 'bootstrap') { 34 | updateStructure(belle.style, bootstrap3Theme.style); 35 | updateStructure(belle.config, bootstrap3Theme.config); 36 | } else if (theme === 'belle-with-default-focus') { 37 | updateStructure(belle.style, belleWithClassicFocusTheme.style); 38 | updateStructure(belle.config, belleWithClassicFocusTheme.config); 39 | } 40 | } 41 | 42 | export default initializeTheme; 43 | -------------------------------------------------------------------------------- /docs/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); // eslint-disable-line no-var 2 | var webpack = require('webpack'); // eslint-disable-line no-var 3 | 4 | module.exports = { 5 | devtool: 'eval', 6 | entry: [ 7 | 'webpack-hot-middleware/client', 8 | './index', 9 | ], 10 | output: { 11 | path: path.join(__dirname, 'dist'), 12 | filename: 'bundle.js', 13 | publicPath: '/static/', 14 | }, 15 | plugins: [ 16 | new webpack.HotModuleReplacementPlugin(), 17 | new webpack.NoErrorsPlugin(), 18 | ], 19 | resolve: { 20 | alias: { 21 | belle: path.join(__dirname, '..', 'src'), 22 | react: path.join(__dirname, 'node_modules', 'react'), 23 | }, 24 | extensions: ['', '.js'], 25 | }, 26 | module: { 27 | loaders: [ 28 | { 29 | test: /\.js$/, 30 | loaders: ['babel'], 31 | exclude: /node_modules/, 32 | include: __dirname, 33 | }, { 34 | test: /\.js$/, 35 | loaders: ['babel'], 36 | include: path.join(__dirname, '..', 'src'), 37 | }, 38 | ], 39 | }, 40 | }; 41 | -------------------------------------------------------------------------------- /docs/webpack.config.production.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); // eslint-disable-line no-var 2 | var webpack = require('webpack'); // eslint-disable-line no-var 3 | 4 | module.exports = { 5 | entry: [ 6 | './index', 7 | ], 8 | output: { 9 | path: path.join(__dirname, 'static'), 10 | filename: 'bundle.js', 11 | publicPath: '/static/', 12 | }, 13 | resolve: { 14 | alias: { 15 | belle: path.join(__dirname, '..', 'src'), 16 | react: path.join(__dirname, 'node_modules', 'react'), 17 | }, 18 | extensions: ['', '.js'], 19 | }, 20 | plugins: [ 21 | new webpack.optimize.UglifyJsPlugin({ minimize: true }), 22 | new webpack.DefinePlugin({ 23 | 'process.env': { 24 | NODE_ENV: JSON.stringify('production'), 25 | }, 26 | }), 27 | ], 28 | module: { 29 | loaders: [ 30 | { 31 | test: /\.js$/, 32 | loaders: ['babel'], 33 | exclude: /node_modules/, 34 | include: __dirname, 35 | }, { 36 | test: /\.js$/, 37 | loaders: ['babel'], 38 | include: path.join(__dirname, '..', 'src'), 39 | }, 40 | ], 41 | }, 42 | }; 43 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | Examples Playground for Development 2 | ================ 3 | 4 | ## Install 5 | 6 | ``` 7 | npm install 8 | ``` 9 | 10 | Make sure you ran `npm install` in the root folder of Belle. 11 | 12 | ## Run 13 | 14 | ``` 15 | npm start 16 | ``` 17 | 18 | The app will run with hot reloading on `http://localhost:3000`. 19 | -------------------------------------------------------------------------------- /examples/components/ButtonPlayground.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button, Card } from 'belle'; 3 | 4 | export default React.createClass({ 5 | 6 | render() { 7 | return ( 8 | 9 |

Button

10 | 11 |

Default Button

12 | 13 | 14 |

Disabled Default Button

15 | 16 | 17 |

Default Button

18 | 19 | 20 |

Disabled Button

21 | 22 | 23 |

Primary Button

24 | 25 | 26 |

Disabled Primary Button

27 | 28 | 29 |

Colored Buttons

30 | 31 | 32 | 33 | 34 | 35 |
36 | ); 37 | }, 38 | }); 39 | -------------------------------------------------------------------------------- /examples/components/CardPlayground.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Card } from 'belle'; 3 | 4 | export default React.createClass({ 5 | 6 | render() { 7 | return ( 8 |
9 |

Card

10 | 11 |

Looks nice!

12 | 13 | What about another font color? 14 | 15 | 16 |
Looks nice!
17 |
Even with multiple elements passed
18 |
19 | 20 |
21 | ); 22 | }, 23 | }); 24 | -------------------------------------------------------------------------------- /examples/components/ComboBoxPlayground.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | 3 | import React from 'react'; 4 | import { Card, ComboBox, Option } from 'belle'; 5 | 6 | export default React.createClass({ 7 | 8 | getInitialState() { 9 | return { comboValue: 'te' }; 10 | }, 11 | 12 | _handleChange(newValue) { 13 | this.setState({ comboValue: newValue }); 14 | }, 15 | 16 | render() { 17 | const valueLink = { 18 | value: this.state.comboValue, 19 | requestChange: this._handleChange, 20 | }; 21 | 22 | return ( 23 |
24 | 25 |

ComboBox

26 | 27 | 28 |

Default Value Example

29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 |
39 | 40 |

Value Example

41 |
42 | { 45 | console.log(`${event.value} - ${event.identifier} - ${event.isOptionSelection} - ${event.isMatchingOption}`); 46 | }} 47 | > 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 |
56 | 57 |

Value Link Example

58 |
59 | { console.log(event.value); }}> 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 |
68 | 69 |
70 | 71 | 72 | 73 |
74 | 75 |
76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 |
85 | 86 |
87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 |
96 | 97 |
98 | 99 | 100 | 101 | 102 |
103 | 104 |
105 | 106 |
107 | ); 108 | }, 109 | }); 110 | -------------------------------------------------------------------------------- /examples/components/DatePickerPlayground.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Card, DatePicker } from 'belle'; 3 | 4 | export default React.createClass({ 5 | 6 | _renderDay(day) { 7 | const date = day.getDate(); 8 | return ( 9 |
10 | 🎁{ date } 11 |
12 | ); 13 | }, 14 | 15 | _onMouseDown(event) { 16 | event.stopPropagation(); 17 | }, 18 | 19 | render() { 20 | const selectedDate = new Date(); 21 | selectedDate.setDate(selectedDate.getDate() + 5); 22 | 23 | const minDate = new Date(); 24 | minDate.setDate(10); 25 | 26 | const maxDate = new Date(); 27 | maxDate.setDate(20); 28 | 29 | return ( 30 |
31 | 32 |

DatePicker

33 | 34 | 35 |

Default Calendar Example

36 |
37 | 38 |
39 | 40 |

DatePicker with min & max

41 |
42 | 47 |
48 | 49 |

Disabled Calendar Example

50 |
51 | 52 |
53 |

Calendar without showing other months dates Example

54 |
55 | 56 |
57 |

Read-Only active Calendar Example

58 |
59 | 63 |
64 |

Special renderDay

65 |
66 | 70 |
71 |

Calendar in dutch french !!!

72 |
73 | 74 |
75 |

Calendar in dutch arabic !!!

76 |
77 | 78 |
79 |

Calendar in dutch hebrew !!!

80 |
81 | 85 |
86 |
87 | 88 |
89 | ); 90 | }, 91 | }); 92 | -------------------------------------------------------------------------------- /examples/components/RatingPlayground.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | 3 | import React from 'react'; 4 | import LinkedStateMixin from 'react-addons-linked-state-mixin'; 5 | import { Card, Rating, Button } from 'belle'; 6 | 7 | export default React.createClass({ 8 | 9 | mixins: [LinkedStateMixin], 10 | 11 | getInitialState() { 12 | return { ratingValue: 2 }; 13 | }, 14 | 15 | _handleChange(newValue) { 16 | this.setState({ ratingValue: newValue }); 17 | }, 18 | 19 | _updateRatingToThree() { 20 | this.setState({ ratingValue: 3 }); 21 | }, 22 | 23 | render() { 24 | return ( 25 |
26 |

Rating

27 | 28 | 29 | 30 | 31 | 32 | //onUpdate should not be called for valueLink 33 |

ValueLink

34 | console.log(event.value) } 37 | /> 38 | 39 |

Value with update function onUpdate

40 | { 43 | console.log(event.value); 44 | this._handleChange(event.value); 45 | } 46 | } 47 | /> 48 | 49 |

Value

50 | console.log(event.value) } 53 | /> 54 | 55 |

DefaultValue

56 | console.log(event.value) } 59 | /> 60 | 61 |

Disabled

62 | 63 | 64 |

RatingCharacter

65 | 66 | 67 |
68 | 69 |
70 | ); 71 | }, 72 | }); 73 | -------------------------------------------------------------------------------- /examples/components/SpinnerPlayground.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button, Card, Spinner } from 'belle'; 3 | 4 | export default React.createClass({ 5 | 6 | render() { 7 | return ( 8 | 9 |

Spinner

10 | 11 | 12 | 13 |

14 | Loading 15 |

16 | 17 | 20 | 21 | 24 | 25 |
26 | ); 27 | }, 28 | 29 | }); 30 | -------------------------------------------------------------------------------- /examples/components/TextInputPlayground.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | 3 | import React from 'react'; 4 | import { TextInput, Card } from 'belle'; 5 | 6 | function conditionalTextInput(showTextInput) { 7 | if (showTextInput) { 8 | return ; 9 | } 10 | 11 | return null; 12 | } 13 | 14 | export default React.createClass({ 15 | 16 | getInitialState() { 17 | return { 18 | showTextInput: true, 19 | inputValue: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 20 | }; 21 | }, 22 | 23 | _handleChange(newValue) { 24 | this.setState({ inputValue: newValue }); 25 | }, 26 | 27 | _removeTextInput() { 28 | this.setState({ 29 | showTextInput: false, 30 | }); 31 | }, 32 | 33 | render() { 34 | const valueLink = { 35 | value: this.state.inputValue, 36 | requestChange: this._handleChange, 37 | }; 38 | 39 | return ( 40 | 41 |

TextInput

42 | 43 | {/* Common use case */} 44 | console.log(event.value) } 49 | /> 50 |
51 | 52 | {/* Common use case disabled */} 53 | 54 |
55 | 56 | {/* Remove TextInput behaviour */} 57 | {conditionalTextInput(this.state.showTextInput)} 58 |
59 | 60 | 61 | {/* Empty TextInput */} 62 | 63 |
64 | 65 |

Not editable value

66 |
67 | { 71 | console.log(event.value); 72 | this._handleChange(event.value); 73 | } 74 | } 75 | /> 76 |
77 |
78 | 79 | {/* Full width TextInput */} 80 |
81 | 82 |
83 |
84 | 85 | {/* TextInput with placeholder & a minHeight & custom hoverStyle */} 86 |
87 | 92 |
93 | 94 |

Test with 3 min rows & 5 max rows

95 |
96 | 97 |
98 | 99 |

Test 4 min rows & minHeight 80

100 |
101 | 102 |
103 | 104 |

Test 2 max rows & maxHeight 300

105 |
106 | 107 |
108 | 109 |

style minHeight 80

110 |
111 | 112 |
113 | 114 | {/* Value test */} 115 |
116 |