├── .babelrc ├── .eslintrc ├── .gitignore ├── .npmignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── gulpfile.js ├── package.json ├── src ├── button │ ├── README.md │ └── index.jsx ├── card │ ├── README.md │ ├── actions │ │ ├── README.md │ │ └── index.jsx │ ├── index.jsx │ ├── media │ │ ├── README.md │ │ └── index.jsx │ ├── menu │ │ ├── README.md │ │ └── index.jsx │ ├── subtitle-text │ │ ├── README.md │ │ └── index.jsx │ ├── supporting-text │ │ ├── README.md │ │ └── index.jsx │ ├── title-text │ │ ├── README.md │ │ └── index.jsx │ └── title │ │ ├── README.md │ │ └── index.jsx ├── examples │ ├── index.html │ └── index.js ├── index.js └── lib │ ├── index.js │ ├── make-class-name.js │ ├── mdl-hook.jsx │ └── prepare-props.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "stage": 0 3 | } 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "env": { 4 | "browser": true 5 | }, 6 | "plugins": [ 7 | "react" 8 | ], 9 | "rules": { 10 | "strict": 0, 11 | "quotes": [2, "single", "avoid-escape"], 12 | "curly": 0, 13 | "no-underscore-dangle": 0, 14 | "no-use-before-define": 0, 15 | 16 | "react/display-name": 1, 17 | "react/jsx-boolean-value": 1, 18 | "react/jsx-no-undef": 1, 19 | "react/jsx-quotes": 1, 20 | "react/jsx-sort-prop-types": 0, 21 | "react/jsx-sort-props": 0, 22 | "react/jsx-uses-react": 1, 23 | "react/jsx-uses-vars": 1, 24 | "react/no-danger": 1, 25 | "react/no-did-mount-set-state": 1, 26 | "react/no-did-update-set-state": 1, 27 | "react/no-multi-comp": 1, 28 | "react/no-unknown-property": 1, 29 | "react/prop-types": 1, 30 | "react/react-in-jsx-scope": 1, 31 | "react/require-extension": 1, 32 | "react/self-closing-comp": 1, 33 | "react/sort-comp": 1, 34 | "react/wrap-multilines": 1 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /button 3 | /card 4 | /examples 5 | /index.js 6 | /lib 7 | node_modules 8 | npm-debug.log 9 | todo* 10 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | gulp* 3 | todo* 4 | examples 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v0.2.1 4 | * Adds `rippleEffect` prop to `Button` 5 | * Fixes `miniFab` and `display="miniFab"` props on `Button` 6 | 7 | ## v0.2.0 8 | * Adds `Card` Components 9 | 10 | ## v0.1.7 11 | * Import Components from project root like `import Button from 'material-design-react/button` 12 | 13 | ## v0.1.6 14 | 15 | * Adds Button readme 16 | * Updates readme 17 | * Adds license file 18 | 19 | ## v0.1.5 20 | 21 | * restructure 22 | 23 | ## v0.1.2 24 | 25 | * Makes npm package usable 26 | 27 | ## v0.1.0 28 | 29 | * Initial structure 30 | * Working `Button` component 31 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Welcome to the contributing guide for Material Design React! 2 | 3 | This file is a work in progress, your are welcome to contribute towards bringing this guide to completion. 4 | 5 | ## Most wanted 6 | 7 | 1. __Implement missing Components. [Read the issue](https://github.com/nikvm/material-design-react/issues/4) and [read the guide](https://github.com/nikvm/material-design-react/wiki/Component-How-To)__ 8 | 2. Improve `MDLHook` decorator. [Read the issue](https://github.com/nikvm/material-design-react/issues/10). 9 | 3. Write tests. [Read the issue](https://github.com/nikvm/material-design-react/issues/11). 10 | 11 | ## Contributing 12 | 13 | 1. Figure out what bugs you 14 | 2. Open an issue (or add your comment) 15 | 3. State you want to work on a particular problem. 16 | 3. Start [developing](#Developoing). 17 | 18 | *Oh, and use [emoticons](http://www.emoji-cheat-sheet.com/) to your :heart: wishes :wink:* 19 | 20 | ## Developing 21 | 22 | 1. Fork the project. 23 | 2. Install dependencies via `npm install`. 24 | 3. Start a server for `src/examples` via `gulp serve`. 25 | 4. Write code and add `examples/`. 26 | 4. Build the project via `gulp`. 27 | 5. Make sure your code is lint-error free. 28 | 6. Make sure the project installs via `npm install -g .` 29 | 5. Open a pull request. 30 | 31 | ## Style guide 32 | 33 | In lieu of a formal styleguide, take care to maintain the existing coding style. Lint your code using gulp with eslint (you may suggest `.eslintrc` changes). 34 | 35 | Also we use Babel configured with `stage: 0`, meaning you can use all the (maybe) coming goodness. 36 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 The contributors listed at https://github.com/nikvm/material-design-react/graphs/contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [DEPRECATED] Material Design React (MDR) 2 | 3 | :octocat: repository preserved for historical reasons :octocat: 4 | 5 | *Pragmatic* [React](https://github.com/facebook/react) wrapper for [Material Design Lite](https://github.com/google/material-design-lite) (MDL) components. 6 | 7 | 8 | ## Contents 9 | 10 | - [Introduction](#introduction) 11 | - [Getting Started](#getting-started) 12 | - [Contributing](#contributing) 13 | - [Components](#components) 14 | - [Histroy](#history) 15 | - [Credits](#credits) 16 | - [License](#license) 17 | 18 | 19 | ## Introduction 20 | 21 | *Pragmatic* – because if you know how to use MDL you already know how to use MDR. 22 | 23 | Most MDL BEM **blocks and elements translate to MDR Components** and **modifiers translate to boolean properties**. In addition Components may have added some extra sugar. 24 | 25 | ### An Example 26 | 27 | Given MDL markup: 28 | 29 | ```html 30 | 31 | ``` 32 | 33 | becomes: 34 | 35 | ```html 36 | 37 | ``` 38 | 39 | or – considering that 40 | *fab*, *miniFab*, *icon* and *raised* are mutually exclusive – we can use the display property: 41 | 42 | ```html 43 | 44 | ``` 45 | 46 | 47 | ## Getting Started 48 | 49 | ### Installation 50 | 51 | npm: 52 | ```bash 53 | npm install --save material-design-react 54 | ``` 55 | 56 | *Please file an issue if you need additional means of installation.* 57 | 58 | 59 | ### Usage 60 | Include the Material Design Lite CSS and JavaScript files in each HTML page in your project. 61 | More info: http://www.getmdl.io/started/index.html#download 62 | 63 | ```html 64 | 65 | 66 | 67 | ``` 68 | 69 | In your project's JS files import the components you need. 70 | 71 | ```javascript 72 | /* app.jsx */ 73 | import React from 'react'; 74 | import { Button } from 'material-design-react'; 75 | // or 76 | import Button from 'material-design-react/button'; 77 | // or 78 | var MDR = require('material-design-react'); 79 | var Button = MDR.Button; 80 | 81 | let coloredButton = ; 82 | ``` 83 | 84 | 85 | ## Contributing 86 | 87 | We welcome any contribution. 88 | Please get started by reading [CONTRIBUTING.md](CONTRIBUTING.md) 89 | 90 | 91 | ## History 92 | 93 | Have a look at the [changelog](CHANGELOG.md). 94 | 95 | 96 | ## Components 97 | 98 | *Links point to a component's readme.* 99 | 100 | - [x] [Button](src/button/README.md) 101 | - [x] [Card](src/card/README.md) 102 | - [x] [CardTitle](src/card/title/README.md) 103 | - [x] [CardTitleText](src/card/title-text/README.md ) 104 | - [x] [CardSubtitleText](src/card/subtitle-text/README.md) 105 | - [x] [CardMedia](src/card/media/README.md) 106 | - [x] [CardSupportingText](src/card/supporting-text/README.md) 107 | - [x] [CardActions](src/card/actions/README.md) 108 | - [x] [CardMenu](src/card/menu/README.md) 109 | - ...*[Contribute!](https://github.com/nikvm/material-design-react/issues/4)* 110 | 111 | 112 | ## Credits 113 | 114 | - [Contributors](https://github.com/nikvm/material-design-react/graphs/contributors) for contributing 115 | - [Google](https://github.com/google) for [Material Design Lite](https://github.com/google/material-design-lite) 116 | - [Facebook](https://github.com/facebook) for [React](https://github.com/facebook/react) 117 | - [Yan Foto](https://github.com/yan-foto) for his article [React Components with Material Design Lite](http://quaintous.com/2015/07/09/react-components-with-mdl/) 118 | - [Zeno Rocha](https://github.com/zenorocha) for his [README template](https://gist.github.com/zenorocha/4526327) 119 | - NPM module authors for [this project's dependencies](package.json) 120 | 121 | *Get in contact if you think you belong here.* 122 | 123 | ## License 124 | 125 | This project is licensed under the terms of the [MIT](LICENSE.md) license. 126 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var gutil = require('gulp-util') 3 | var babel = require('gulp-babel'); 4 | var del = require('del'); 5 | var fs = require('fs'); 6 | var eslint = require('gulp-eslint'); 7 | var webpack = require('webpack'); 8 | var webpackConfig = require('./webpack.config.js'); 9 | var WebpackDevServer = require("webpack-dev-server"); 10 | var infoColor = gutil.colors.blue; 11 | 12 | // DISTRIBUTION 13 | 14 | gulp.task('default', ['build']); 15 | 16 | // todo update .gitignore 17 | gulp.task('build', ['update-gitignore'], function() { 18 | return gulp.src('src/**/*.js?(x)') 19 | .pipe(eslint()) 20 | .pipe(eslint.format()) 21 | .pipe(eslint.failAfterError()) 22 | .pipe(babel()) 23 | .pipe(gulp.dest('./')); 24 | }); 25 | 26 | // Searches src/ for files 27 | // that are not ignored when built into project root 28 | // and adds them to .gitignore 29 | gulp.task('update-gitignore', function(cb) { 30 | var ignored = fs.readFileSync('./.gitignore') 31 | .toString() 32 | .split("\n") 33 | .filter(function noEmptyString(string) { 34 | return string.length > 0; 35 | }); 36 | var shouldIgnore = fs.readdirSync('./src') 37 | .map(function prefixSlash(file) { 38 | return '/' + file; 39 | }) 40 | .filter(function notIgnoredYet(file) { 41 | return ignored.indexOf(file) === -1; 42 | }); 43 | var willIgnore = ignored 44 | .concat(shouldIgnore) 45 | // keep it clean? 46 | .sort() 47 | // empty string adds new line at end of file 48 | .concat(''); 49 | 50 | gutil.log('Adding files:', infoColor(shouldIgnore.join(', '))); 51 | 52 | fs.writeFileSync('./.gitignore', willIgnore.join('\n')) 53 | 54 | cb(); 55 | }) 56 | 57 | 58 | // DEVELOPMENT 59 | 60 | gulp.task('serve', ['prep-examples'], function(cb) { 61 | new WebpackDevServer(webpack(webpackConfig), { 62 | publicPath: '/', 63 | contentBase: './examples', 64 | info: false, 65 | stats: { 66 | chunks: false, 67 | colors: true 68 | }, 69 | }).listen(8080, "localhost", function(err) { 70 | if(err) throw new gutil.PluginError("webpack-dev-server", err); 71 | gutil.log("[webpack-dev-server]", "http://localhost:8080/webpack-dev-server/index.html"); 72 | }); 73 | }); 74 | 75 | gulp.task("webpack", ['prep-examples'], function(cb) { 76 | webpack(webpackConfig).run(function(err, stats) { 77 | if(err) throw new gutil.PluginError("webpack:build-dev", err); 78 | gutil.log("[webpack:build-dev]", stats.toString({ 79 | colors: true, 80 | chunks: false 81 | })); 82 | cb(); 83 | }); 84 | }); 85 | 86 | gulp.task('prep-examples', ['clean-examples'], function(cb) { 87 | // move index 88 | return gulp.src('src/examples/index.html') 89 | .pipe(gulp.dest('examples/')) 90 | }); 91 | 92 | gulp.task('clean-examples', function(cb) { 93 | del(['./examples'], cb); 94 | }); 95 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "material-design-react", 3 | "version": "0.2.1", 4 | "description": "An implementation of Material Design Lite in React", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/nikvm/material-design-react.git" 12 | }, 13 | "keywords": [ 14 | "material", 15 | "design", 16 | "lite", 17 | "material-design-lite", 18 | "mdl", 19 | "react", 20 | "components" 21 | ], 22 | "author": "nikvm (https://nikvm.me)", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/nikvm/material-design-react/issues" 26 | }, 27 | "homepage": "https://github.com/nikvm/material-design-react#readme", 28 | "dependencies": { 29 | "omit": "^1.0.1", 30 | "react": "^0.13.3" 31 | }, 32 | "devDependencies": { 33 | "babel": "^5.6.14", 34 | "babel-core": "^5.6.17", 35 | "babel-eslint": "^3.1.23", 36 | "babel-loader": "^5.3.2", 37 | "del": "^1.2.0", 38 | "eslint": "^0.24.1", 39 | "eslint-plugin-react": "^2.7.0", 40 | "gulp": "^3.9.0", 41 | "gulp-babel": "^5.1.0", 42 | "gulp-eslint": "^0.15.0", 43 | "gulp-util": "^3.0.6", 44 | "webpack": "^1.10.1", 45 | "webpack-dev-server": "^1.10.1" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/button/README.md: -------------------------------------------------------------------------------- 1 | # Button 2 | 3 | http://www.getmdl.io/components/index.html#buttons-section 4 | 5 | 6 | ## Usage 7 | 8 | ```javascript 9 | // import { Button } from 'material-design-react'; 10 | import Button from 'material-design-react/button'; 11 | 12 | let myButton = ; 13 | ``` 14 | 15 | ## Properties 16 | Property | Type | Default | Effect | Remarks 17 | -------- | ---- | ------- | ------ | ------- 18 | rippleEffect | bool | undefined | Add ripple effect | JS effect 19 | ripple | bool | undefined | Add ripple effect | Alias for `rippleEffect` 20 | raised | bool | undefined | Add shadow | Mutually exclusive with `fab`, `miniFab`, `icon` 21 | fab | bool | undefined | Make floating action button | Mutually exclusive with `raised`, `miniFab`, `icon` 22 | miniFab | bool | undefined | Make mini floating action button | Mutually exclusive with `raised`, `fab`, `icon`. MDL needs you to also apply `fab` class, we do this implicitly 23 | icon | bool | undefined | Make icon button | Mutually exclusive with `raised`, `fab`, `miniFab` 24 | display | one of: `raised`, `fab`, `miniFab`, `icon` | undefined | *See above* | Mutually exclusive with `raised`, `fab`, `miniFab`, `icon` 25 | colored | bool | undefined | Add background color | Mutually exclusive with `accent` 26 | accent | bool | undefined | Add accent background color | Mutually exclusive with `colored` 27 | disabled | bool | undefined | Disable button | Adds `disabled` prop to ` 29 | 30 | 31 | 32 | 33 | 34 | 35 | ); 36 | ``` 37 | 38 | You may also use a shorthand with properties. 39 | 40 | ```javascript 41 | let myCard = ( 42 | Act on it., ]} 49 | actionsBorder /> 50 | ); 51 | ``` 52 | 53 | 54 | ## Properties 55 | 56 | Property | Type | Default | Effect | Remarks 57 | -------- | -----| ------- | ------ | ------- 58 | shadow | one of: `2`, `3`, `4`, `6`, `8`,`16` | undefined | Assigns shadow with variable depths | Depths 5 and 7 don't exist 59 | title | node | undefined | Adds title text | - 60 | titleLevel | one of: `1`, `2`, `3`, `4`, `5`, `6` | `1` | Sets title's heading level | Sets html elements `

` through `

` 61 | titleBorder | bool| undefined | Adds border to title container | - 62 | subtitle | node | undefined | Adds subtitle | - 63 | supporting | node | undefined | Adds supporting text | - 64 | media | node | undefined | Adds media content | - 65 | actions | node | undefined | Adds actions | - 66 | actionsBorder | bool | undefined | Adds border to actions container | - 67 | menu | node | undefined | Adds menu | Usually a mdl/mdr icon button (plus menu) 68 | 69 | ## Children 70 | 71 | * [Title](./title/README.md) 72 | * [TitleText](./title-text/README.md) 73 | * [SubtitleText](./subtitle-text/README.md) 74 | * [SupportingText](./supporting-text/README.md) 75 | * [Media](./media/README.md) 76 | * [Actions](./actions/README.md) 77 | * [Menu](./menu/README.md) 78 | 79 | 80 | ## Notes 81 | 82 | When using `Card` with props the order in which children are rendered is as follows: 83 | 84 | 1. `title` 85 | 2. `subtitle` 86 | 3. `supporting` 87 | 4. `media` 88 | 5. `children` (prop or actual) 89 | 6. `actions` 90 | 7. `menu` 91 | 92 | If your use case seeks a different order, use `Card` with children instead or mix as needed (as `children` will be rendered in any case). 93 | -------------------------------------------------------------------------------- /src/card/actions/README.md: -------------------------------------------------------------------------------- 1 | # CardActions 2 | 3 | http://www.getmdl.io/components/index.html#cards-section 4 | 5 | 6 | ## Usage 7 | 8 | ```javascript 9 | import Card from 'material-design-react/card'; 10 | 11 | let myCard = ( 12 | 13 | {/* ... */} 14 | 15 | Action! 16 | 17 | {/* ... */} 18 | 19 | ); 20 | ``` 21 | 22 | You may also import and use `CardActions` directly. 23 | 24 | ```javascript 25 | // import { CardActions } from 'material-design-react'; 26 | import CardActions from 'material-design-react/card/actions'; 27 | 28 | let myCardActions = ( 29 | 30 | Button? 31 | 32 | ); 33 | ``` 34 | 35 | 36 | ## Properties 37 | 38 | Property | Type | Default | Effect | Remarks 39 | -------- | -----| ------- | ------ | ------- 40 | border | bool | undefined | Adds border to section | - 41 | 42 | 43 | ## Parent 44 | 45 | [Card](../README.md) 46 | 47 | 48 | ## Notes 49 | *none* 50 | -------------------------------------------------------------------------------- /src/card/actions/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import mdlHook from '../../lib/mdl-hook'; 3 | 4 | @mdlHook({ 5 | displayName: 'MDR:CardActions', 6 | blockClassName: 'mdl-card__actions', 7 | modifiers: [ 8 | { 9 | prop: 'border', 10 | className: 'mdl-card--border', 11 | type: React.PropTypes.bool 12 | } 13 | ] 14 | }) 15 | class CardActions extends React.Component { 16 | 17 | render() { 18 | return
; 19 | } 20 | } 21 | 22 | export default CardActions; 23 | -------------------------------------------------------------------------------- /src/card/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import mdlHook from '../lib/mdl-hook'; 3 | import CardMenu from './menu'; 4 | import CardMedia from './media'; 5 | import CardTitle from './title'; 6 | import CardActions from './actions'; 7 | import CardTitleText from './title-text'; 8 | import CardSubtitleText from './subtitle-text'; 9 | import CardSupportingText from './supporting-text'; 10 | 11 | @mdlHook({ 12 | displayName: 'MDR:Card', 13 | blockClassName: 'mdl-card mdl-js-card', 14 | modifiers: [ 15 | { 16 | prop: 'shadow', 17 | type: React.PropTypes.oneOf([2, 3, 4, 6, 8, 16]), 18 | classNameFn: (val) => `mdl-shadow--${val}dp` 19 | } 20 | ] 21 | }) 22 | class Card extends React.Component { 23 | static propTypes = { 24 | title: React.PropTypes.node, 25 | titleLevel: React.PropTypes.oneOf([1, 2, 3, 4, 5, 6]), 26 | titleBorder: React.PropTypes.bool, 27 | subtitle: React.PropTypes.node, 28 | supporting: React.PropTypes.node, 29 | media: React.PropTypes.node, 30 | actions: React.PropTypes.node, 31 | actionsBorder: React.PropTypes.bool, 32 | menu: React.PropTypes.node, 33 | children: React.PropTypes.node 34 | } 35 | 36 | static defaultProps = { 37 | titleLevel: 1 38 | } 39 | 40 | render() { 41 | let { 42 | title, 43 | titleLevel, 44 | titleBorder, 45 | subtitle, 46 | supporting, 47 | media, 48 | actions, 49 | actionsBorder, 50 | menu, 51 | children, 52 | ...otherProps 53 | } = this.props; 54 | 55 | let renderedTitle = renderTitle({title, titleLevel, titleBorder, subtitle}); 56 | let renderedSupporting = renderSupporting({supporting}); 57 | let renderedMedia = renderMedia({media}); 58 | let renderedActions = renderActions({actions, actionsBorder}); 59 | let renderedMenu = renderMenu({menu}); 60 | 61 | return ( 62 |
63 | {renderedTitle} 64 | {renderedSupporting} 65 | {renderedMedia} 66 | {children} 67 | {renderedActions} 68 | {renderedMenu} 69 |
70 | ); 71 | } 72 | } 73 | 74 | function renderTitle(props) { 75 | let Subtitle = props.title && props.subtitle 76 | ? 77 | : null; 78 | if (props.title) return ( 79 | 80 | 81 | {Subtitle} 82 | 83 | ); 84 | return null; 85 | } 86 | 87 | function renderSupporting(props) { 88 | if (props.supporting) return ( 89 | 90 | ); 91 | return null; 92 | } 93 | 94 | function renderMedia(props) { 95 | if (props.media) return ( 96 | 97 | ); 98 | return null; 99 | } 100 | 101 | function renderActions(props) { 102 | if (props.actions) return ( 103 | 104 | ); 105 | return null; 106 | } 107 | 108 | function renderMenu(props) { 109 | if (props.menu) return ( 110 | 111 | ); 112 | return null; 113 | } 114 | 115 | Card.Title = CardTitle; 116 | Card.TitleText = CardTitleText; 117 | Card.SubtitleText = CardSubtitleText; 118 | Card.SupportingText = CardSupportingText; 119 | Card.Media = CardMedia; 120 | Card.Actions = CardActions; 121 | Card.Menu = CardMenu; 122 | 123 | export default Card; 124 | -------------------------------------------------------------------------------- /src/card/media/README.md: -------------------------------------------------------------------------------- 1 | # CardMedia 2 | 3 | http://www.getmdl.io/components/index.html#cards-section 4 | 5 | 6 | ## Usage 7 | 8 | ```javascript 9 | import Card from 'material-design-react/card'; 10 | 11 | let myCard = ( 12 | 13 | {/* ... */} 14 | 15 | {/* ... */} 16 | 17 | {/* ... */} 18 | 19 | ); 20 | ``` 21 | 22 | You may also import and use `CardMedia` directly. 23 | 24 | ```javascript 25 | // import { CardMedia } from 'material-design-react'; 26 | import CardMedia from 'material-design-react/card/media'; 27 | 28 | let myCardMedia = ( 29 | 30 | {/* ... */} 31 | 32 | ); 33 | ``` 34 | 35 | 36 | ## Properties 37 | 38 | *none* 39 | 40 | 41 | ## Parent 42 | 43 | [Card](../README.md) 44 | 45 | 46 | ## Notes 47 | *none* 48 | -------------------------------------------------------------------------------- /src/card/media/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import mdlHook from '../../lib/mdl-hook'; 3 | 4 | @mdlHook({ 5 | displayName: 'MDR:CardMedia', 6 | blockClassName: 'mdl-card__media' 7 | }) 8 | class CardMedia extends React.Component { 9 | 10 | render() { 11 | return
; 12 | } 13 | } 14 | 15 | export default CardMedia; 16 | -------------------------------------------------------------------------------- /src/card/menu/README.md: -------------------------------------------------------------------------------- 1 | # CardMenu 2 | 3 | http://www.getmdl.io/components/index.html#cards-section 4 | 5 | 6 | ## Usage 7 | 8 | ```javascript 9 | import Card from 'material-design-react/card'; 10 | 11 | let myCard = ( 12 | 13 | {/* ... */} 14 | 15 | {/* ... */} 16 | 17 | {/* ... */} 18 | 19 | ); 20 | ``` 21 | 22 | You may also import and use `CardMenu` directly. 23 | 24 | ```javascript 25 | // import { CardMenu } from 'material-design-react'; 26 | import CardMenu from 'material-design-react/card/menu'; 27 | 28 | let myCardMenu = ( 29 | 30 | {/* ... */} 31 | 32 | ); 33 | ``` 34 | 35 | 36 | ## Properties 37 | 38 | *none* 39 | 40 | 41 | ## Parent 42 | 43 | [Card](../README.md) 44 | 45 | 46 | ## Notes 47 | *none* 48 | -------------------------------------------------------------------------------- /src/card/menu/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import mdlHook from '../../lib/mdl-hook'; 3 | 4 | @mdlHook({ 5 | displayName: 'MDR:CardMenu', 6 | blockClassName: 'mdl-card__menu' 7 | }) 8 | class CardMenu extends React.Component { 9 | 10 | render() { 11 | return
; 12 | } 13 | } 14 | 15 | export default CardMenu; 16 | -------------------------------------------------------------------------------- /src/card/subtitle-text/README.md: -------------------------------------------------------------------------------- 1 | # CardSubtitleText 2 | 3 | http://www.getmdl.io/components/index.html#cards-section 4 | 5 | 6 | ## Usage 7 | 8 | ```javascript 9 | import Card from 'material-design-react/card'; 10 | 11 | let myCard = ( 12 | 13 | 14 | 15 | A Title 16 | 17 | 18 | 19 | A subtitle 20 | 21 | 22 | 23 | {/* ... */} 24 | 25 | ); 26 | ``` 27 | 28 | You may also import and use `CardSubtitleText` directly. 29 | 30 | ```javascript 31 | // import { CardSubtitleText } from 'material-design-react'; 32 | import CardSubtitleText from 'material-design-react/card/subtitle-text'; 33 | 34 | let myCardSubtitleText = ( 35 | 36 | {/* ... */} 37 | 38 | ) 39 | ); 40 | ``` 41 | 42 | 43 | ## Properties 44 | 45 | *none* 46 | 47 | 48 | ## Parent 49 | 50 | [Card](../README.md) 51 | 52 | 53 | ## Notes 54 | *none* 55 | -------------------------------------------------------------------------------- /src/card/subtitle-text/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import mdlHook from '../../lib/mdl-hook'; 3 | 4 | @mdlHook({ 5 | displayName: 'MDR:CardSubtitleText', 6 | blockClassName: 'mdl-card__subtitle-text' 7 | }) 8 | class CardSubtitleText extends React.Component { 9 | 10 | render() { 11 | return
; 12 | } 13 | } 14 | 15 | export default CardSubtitleText; 16 | -------------------------------------------------------------------------------- /src/card/supporting-text/README.md: -------------------------------------------------------------------------------- 1 | # CardSupportingText 2 | 3 | http://www.getmdl.io/components/index.html#cards-section 4 | 5 | 6 | ## Usage 7 | 8 | ```javascript 9 | import Card from 'material-design-react/card'; 10 | 11 | let myCard = ( 12 | 13 | {/* ... */} 14 | 15 | Some supporting text 16 | 17 | {/* ... */} 18 | 19 | ); 20 | ``` 21 | 22 | You may also import and use `CardSupportingText` directly. 23 | 24 | ```javascript 25 | // import { CardSupportingText } from 'material-design-react'; 26 | import CardSupportingText from 'material-design-react/card/subtitle-text'; 27 | 28 | let myCardSupportingText = ( 29 | 30 | {/* ... */} 31 | 32 | ) 33 | ); 34 | ``` 35 | 36 | 37 | ## Properties 38 | 39 | *none* 40 | 41 | 42 | ## Parent 43 | 44 | [Card](../README.md) 45 | 46 | 47 | ## Notes 48 | *none* 49 | -------------------------------------------------------------------------------- /src/card/supporting-text/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import mdlHook from '../../lib/mdl-hook'; 3 | 4 | @mdlHook({ 5 | displayName: 'MDR:CardSupportingText', 6 | blockClassName: 'mdl-card__supporting-text' 7 | }) 8 | class CardSupportingText extends React.Component { 9 | 10 | render() { 11 | return
; 12 | } 13 | } 14 | 15 | export default CardSupportingText; 16 | -------------------------------------------------------------------------------- /src/card/title-text/README.md: -------------------------------------------------------------------------------- 1 | # CardTitleText 2 | 3 | http://www.getmdl.io/components/index.html#cards-section 4 | 5 | 6 | ## Usage 7 | 8 | ```javascript 9 | import Card from 'material-design-react/card'; 10 | 11 | let myCard = ( 12 | 13 | 14 | 15 | A Card's Title 16 | 17 | 18 | {/* ... */} 19 | 20 | ); 21 | ``` 22 | 23 | You may also import and use `CardTitleText` directly. 24 | 25 | ```javascript 26 | // import { CardTitleText } from 'material-design-react'; 27 | import CardTitleText from 'material-design-react/card/title-text'; 28 | 29 | let myCardTitleText = ( 30 | 31 | A Card's Title 32 | 33 | ); 34 | ``` 35 | 36 | 37 | ## Properties 38 | 39 | Property | Type | Default | Effect | Remarks 40 | -------- | ---- | ------- | ------ | ------- 41 | level | one of: 1, 2, 3, 4, 5, 6 | 1 | Sets heading level | Defines DOM element `

