├── .gitignore ├── README.md ├── package.json ├── public ├── favicon.ico ├── index.html └── manifest.json └── src ├── Editor.js ├── index.js ├── parse.js └── styles.js /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /build 3 | package-lock.json 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | a **Work-in-Progress** grammatical WISYWIG text editor, using [draftjs](https://draftjs.org/) 2 | 3 | ![image](https://user-images.githubusercontent.com/399657/45503877-32135b80-b756-11e8-8f86-9b2be2f77b95.png) 4 | 5 | ### [Demo](http://nlp-compromise.github.io/react-nlp/index.html) 6 | 7 | to play with it, run `npm run start` 8 | 9 | will publish it once it's working better 10 | 11 | MIT 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-nlp", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "compromise": "^11.12.0", 7 | "draft-js": "^0.10.5", 8 | "react": "^16.5.0", 9 | "react-dom": "^16.5.0", 10 | "react-scripts": "1.1.5" 11 | }, 12 | "scripts": { 13 | "start": "react-scripts start", 14 | "build": "react-scripts build", 15 | "test": "react-scripts test --env=jsdom", 16 | "eject": "react-scripts eject" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nlp-compromise/react-nlp/d18d25ffb61482f61a6216fbcd2772aa7871881a/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /src/Editor.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import { Editor, EditorState, RichUtils, CompositeDecorator } from "draft-js"; 3 | import styles from "./styles"; 4 | import { findNoun, renderNoun } from "./parse"; 5 | 6 | class MyEditor extends Component { 7 | constructor(props) { 8 | super(props); 9 | const compositeDecorator = new CompositeDecorator([ 10 | { 11 | strategy: findNoun, 12 | component: renderNoun 13 | } 14 | ]); 15 | this.state = { 16 | editorState: EditorState.createEmpty(compositeDecorator) 17 | }; 18 | this.focus = () => this.refs.editor.focus(); 19 | this.onChange = editorState => { 20 | this.setState({ 21 | editorState 22 | }); 23 | }; 24 | } 25 | render() { 26 | return ( 27 |
28 |
29 | 36 |
37 |
38 | ); 39 | } 40 | } 41 | 42 | export default MyEditor; 43 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import Editor from "./Editor"; 4 | 5 | ReactDOM.render(, document.getElementById("root")); 6 | -------------------------------------------------------------------------------- /src/parse.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import styles from "./styles"; 3 | import nlp from "compromise"; 4 | 5 | export function findNoun(contentBlock, callback) { 6 | const text = contentBlock.getText(); 7 | let doc = nlp(text); 8 | let nouns = doc.nouns().out("offsets"); 9 | nouns.forEach(o => { 10 | callback(o.wordStart, o.wordEnd); 11 | }); 12 | } 13 | export const renderNoun = props => { 14 | return ( 15 | 16 | {props.children} 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /src/styles.js: -------------------------------------------------------------------------------- 1 | const blue = "#6699cc"; 2 | const red = "#cc7066"; 3 | const green = "#6accb2"; 4 | // const navy = '#335799' 5 | // const yellow = '#e1e6b3' 6 | // const pink = '#e6b8b3 7 | // const olive = '#7f9c6c' 8 | // const brown = '#9c896c' 9 | // const darkblue = '#6c7f9c' 10 | // const orange = '#cc8a66' 11 | // const purple = '#d8b3e6' 12 | // const lightblue = '#66a8cc' 13 | // const lightgreen = '#66ccac' 14 | // const darkgreen = '#339957' 15 | // const darkbrown = '#605439' 16 | // const burnt = '#603a39' 17 | // const rose = '#e6b4b3' 18 | // const dimblue = '#949a9e' 19 | // const beige = '#e6d7b3' 20 | 21 | // const offwhite = '#fbfbfb' 22 | 23 | // const lightgrey = '#e9edec' 24 | // const dimgrey = '#d7d5d2' 25 | // const grey = '#4d4d4d' 26 | // const midgrey = '#949a9e' 27 | // const slategrey = '#51433e' 28 | // const bluegrey = '#606c74' 29 | // const darkgrey = '#443d3d' 30 | // const offblack = '#333333' 31 | 32 | const styles = { 33 | root: { 34 | fontFamily: "'Helvetica', sans-serif", 35 | padding: 20, 36 | width: 600 37 | }, 38 | editor: { 39 | border: "1px solid #ddd", 40 | cursor: "text", 41 | fontSize: 20, 42 | minHeight: 30, 43 | padding: 10 44 | }, 45 | red: { 46 | color: red 47 | }, 48 | blue: { 49 | color: blue 50 | }, 51 | green: { 52 | color: green 53 | }, 54 | hashtag: { 55 | color: "rgba(95, 184, 138, 1.0)" 56 | } 57 | }; 58 | export default styles; 59 | --------------------------------------------------------------------------------