├── .babelrc ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .jscsrc ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── app ├── README.md ├── components │ ├── HintCssModulesExample │ │ ├── index.js │ │ └── styles.css │ ├── HintExample │ │ └── index.js │ └── HintJssExample │ │ ├── index.js │ │ └── styles.js ├── index.html ├── index.js ├── package.json ├── server.js └── webpack.config.js ├── global-theming.md ├── package.json └── ui-lib ├── Context ├── Hint.js └── Theme.js ├── Factory ├── belle │ └── Hint.js ├── elemental │ └── Hint.js ├── react-themeable │ └── createComponent.js └── ui-core │ └── Hint.js ├── ModuleExport └── Hint.js └── StaticProperty └── Hint.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 | app/** 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "env": { 4 | "mocha": true 5 | }, 6 | "rules": { 7 | "react/prop-types": 0 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.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 | .DS_Store 7 | 8 | # Webpack cache & build files 9 | bundle.js 10 | .bundle.js 11 | 12 | # Build 13 | /lib/ 14 | 15 | # NPM debug 16 | npm-debug.log 17 | npm-debug.log* 18 | -------------------------------------------------------------------------------- /.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "preset": "airbnb", 3 | "validateQuoteMarks": null, 4 | "excludeFiles": [ 5 | "coverage/**", 6 | "node_modules/**", 7 | "app/**", 8 | "lib/**" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /.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 | # Webpack cache & build files 7 | bundle.js 8 | .bundle.js 9 | 10 | # Sources 11 | /app/ 12 | 13 | # NPM debug 14 | npm-debug.log 15 | 16 | tests 17 | docs 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "4.1" 4 | sudo: false 5 | script: 6 | - npm test 7 | - npm run lint 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Nik 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 | # A Playground to investigate a good third-party React UI Lib Architecture 2 | 3 | My goal is to find an architecture which could be common ground a base for quality React UI libraries. A consistent theming/styling API would make the lives of many developers way more comfortable. 4 | 5 | HELP/FEEDBACK/YOUR OPINION WANTED! :) 6 | Feel free to join the ongoing discussion [here](https://github.com/nikgraf/future-react-ui/issues/1) or open up a new issue. 7 | 8 | ## How to setup & run 9 | 10 | ``` 11 | npm install 12 | cd app 13 | npm install 14 | npm start 15 | ``` 16 | 17 | ## Basic Ideas 18 | 19 | #### Self-contained 20 | 21 | Make components self contained (no global UI lib dependencies) so you can import them and avoid importing the whole library e.g. 22 | 23 | ``` 24 | // import the whole lib and get Toggle 25 | import { Toggle } from 'ui-lib'; 26 | 27 | // just import toggle without importing the whole library 28 | import Toggle from 'ui-lib/Toggle'; 29 | ``` 30 | 31 | #### react-themeable 32 | 33 | Leverage react-themeable. It's a nice way of providing many styling classes to a single component. 34 | I believe establishing this as a convention would benefit the React community due the consistent API over many libs. 35 | 36 | #### ClassName based 37 | 38 | Component styles should be class based. It's more performant & responsive styling doesn't work with server-side rendering. I myself went down the inline-styles path in the past, but switched back to classes. A component using react-themeable could actually work with both (class-names & inline-styles), but I believe this is an unnecessary overhead. Your thoughts? 39 | 40 | #### Ship without a theme 41 | 42 | Ship without a global theme so people don't have to import the styling code. This might not be relevant to company internal or in general libraries that a opinionated about styling. 43 | 44 | #### Global theming utility 45 | 46 | Provide a simple & handy way to apply a global theme for all the imported components. 47 | 48 | ## Global Theming 49 | 50 | While react-themeable is super useful I believe having a way to set a default styling is a crucial feature for a UI library. Most of the time you will use the default theme specific to your product. This avoids adding a lot of theme props through the whole application. 51 | 52 | ### Factory Pattern 53 | 54 | https://github.com/nikgraf/future-react-ui/tree/master/ui-lib/Factory 55 | 56 | In this version we assume there is a package which includes a completely unstyled version of the UI kits while there is a second one which takes all the needed components and return themed components buy leveraging a factory function. 57 | 58 | ``` 59 | /** 60 | * Returns a the provided component as themed component. 61 | * 62 | * Note: defaultProps could be useful for default special behavioural in 63 | * different ui libraries. 64 | */ 65 | export default (Component, theme, defaultProps) => (props) => { 66 | return ; 67 | }; 68 | ``` 69 | 70 | For example these UI 71 | 72 | #### Not themed kits & components 73 | 74 | - material-ui-core (unstyled kit) 75 | - belle-core (unstyled kit) 76 | - elemental-core (unstyled kit) 77 | - react-toolbox-core (unstyled kit) 78 | - react-select (unstyled component) 79 | - react-autocomplete (unstyled component) 80 | - react-modal (unstyled component) 81 | 82 | #### Themed UI kits 83 | 84 | - material-ui (themed with material ui style and based on material-ui-core) 85 | - belle (themed with belle style and based on belle-core) 86 | - belle-flat (themed with a flat theme and based on belle-core) 87 | - elemental (themed with the elemental theme and based on elemental-core) 88 | - react-toolbox (themed with the material theme and based on react-toolbox-core) 89 | - your-product-ui-lib (themed with your company style and based on belle-core[Toggle, Rating] & react-select & react-modal) 90 | - your-friends-product-ui-lib (themed with their company style and based on react-select & react-modal & react-autocomplete) 91 | 92 | Usage: 93 | ``` 94 | import Hint from 'elemental/Hint'; 95 | 96 | const customTheme = { 97 | questionMark: 'custom-class-for-question-mark-gold', 98 | visibleContent: 'custom-class-visible-content', 99 | }; 100 | 101 | export default (props) => { 102 | return ( 103 |
104 | {/* Globally theme component */} 105 | 106 | {/* Overwriting the theme locally for this case */} 107 | 108 |
109 | ); 110 | }; 111 | ``` 112 | 113 | ### Other Global Theming Patterns 114 | 115 | other patterns can be found here: https://github.com/nikgraf/future-react-ui/blob/master/global-theming.md 116 | 117 | ## Temporary Conclusion 118 | 119 | While the Theme component based idea is pretty powerful the issues make me not like it as a default. For some time I was convinced that Module export or Static property would be one of the winners. Right now I'm pretty convinced the Factory Pattern is the clear winner. It is super flexible and allows people to create their own company UI kits. They can easily provide their own styling as well as set other props as default suited to their needs. Another benefit is that you can easily get started with prototyping by using an already style version (e.g. belle-flat) and replace it later with your custom product style. 120 | 121 | If you have some ideas/feedback please reach out to me and let's discuss. (Github Issues might be best, but Twitter, Email, Skype, Hangout works as well) 122 | 123 | ## License 124 | 125 | MIT 126 | -------------------------------------------------------------------------------- /app/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. 11 | 12 | ## Run 13 | 14 | ``` 15 | npm start 16 | ``` 17 | 18 | The app will run with hot reloading on `http://localhost:3000`. 19 | -------------------------------------------------------------------------------- /app/components/HintCssModulesExample/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Hint from 'ui-lib/StaticProperty/Hint'; 3 | import styles from './styles.css'; 4 | 5 | const HintExample = () => { 6 | return ( 7 |
8 | 9 | CSS Modules styled closed hint. 10 | 11 | 12 | 13 | CSS Modules styles open hint. 14 | 15 |
16 | ); 17 | }; 18 | 19 | export default HintExample; 20 | -------------------------------------------------------------------------------- /app/components/HintCssModulesExample/styles.css: -------------------------------------------------------------------------------- 1 | .base { 2 | margin-bottom: 10px; 3 | } 4 | 5 | .questionMark { 6 | box-sizing: border-box; 7 | background: grey; 8 | color: #fff; 9 | border-radius: 18px; 10 | width: 18px; 11 | height: 18px; 12 | font-size: 14px; 13 | text-align: center; 14 | padding-top: 1px; 15 | cursor: pointer; 16 | display: inline-block; 17 | } 18 | 19 | .visibleContent { 20 | position: relative; 21 | border: 1px solid #ccc; 22 | border-radius: 3px; 23 | padding: 10px; 24 | display: inline-block; 25 | margin-left: 5px; 26 | } 27 | 28 | .hiddenContent { 29 | display: none; 30 | } 31 | -------------------------------------------------------------------------------- /app/components/HintExample/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Hint from 'ui-lib/StaticProperty/Hint'; 3 | import Hint2 from 'ui-lib/ModuleExport/Hint'; 4 | import Hint3 from 'ui-lib/ModuleExport/Hint'; 5 | 6 | const HintExample = () => { 7 | return ( 8 |
9 | 10 |
11 | ); 12 | }; 13 | 14 | export default HintExample; 15 | -------------------------------------------------------------------------------- /app/components/HintJssExample/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Hint from 'ui-lib/StaticProperty/Hint'; 3 | import jss from 'jss'; 4 | import styles from './styles'; 5 | 6 | const styleSheet = jss.createStyleSheet(styles).attach(); 7 | 8 | const HintExample = () => { 9 | return ( 10 |
11 | 12 | JSS styled closed hint. 13 | 14 | 15 | 16 | JSS styles open hint. 17 | 18 |
19 | ); 20 | }; 21 | 22 | export default HintExample; 23 | -------------------------------------------------------------------------------- /app/components/HintJssExample/styles.js: -------------------------------------------------------------------------------- 1 | export default { 2 | base: { 3 | 'margin-bottom': '10px', 4 | }, 5 | questionMark: { 6 | 'box-sizing': 'border-box', 7 | background: 'grey', 8 | color: '#fff', 9 | 'border-radius': '18px', 10 | width: '18px', 11 | height: '18px', 12 | 'font-size': '14px', 13 | 'text-align': 'center', 14 | 'padding-top': '1px', 15 | cursor: 'pointer', 16 | display: 'inline-block', 17 | }, 18 | visibleContent: { 19 | position: 'relative', 20 | border: '1px solid #ccc', 21 | 'border-radius': '3px', 22 | padding: '10px', 23 | display: 'inline-block', 24 | 'margin-left': '5px', 25 | }, 26 | hiddenContent: { 27 | display: 'none', 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Belle Future 10 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | import HintExample from './components/HintExample'; 5 | import HintJssExample from './components/HintJssExample'; 6 | import HintCssModulesExample from './components/HintCssModulesExample'; 7 | 8 | /* In this version each porperty of the importet theme can be overwritten. */ 9 | import Hint, { defaultTheme } from 'ui-lib/ModuleExport/Hint'; 10 | defaultTheme.questionMark = 'custom-class-for-question-mark-green'; 11 | defaultTheme.visibleContent = 'custom-class-visible-content'; 12 | 13 | /* In this variant the default theme can be overwritten by assigning a new object. */ 14 | import Hint2 from 'ui-lib/StaticProperty/Hint'; 15 | Hint2.theme = { 16 | questionMark: 'custom-class-for-question-mark-red', 17 | visibleContent: 'custom-class-visible-content', 18 | }; 19 | /* It is also possible to just overwrite a single property. */ 20 | Hint2.theme.questionMark = 'custom-class-for-question-mark-red'; 21 | 22 | /* Context based theming */ 23 | import Hint3 from 'ui-lib/Context/Hint'; 24 | import Theme from 'ui-lib/Context/Theme'; 25 | const contextTheme = { 26 | hint: { 27 | questionMark: 'custom-class-for-question-mark-blue', 28 | visibleContent: 'custom-class-visible-content', 29 | }, 30 | }; 31 | 32 | /* Factory based theming 33 | * also see /ui-lib/Factory/belle/Hint or /ui-lib/Factory/elemental/Hint 34 | */ 35 | import Hint4Unstyled from '../ui-lib/Factory/ui-core/Hint'; 36 | import createComponent from '../ui-lib/Factory/react-themeable/createComponent'; 37 | const theme = { 38 | questionMark: 'custom-class-for-question-mark-gold', 39 | visibleContent: 'custom-class-visible-content', 40 | }; 41 | const Hint4 = createComponent(Hint, theme); 42 | 43 | window.React = React; 44 | 45 | const App = () => { 46 | return ( 47 |
48 |

JSS styled

49 | 50 |

CSS Modules styled

51 | 52 | 53 |

54 | 55 |

Unstyled (globally patched classNames)

56 |

Global theme as module export

57 | Basic closed hint without styling. 58 | Basic open hint without styling. 59 | 60 | 61 |

Global theme as static property

62 | Basic closed hint without styling. 63 | Basic open hint without styling. 64 | 65 | 66 |

Global theme as Theme component leveraging context

67 | 68 | Basic closed hint without styling. 69 | Basic open hint without styling. 70 | 71 | 72 | 73 |

Factory to create Components with a provided Theme

74 | Basic closed hint without styling. 75 | Basic open hint without styling. 76 |
77 | ); 78 | }; 79 | 80 | ReactDOM.render(, document.getElementById('react')); 81 | -------------------------------------------------------------------------------- /app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ui-lib-future-playground", 3 | "version": "0.0.0", 4 | "description": "", 5 | "author": { 6 | "name": "Nik Graf", 7 | "email": "nik@nikgraf.com", 8 | "url": "https://github.com/nikgraf" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "TODO" 13 | }, 14 | "dependencies": { 15 | "babel-preset-stage-0": "^6.3.13", 16 | "css-loader": "^0.23.1", 17 | "extract-text-webpack-plugin": "^1.0.1", 18 | "jss": "^3.2.0", 19 | "react": "=0.14.6", 20 | "react-dom": "^0.14.6", 21 | "style-loader": "^0.13.0" 22 | }, 23 | "devDependencies": { 24 | "babel-core": "^6.4.5", 25 | "babel-loader": "^6.2.1", 26 | "babel-preset-es2015": "^6.3.13", 27 | "babel-preset-react": "^6.3.13", 28 | "babel-preset-react-hmre": "^1.0.1", 29 | "eslint": "^1.10.3", 30 | "express": "^4.13.4", 31 | "node-libs-browser": "^0.5.3", 32 | "react-transform-catch-errors": "^1.0.1", 33 | "redbox-react": "^1.2.0", 34 | "webpack": "^1.12.11", 35 | "webpack-dev-server": "^1.14.1" 36 | }, 37 | "scripts": { 38 | "start": "node server.js" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/server.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var express = require('express'); 3 | var webpack = require('webpack'); 4 | var config = require('./webpack.config'); 5 | 6 | var app = express(); 7 | var compiler = webpack(config); 8 | 9 | app.use(require('webpack-dev-middleware')(compiler, { 10 | noInfo: true, 11 | publicPath: config.output.publicPath, 12 | })); 13 | 14 | app.use(require('webpack-hot-middleware')(compiler)); 15 | 16 | app.get('*', function(req, res) { 17 | res.sendFile(path.join(__dirname, 'index.html')); 18 | }); 19 | 20 | app.listen(3000, 'localhost', function(err) { 21 | if (err) { 22 | console.log(err); 23 | return; 24 | } 25 | 26 | console.log('Listening at http://localhost:3000'); 27 | }); 28 | -------------------------------------------------------------------------------- /app/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | var ExtractTextPlugin = require('extract-text-webpack-plugin'); 4 | 5 | module.exports = { 6 | devtool: 'eval', 7 | entry: [ 8 | 'webpack-hot-middleware/client', 9 | './index', 10 | ], 11 | output: { 12 | path: path.join(__dirname, 'dist'), 13 | filename: 'bundle.js', 14 | publicPath: '/static/', 15 | }, 16 | plugins: [ 17 | new ExtractTextPlugin('style.css', { allChunks: true }), 18 | new webpack.HotModuleReplacementPlugin(), 19 | new webpack.NoErrorsPlugin(), 20 | ], 21 | resolve: { 22 | alias: { 23 | 'ui-lib': path.join(__dirname, '..', 'ui-lib'), 24 | react: path.join(__dirname, 'node_modules', 'react'), 25 | 'react-dom': path.join(__dirname, 'node_modules', 'react-dom'), 26 | }, 27 | extensions: ['', '.js'], 28 | }, 29 | module: { 30 | loaders: [ 31 | { 32 | test: /\.js$/, 33 | loaders: ['babel'], 34 | exclude: /node_modules/, 35 | include: __dirname, 36 | }, { 37 | test: /\.js$/, 38 | loaders: ['babel'], 39 | include: path.join(__dirname, '..', 'ui-lib'), 40 | }, { 41 | test: /\.css/, 42 | loader: ExtractTextPlugin.extract('style', 'css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]'), 43 | include: __dirname, 44 | }, 45 | ], 46 | }, 47 | }; 48 | -------------------------------------------------------------------------------- /global-theming.md: -------------------------------------------------------------------------------- 1 | #### Module export 2 | 3 | https://github.com/nikgraf/future-react-ui/tree/master/ui-lib 4 | 5 | In this version the defaultTheme is exported through a named module export. On line 9, 10, 11 you can see how the default theme is patched with custom classes. (https://github.com/nikgraf/future-react-ui/blob/master/app/index.js#L8) Since this is not so hand it might be useful to have utility function for each library to apply a theme. 6 | 7 | #### Static property 8 | 9 | https://github.com/nikgraf/future-react-ui/blob/master/ui-lib/StaticProperty/Hint.js 10 | 11 | In this version the defaultTheme is attached to the component itself as static property. Compared to the 'Module export' this is a bit more flexible as you can overwrite the whole `theme` object in one go. See line 13-20 for usage. (https://github.com/nikgraf/future-react-ui/blob/master/app/index.js#L13) 12 | 13 | #### Theme Component leveraging Context 14 | 15 | https://github.com/nikgraf/future-react-ui/blob/master/ui-lib/Context/Hint.js 16 | 17 | In this version we leverage context to build a `` component that takes a theme as property and passes it down to all child components via React's context. A theme is still a simple JS object as can be seen on line 25-30. (https://github.com/nikgraf/future-react-ui/blob/master/app/index.js#L22). On one hand this approach is powerful, because you can apply different themes various nesting levels in the render tree. 18 | 19 | ``` 20 | 21 | 22 | 23 | 24 | Basic open hint without styling. 25 | 26 | ``` 27 | 28 | There is one obvious concern with this approach. There could be name-clashing between libraries that use the same key in the `theme` object. This could be solved by following a namespace convention like prefixing the keys with the npm package name. 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ui-lib-future", 3 | "version": "0.0.0", 4 | "description": "", 5 | "author": { 6 | "name": "Nik Graf", 7 | "email": "nik@nikgraf.com", 8 | "url": "https://github.com/nikgraf" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "TODO" 13 | }, 14 | "main": "lib/index.js", 15 | "keywords": [ 16 | "react" 17 | ], 18 | "peerDependencies": { 19 | "react": ">=0.14.0", 20 | "react-dom": ">=0.14.0" 21 | }, 22 | "scripts": { 23 | "prepublish": "npm run build", 24 | "lint": "npm run lint:eslint && npm run lint:jscs", 25 | "lint:eslint": "eslint ./", 26 | "lint:jscs": "jscs ./" 27 | }, 28 | "devDependencies": { 29 | "babel": "^6.3.26", 30 | "babel-cli": "^6.4.5", 31 | "babel-core": "^6.4.5", 32 | "babel-eslint": "^5.0.0-beta6", 33 | "babel-jest": "^6.0.1", 34 | "babel-loader": "^6.2.1", 35 | "babel-plugin-react-transform": "^2.0.0", 36 | "babel-preset-es2015": "^6.3.13", 37 | "babel-preset-react": "^6.3.13", 38 | "babel-preset-react-hmre": "^1.0.1", 39 | "eslint": "^1.10.3", 40 | "eslint-config-airbnb": "^3.1.0", 41 | "eslint-plugin-react": "^3.15.0", 42 | "jest-cli": "^0.8.2", 43 | "jscs": "^2.8.0", 44 | "react-transform-catch-errors": "^1.0.1", 45 | "react-transform-hmr": "^1.0.1", 46 | "redbox-react": "^1.2.0", 47 | "webpack": "^1.12.11", 48 | "webpack-dev-middleware": "^1.5.1", 49 | "webpack-dev-server": "^1.14.1", 50 | "webpack-hot-middleware": "^2.6.0" 51 | }, 52 | "license": "MIT", 53 | "dependencies": { 54 | "babel-preset-stage-0": "^6.3.13", 55 | "immutable": "^3.7.6", 56 | "react": "^0.14.6", 57 | "react-dom": "^0.14.6" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /ui-lib/Context/Hint.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Hint = ({ children, isOpen = false, theme }, context) => { 4 | const currentTheme = theme ? theme : context.theme.hint; 5 | return ( 6 |
7 |
?
8 |
9 | {children} 10 |
11 |
12 | ); 13 | }; 14 | 15 | Hint.contextTypes = { theme: React.PropTypes.object }; 16 | 17 | export default Hint; 18 | -------------------------------------------------------------------------------- /ui-lib/Context/Theme.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class Theme extends React.Component { 4 | 5 | static childContextTypes = { 6 | theme: React.PropTypes.object, 7 | }; 8 | 9 | getChildContext() { 10 | return { 11 | theme: this.props.theme, 12 | }; 13 | } 14 | 15 | render() { 16 | return
{ this.props.children }
; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ui-lib/Factory/belle/Hint.js: -------------------------------------------------------------------------------- 1 | import Hint from '../ui-core/Hint'; 2 | import createComponent from '../react-themeable/createComponent'; 3 | 4 | // An example of generated hashclasses by either JSS, CSSModules or any other 5 | // CSS libraries which generates classes. 6 | const belleTheme = { 7 | base: 'belle-hint-WQE73V', 8 | questionMark: 'belle-hint-FD7ASD', 9 | visibleContent: 'belle-hint-KASD34', 10 | hiddenContent: 'belle-hint-456BFD', 11 | }; 12 | 13 | export default createComponent(Hint, belleTheme); 14 | -------------------------------------------------------------------------------- /ui-lib/Factory/elemental/Hint.js: -------------------------------------------------------------------------------- 1 | import Hint from '../ui-core/Hint'; 2 | import createComponent from '../react-themeable/createComponent'; 3 | 4 | // An example of making use of Elemental's global css classes. 5 | const elementalTheme = { 6 | base: 'elemental-hint-wrapper', 7 | questionMark: 'elemental-hint-questionmark', 8 | visibleContent: 'elemental-hint-content', 9 | hiddenContent: 'elemental-hint-hidden-content', 10 | }; 11 | 12 | export default createComponent(Hint, elementalTheme); 13 | -------------------------------------------------------------------------------- /ui-lib/Factory/react-themeable/createComponent.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | /** 4 | * Returns a the provided component as themed component. 5 | * 6 | * Note: defaultProps could be useful for default special behavioural in 7 | * different ui libraries. 8 | */ 9 | export default (Component, theme, defaultProps) => (props) => { 10 | return ; 11 | }; 12 | -------------------------------------------------------------------------------- /ui-lib/Factory/ui-core/Hint.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | // This file would be an example of an unstyled component which can be used if 4 | // directly provided with a theme as an alternative to compose your custom UI kit 5 | // with react-themeable's createComponent. 6 | export default ({ children, isOpen = false, theme = {} }) => { 7 | return ( 8 |
9 |
?
10 |
11 | {children} 12 |
13 |
14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /ui-lib/ModuleExport/Hint.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export const defaultTheme = { 4 | base: undefined, 5 | questionMark: undefined, 6 | visibleContent: undefined, 7 | hiddenContent: undefined, 8 | }; 9 | 10 | const Hint = ({ children, isOpen = false, theme = defaultTheme }) => { // eslint-disable-line no-shadow 11 | return ( 12 |
13 |
?
14 |
15 | {children} 16 |
17 |
18 | ); 19 | }; 20 | 21 | export default Hint; 22 | -------------------------------------------------------------------------------- /ui-lib/StaticProperty/Hint.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Hint = ({ children, isOpen = false, theme = Hint.theme }) => { 4 | return ( 5 |
6 |
?
7 |
8 | {children} 9 |
10 |
11 | ); 12 | }; 13 | 14 | Hint.theme = { 15 | base: undefined, 16 | questionMark: undefined, 17 | visibleContent: undefined, 18 | hiddenContent: undefined, 19 | }; 20 | 21 | /* Alternative class based implementation */ 22 | 23 | // class Hint extends React.Component { 24 | // 25 | // static theme = { 26 | // base: undefined, 27 | // questionMark: undefined, 28 | // visibleContent: undefined, 29 | // hiddenContent: undefined, 30 | // }; 31 | // 32 | // render() { 33 | // const {children, isOpen = false, theme = Hint.theme} = this.props; 34 | // return ( 35 | //
36 | //
?
37 | //
38 | // {this.props.children} 39 | //
40 | //
41 | // ); 42 | // } 43 | // }; 44 | 45 | export default Hint; 46 | --------------------------------------------------------------------------------