package.json
1 2 3 4 5 6 7 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 |
{ "name": "draft-js-example", "version": "0.1.0", "private": true, "dependencies": { "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "dompurify": "^2.4.1", "draft-convert": "^2.1.13", "draft-js": "^0.11.7", "draft-js-example": "file:", "react": "^18.2.0", "react-dom": "^18.2.0", "react-draft-wysiwyg": "^1.15.0", "react-scripts": "5.0.1", "web-vitals": "^2.1.4" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, "eslintConfig": { "extends": [ "react-app", "react-app/jest" ] }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] } } |
App.css
1 2 3 4 5 6 7 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 |
.App-header { background-color: #282c34; min-height: 5vh; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: calc(10px + 2vmin); color: white; margin-bottom: 5vh; text-align: center; padding: 12px; } .wrapper-class { padding: 1rem; border: 1px solid #ccc; } .editor-class { background-color: lightgray; padding: 1rem; border: 1px solid #ccc; } .toolbar-class { border: 1px solid #ccc; } .preview { padding: 1rem; margin-top: 1rem; } |
App.jsx
1 2 3 4 5 6 7 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 51 52 53 54 55 56 57 58 59 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 |
import React, { useState, useEffect } from 'react'; import { EditorState } from 'draft-js'; import { Editor } from 'react-draft-wysiwyg'; import { convertToHTML } from 'draft-convert'; import DOMPurify from 'dompurify'; import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css'; import './App.css'; function App() { const [editorState, setEditorState] = useState( () => EditorState.createEmpty(), ); const [convertedContent, setConvertedContent] = useState(null); useEffect(() => { let html = convertToHTML(editorState.getCurrentContent()); setConvertedContent(html); }, [editorState]); function createMarkup(html) { return { __html: DOMPurify.sanitize(html) } } return ( <div className="App"> <header className="App-header"> Rich Text Editor Example </header> <Editor editorState={editorState} onEditorStateChange={setEditorState} wrapperClassName="wrapper-class" editorClassName="editor-class" toolbarClassName="toolbar-class" toolbar={{ options: [ 'inline', 'blockType', 'fontSize', 'fontFamily', 'list', 'textAlign', 'colorPicker', 'link', 'embedded', 'emoji', 'image', 'remove', 'history' ], inline: { options: ['bold', 'italic', 'underline', 'strikethrough', 'monospace', 'superscript', 'subscript'], }, list: { options: ['unordered', 'ordered', 'indent', 'outdent'], }, textAlign: { options: ['left', 'center', 'right', 'justify'], }, link: { options: ['link', 'unlink'], }, history: { options: ['undo', 'redo'], }, }} hashtag={{ separator: ' ', trigger: '#', }} mention={{ separator: ' ', trigger: '@', suggestions: [ { text: 'JavaScript', value: 'javascript', url: 'js' }, { text: 'Golang', value: 'golang', url: 'go' }, ], }} /> <div className="preview" dangerouslySetInnerHTML={createMarkup(convertedContent)}> </div> </div> ) } export default App; |