` through `

` 42 | 43 | 44 | ## Parent 45 | 46 | [Card](../README.md) 47 | 48 | 49 | ## Notes 50 | *none* 51 | -------------------------------------------------------------------------------- /src/card/title-text/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import mdlHook from '../../lib/mdl-hook'; 3 | 4 | @mdlHook({ 5 | displayName: 'MDR:CardTitleText', 6 | blockClassName: 'mdl-card__title-text' 7 | }) 8 | class CardTitleText extends React.Component { 9 | static propTypes = { 10 | level: React.PropTypes.oneOf([1, 2, 3, 4, 5, 6]) 11 | } 12 | static defaultProps = { 13 | level: 1 14 | } 15 | 16 | render() { 17 | let { level, ...otherProps } = this.props; 18 | 19 | return React.DOM[`h${level}`](otherProps); 20 | } 21 | } 22 | 23 | export default CardTitleText; 24 | -------------------------------------------------------------------------------- /src/card/title/README.md: -------------------------------------------------------------------------------- 1 | # CardTitle 2 | 3 | http://www.getmdl.io/components/index.html#cards-section 4 | 5 | 6 | ## Usage 7 | 8 | ```javascript 9 | import Card from 'material-design-react/card'; 10 | 11 | let myCard = ( 12 | 13 | 14 | {/* ... */} 15 | 16 | {/* ... */} 17 | 18 | ); 19 | ``` 20 | 21 | You may also import and use `CardTitle` directly. 22 | 23 | ```javascript 24 | // import { CardTitle } from 'material-design-react'; 25 | import CardTitle from 'material-design-react/card/title'; 26 | 27 | let myCardTitle = ( 28 | 29 | {/* ... */} 30 | 31 | ); 32 | ``` 33 | 34 | 35 | ## Properties 36 | 37 | Property | Type | Default | Effect | Remarks 38 | -------- | -----| ------- | ------ | ------- 39 | border | bool | undefined | Adds border to section | - 40 | 41 | 42 | ## Parent 43 | 44 | [Card](../README.md) 45 | 46 | 47 | ## Notes 48 | *none* 49 | -------------------------------------------------------------------------------- /src/card/title/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import mdlHook from '../../lib/mdl-hook'; 3 | 4 | @mdlHook({ 5 | displayName: 'MDR:CardTitle', 6 | blockClassName: 'mdl-card__title', 7 | modifiers: [ 8 | { 9 | prop: 'border', 10 | className: 'mdl-card--border', 11 | type: React.PropTypes.bool 12 | } 13 | ] 14 | }) 15 | class CardTitle extends React.Component { 16 | 17 | render() { 18 | return
; 19 | } 20 | } 21 | 22 | export default CardTitle; 23 | -------------------------------------------------------------------------------- /src/examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | MDR Examples 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/examples/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Button, 4 | Card, 5 | CardTitle, 6 | CardTitleText, 7 | CardSubtitleText, 8 | CardSupportingText, 9 | CardMedia, 10 | CardMenu, 11 | CardActions 12 | } from '../index'; // material-design-react 13 | 14 | class Examples extends React.Component { 15 | render() { 16 | let children = React.Children.map(this.props.children, (child) => { 17 | return
{child}
; 18 | }); 19 | return ( 20 |
{children}
21 | ); 22 | } 23 | } 24 | 25 | class App extends React.Component { 26 | render() { 27 | return ( 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | Card.TitleText 43 | 44 | 45 | 46 | 47 | 48 | 49 | CardTitleText level 1 50 | 51 | 52 | Subtitle 53 | 54 | 55 | 56 | CardMedia 57 | 58 | 59 | A man once sat under a tree 60 | 61 | 62 | 63 | 64 | 65 | 68 | 69 | 70 |
71 | Some media
} 76 | supporting="supporting text" 77 | actions={[]} 78 | actionsBorder 79 | shadow="8" /> 80 | 81 | ); 82 | } 83 | } 84 | 85 | React.render(, document.getElementById('app')); 86 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import Button from './button'; 2 | import Card from './card'; 3 | import CardMenu from './card/menu'; 4 | import CardMedia from './card/media'; 5 | import CardTitle from './card/title'; 6 | import CardActions from './card/actions'; 7 | import CardTitleText from './card/title-text'; 8 | import CardSubtitleText from './card/subtitle-text'; 9 | import CardSupportingText from './card/supporting-text'; 10 | 11 | export default { 12 | Button, 13 | Card, 14 | CardTitle, 15 | CardTitleText, 16 | CardSubtitleText, 17 | CardSupportingText, 18 | CardMedia, 19 | CardActions, 20 | CardMenu 21 | }; 22 | -------------------------------------------------------------------------------- /src/lib/index.js: -------------------------------------------------------------------------------- 1 | import makeClassName from './make-class-name'; 2 | import prepareProps from './prepare-props'; 3 | import mdlHook from './mdl-hook'; 4 | 5 | export default { 6 | makeClassName, 7 | prepareProps, 8 | mdlHook 9 | }; 10 | -------------------------------------------------------------------------------- /src/lib/make-class-name.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Return className with mdl css classes and className from props 3 | * @param {Object} props props defined on Component 4 | * @param {Object} config config for className creation 5 | * @return {String} the final className 6 | */ 7 | export default function makeClassName(props, config) { 8 | let {blockClassName, modifierClassNameFns} = config; 9 | 10 | let propClassNameFn = (prop) => modifierClassNameFns[prop]; 11 | let propValue = (prop) => props[prop]; 12 | 13 | let prepareClassName = (prop) => { 14 | let classNameFn = propClassNameFn(prop); 15 | let value = propValue(prop); 16 | 17 | return classNameFn(value); 18 | }; 19 | 20 | let modifiersClassName = Object.keys(modifierClassNameFns) 21 | .filter(propValue) 22 | .map(prepareClassName) 23 | .join(' '); 24 | 25 | return `${blockClassName} ${modifiersClassName} ${props.className || ''}`; 26 | } 27 | -------------------------------------------------------------------------------- /src/lib/mdl-hook.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import prepareProps from './prepare-props'; 3 | 4 | /** 5 | * # mdlHook 6 | * 7 | * wraps `Target` in higher order Component which 8 | * turns provided `config` into MDL CSS classes and provides lifecycle methods 9 | * for upgrading/ downgrading a Component via 10 | * [mdlComponentHandler](https://github.com/google/material-design-lite/blob/master/src/mdlComponentHandler.js). 11 | * 12 | * ## `config` Properties 13 | * 14 | * The `config` param takes the following properties: 15 | * 1. `displayName`: React display name of higher order element 16 | * 2. `blockClassName`: The Block -- as in BEM -- MDL CSS class (inc. js hook) 17 | * 3. `modifiers`: An array of modifier objects configuring MDL modifier (BEM) CSS classes. 18 | * 19 | * ### `modifiers[i]` Properties 20 | * 21 | * A modifier object takes the following props: 22 | * 1. `prop`: Property name 23 | * 2. `className`: MDL CSS class (mutually exclusive with `classNameFn`, takes precedence) 24 | * 3. `classNameFn`: A function returning MDL CSS class string, takes prop value as argument. ((mutually exclusive with `className`) 25 | * 4. `type`: One of React's `PropType`s (or custom) 26 | * 5. `default`: Default value (optional) 27 | */ 28 | export default function mdlHook({displayName, blockClassName, modifiers = []}) { 29 | 30 | let propTypes = makePropTypes(modifiers); 31 | let defaultProps = makeDefaultProps(modifiers); 32 | let prepareTargetProps = (props) => prepareProps(props, { 33 | blockClassName, 34 | modifierClassNameFns: makeClassNameFns(modifiers) 35 | }); 36 | 37 | return function decorator(Target) { 38 | 39 | return class extends React.Component { 40 | static displayName = displayName; 41 | static propTypes = propTypes; 42 | static defaultProps = defaultProps; 43 | 44 | constructor(props) { 45 | super(props); 46 | 47 | this.state = { 48 | targetProps: prepareTargetProps(props) 49 | }; 50 | } 51 | 52 | componentWillReceiveProps(props) { 53 | this.setState({ 54 | targetProps: prepareTargetProps(props) 55 | }); 56 | } 57 | 58 | // credit: http://quaintous.com/2015/07/09/react-components-with-mdl/ 59 | componentDidUpdate() { 60 | if (window.componentHandler) { 61 | window.componentHandler.upgradeDom(); 62 | } 63 | } 64 | 65 | render() { 66 | return ; 67 | } 68 | }; 69 | }; 70 | } 71 | 72 | /** 73 | * Creates an object mapping prop names to (React style) prop types 74 | * @param {Array} modifiers List of modifier config objects 75 | * @return {Object} propTypes object 76 | */ 77 | function makePropTypes(modifiers) { 78 | return modifiers.reduce((acc, {prop, type}) => { 79 | acc[prop] = type; 80 | return acc; 81 | }, {}); 82 | } 83 | 84 | /** 85 | * Creates an object mapping prop names to default values 86 | * @param {Array} modifiers List of modifier config objects 87 | * @return {Object} defaultProps objects 88 | */ 89 | function makeDefaultProps(modifiers) { 90 | return modifiers.reduce((acc, cur) => { 91 | if (cur.hasOwnProperty('default')) { 92 | acc[cur.prop] = cur.default; 93 | } 94 | return acc; 95 | }, {}); 96 | } 97 | 98 | /** 99 | * Creates an object mapping prop names to functions returning MDL class name 100 | * @param {Array} modifiers List of modifier config objects 101 | * @return {Object} classNameFns map 102 | */ 103 | function makeClassNameFns(modifiers) { 104 | return modifiers.reduce((acc, {prop, className, classNameFn}) => { 105 | acc[prop] = className ? () => className : classNameFn; 106 | return acc; 107 | }, {}); 108 | } 109 | -------------------------------------------------------------------------------- /src/lib/prepare-props.js: -------------------------------------------------------------------------------- 1 | import makeClassName from './make-class-name'; 2 | import omit from 'omit'; 3 | 4 | export default function prepareProps(props, config) { 5 | let modKeys = Object.keys(config.modifierClassNameFns); 6 | let omitModKeys = omit(modKeys); 7 | 8 | return Object.assign( 9 | omitModKeys(props), 10 | {className: makeClassName(props, config)} 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file configures the examples application's webpack build 3 | */ 4 | var path = require('path'); 5 | var webpack = require('webpack'); 6 | 7 | module.exports = { 8 | entry: { 9 | bundle: './src/examples/index.js' 10 | }, 11 | 12 | output: { 13 | path: path.join(__dirname, 'examples'), 14 | filename: '[name].js', 15 | chunkFilename: '[chunkhash].js', 16 | sourceMapFilename: 'debug/[file].map', 17 | }, 18 | 19 | devtool: '#cheap-module-source-map', 20 | 21 | debug: true, 22 | 23 | module: { 24 | loaders: [ 25 | // JS(X) 26 | {test: /\.(jsx?(\?.*)?)$/, loaders: ['babel?stage=0'], exclude: /node_modules/}, 27 | ], 28 | }, 29 | 30 | resolve: { 31 | extensions: ['', '.js', '.jsx'] 32 | }, 33 | 34 | plugins: [ 35 | new webpack.NoErrorsPlugin() 36 | ], 37 | 38 | stats: { 39 | chunks: false 40 | } 41 | }; 42 | --------------------------------------------------------------------------------