├── .npmignore ├── src ├── MarkdownEditor │ ├── LinkDialog │ │ ├── index.js │ │ └── LinkDialog.js │ ├── index.js │ ├── ToolbarPanel │ │ ├── index.js │ │ ├── FlexWrapper.js │ │ ├── Button.js │ │ ├── ToolbarSection.js │ │ ├── ToolbarPanel.js │ │ ├── DropDown.js │ │ └── buttonsSchema.js │ ├── codemirrorOverride.css │ ├── MarkdownEditor.js │ └── formatting.js └── example │ └── index.js ├── .gitignore ├── test ├── .eslintrc ├── helpers │ └── setup-browser-env.js ├── MarkdownEditor.js └── formatting.js ├── .eslintrc ├── webpack-ava.config.js ├── .babelrc ├── example └── index.html ├── webpack-example.config.js ├── webpack-dev-server.config.js ├── LICENSE ├── webpack-prod.config.js ├── README.md └── package.json /.npmignore: -------------------------------------------------------------------------------- 1 | * 2 | !dist/**/* 3 | !README.md 4 | -------------------------------------------------------------------------------- /src/MarkdownEditor/LinkDialog/index.js: -------------------------------------------------------------------------------- 1 | import LinkDialog from './LinkDialog' 2 | 3 | export default LinkDialog 4 | -------------------------------------------------------------------------------- /src/MarkdownEditor/index.js: -------------------------------------------------------------------------------- 1 | import MarkdownEditor from './MarkdownEditor' 2 | 3 | export default MarkdownEditor 4 | -------------------------------------------------------------------------------- /src/MarkdownEditor/ToolbarPanel/index.js: -------------------------------------------------------------------------------- 1 | import ToolbarPanel from './ToolbarPanel' 2 | 3 | export default ToolbarPanel 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Dependency directory 6 | node_modules 7 | 8 | bundle 9 | dist 10 | -------------------------------------------------------------------------------- /test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "import/no-extraneous-dependencies": ["error", {"devDependencies": true}] 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true 4 | }, 5 | "extends": "airbnb", 6 | "rules": { 7 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], 8 | "comma-dangle": ["error", "never"], 9 | "semi" : [2, "never"], 10 | "import/no-unresolved": [0], 11 | "quotes": ["error", "single", { "allowTemplateLiterals": true }] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /webpack-ava.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | output: { 3 | libraryTarget: 'commonjs2' 4 | }, 5 | module: { 6 | debug: true, 7 | loaders: [ 8 | { 9 | test: /\.css$/, 10 | loaders: [ 11 | 'style-loader', 12 | 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]--[hash:base64:5]' 13 | ] 14 | } 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/MarkdownEditor/ToolbarPanel/FlexWrapper.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react' 2 | 3 | const FlexWrapper = ({ children }) => 4 |
5 | {children} 6 |
7 | 8 | export default FlexWrapper 9 | 10 | FlexWrapper.propTypes = { 11 | children: PropTypes.oneOfType([ 12 | PropTypes.element, 13 | PropTypes.arrayOf( 14 | PropTypes.element 15 | ) 16 | ]) 17 | } 18 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"], 3 | "plugins": [ 4 | "babel-plugin-transform-class-properties", 5 | "transform-object-rest-spread" 6 | ], 7 | "env": { 8 | "AVA": { 9 | "plugins": [ 10 | [ 11 | "babel-plugin-webpack-loaders", 12 | { 13 | "config": "${CONFIG}", 14 | "verbose": false, 15 | } 16 | ] 17 | ] 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/helpers/setup-browser-env.js: -------------------------------------------------------------------------------- 1 | import jsdom from 'jsdom' 2 | import noop from 'lodash/noop' 3 | import constant from 'lodash/constant' 4 | 5 | global.window = jsdom.jsdom().defaultView 6 | global.navigator = window.navigator 7 | window.document.createRange = constant( 8 | { 9 | setEnd: noop, 10 | setStart: noop, 11 | getBoundingClientRect: constant({}), 12 | getClientRects: constant({}) 13 | }) 14 | global.document = window.document 15 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Material-UI Markdown Editor 4 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/MarkdownEditor/ToolbarPanel/Button.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react' 2 | import FlatButton from 'material-ui/FlatButton' 3 | 4 | const Button = ({ onClick, style, icon, openDialog, isImageDialog }, { toggleDialog }) => ( 5 | 10 | ) 11 | 12 | Button.propTypes = { 13 | icon: PropTypes.element, 14 | onClick: PropTypes.func, 15 | isImageDialog: PropTypes.bool, 16 | style: PropTypes.object, //eslint-disable-line 17 | openDialog: PropTypes.bool 18 | } 19 | 20 | Button.contextTypes = { 21 | toggleDialog: PropTypes.func 22 | } 23 | 24 | export default Button 25 | -------------------------------------------------------------------------------- /webpack-example.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | const srcPath = path.join(__dirname, 'src', 'example') 4 | const buildPath = path.join(__dirname, 'example') 5 | const config = { 6 | entry: path.join(srcPath, 'index.js'), 7 | output: { 8 | path: buildPath, 9 | filename: 'bundle.js' 10 | }, 11 | module: { 12 | loaders: [ 13 | { 14 | test: /\.js$/, 15 | exclude: /(node_modules)/, 16 | loader: 'babel', 17 | query: { 18 | presets: ['react', 'es2015'], 19 | plugins: ['babel-plugin-transform-class-properties'] 20 | } 21 | }, 22 | { 23 | test: /\.css$/, 24 | loader: 'style-loader!css-loader' 25 | } 26 | ] 27 | } 28 | } 29 | 30 | module.exports = config 31 | -------------------------------------------------------------------------------- /src/MarkdownEditor/codemirrorOverride.css: -------------------------------------------------------------------------------- 1 | .CodeMirror{ 2 | font-family: Roboto, sans-serif; 3 | font-weight: 300; 4 | font-size:18px; 5 | line-height: 26px; 6 | } 7 | .CodeMirror-lines{ 8 | padding: 10px; 9 | } 10 | 11 | .CodeMirror-gutters{ 12 | height: 258px; 13 | color: #212121; 14 | background-color: #F5F5F5; 15 | } 16 | 17 | .CodeMirror-linenumber{ 18 | left: -15px !important; 19 | } 20 | .cm-s-default .cm-header {color: #2196F3;} 21 | .cm-s-default .cm-quote {color: #4CAF50;} 22 | 23 | .cm-s-default .cm-variable, 24 | .cm-s-default .cm-punctuation, 25 | .cm-s-default .cm-property, 26 | .cm-s-default .cm-operator {} 27 | .cm-s-default .cm-variable-2 {color: #03A9F4;} 28 | .cm-s-default .cm-variable-3 {color: #085;} 29 | .cm-s-default .cm-comment {color: #795548;} 30 | .cm-s-default .cm-string {color: #FF5722;} 31 | .cm-s-default .cm-link {color: #3F51B5;} 32 | -------------------------------------------------------------------------------- /src/MarkdownEditor/ToolbarPanel/ToolbarSection.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react' 2 | import { ToolbarSeparator } from 'material-ui/Toolbar' 3 | import Button from './Button' 4 | import DropDown from './DropDown' 5 | 6 | const ToolbarSection = ({ items }) => ( 7 |
8 | { 9 | items.map((item, key) => ( 10 | item.isDropDown 11 | ? 12 | :
17 | ) 18 | 19 | ToolbarSection.propTypes = { 20 | items: PropTypes.arrayOf( 21 | PropTypes.shape({ 22 | style: PropTypes.object, 23 | onClick: PropTypes.func, 24 | icon: PropTypes.element, 25 | getContext: PropTypes.bool 26 | }) 27 | ) 28 | } 29 | 30 | export default ToolbarSection 31 | -------------------------------------------------------------------------------- /src/MarkdownEditor/ToolbarPanel/ToolbarPanel.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react' 2 | import { Toolbar, ToolbarGroup, ToolbarTitle } from 'material-ui/Toolbar' 3 | import ToolbarSection from './ToolbarSection' 4 | import getButtonsSchema from './buttonsSchema' 5 | 6 | const ToolbarPanel = ({ cm, tokens, title }) => ( 7 | 8 | 9 | { 10 | getButtonsSchema(cm, tokens).map((section, i) => 11 | 12 | ) 13 | } 14 | 15 | 16 | 17 | 18 | 19 | ) 20 | 21 | 22 | ToolbarPanel.propTypes = { 23 | cm: PropTypes.object, //eslint-disable-line 24 | tokens: PropTypes.arrayOf(PropTypes.string), 25 | title: PropTypes.string 26 | } 27 | 28 | export default ToolbarPanel 29 | -------------------------------------------------------------------------------- /src/MarkdownEditor/ToolbarPanel/DropDown.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react' 2 | import MenuItem from 'material-ui/MenuItem' 3 | import IconButton from 'material-ui/IconButton' 4 | import IconMenu from 'material-ui/IconMenu' 5 | 6 | const DropDown = ({ icon, style, options, onItemTouchTap }) => ( 7 | 11 | { icon } 12 | 13 | } 14 | > 15 | { 16 | options.map((option, i) => ) 17 | } 18 | 19 | ) 20 | 21 | DropDown.propTypes = { 22 | icon: PropTypes.element, 23 | onItemTouchTap: PropTypes.func, 24 | style: PropTypes.object, //eslint-disable-line 25 | options: PropTypes.arrayOf( 26 | PropTypes.shape({ 27 | style: PropTypes.object, //eslint-disable-line 28 | primaryText: PropTypes.string 29 | }) 30 | ) 31 | } 32 | 33 | export default DropDown 34 | -------------------------------------------------------------------------------- /webpack-dev-server.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | const srcPath = path.join(__dirname, 'src', 'example') 4 | const buildPath = path.join(__dirname, 'example') 5 | 6 | const config = { 7 | entry: [ 8 | 'webpack/hot/dev-server', 9 | 'webpack/hot/only-dev-server', 10 | path.join(srcPath, 'index.js') 11 | ], 12 | output: { 13 | path: buildPath, 14 | filename: 'bundle.js' 15 | }, 16 | devServer: { 17 | contentBase: 'example', 18 | devtool: 'eval', 19 | hot: true, 20 | inline: true, 21 | port: 3000, 22 | outputPath: buildPath 23 | }, 24 | devtool: 'source-map', 25 | module: { 26 | loaders: [ 27 | { 28 | test: /\.js$/, 29 | exclude: /(node_modules)/, 30 | loaders: [ 31 | 'react-hot-loader/webpack', 32 | 'babel?presets[]=react,presets[]=es2015,plugins[]=babel-plugin-transform-class-properties' 33 | ] 34 | }, 35 | { 36 | test: /\.css$/, 37 | loader: 'style-loader!css-loader' 38 | } 39 | ] 40 | } 41 | } 42 | 43 | module.exports = config 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jed Watson 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/example/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import AppBar from 'material-ui/AppBar' 4 | import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider' 5 | import injectTapEventPlugin from 'react-tap-event-plugin' // eslint-disable-line 6 | import 'codemirror/lib/codemirror.css' // import codemirror styles 7 | import MarkdownEditor from '../MarkdownEditor' 8 | import '../MarkdownEditor/codemirrorOverride.css' // 9 | 10 | injectTapEventPlugin() 11 | 12 | const GithubIcon = () => 13 | 22 |