Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Upcoming SlideShare
What to Upload to SlideShare
What to Upload to SlideShare
Loading in …3
×
1 of 38

Edição de Texto Rico com React e Draft.js

0

Share

Download to read offline

Edição de Texto Rico com React e Draft.js

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all

Edição de Texto Rico com React e Draft.js

  1. 1. EdiçãodeTextoRico comReacteDraft.js Guilherme Vierno
  2. 2. Aboutme • Mineiro • Físicoporformação • Fullstackdev-8anos • Desenvolvedorna • Plataformasdepublicação(admin) • megadraft.io
  3. 3. Editoresdetextorico naWeb
  4. 4. Editoresdetextorico Servempara: • Mudaraaparênciadotexto(negrito,itálico,etc) • Adicionarmídias,comoimagensevídeos • Criarrelaçõesentreconteúdosatravésdelinks • … SemeditarHTMLnamão…
  5. 5. OldSchool CKEditor(CKEditor.com) Fonte: https://www.turnkeylinux.org/blog/tinymce-vs-ckeditor
  6. 6. OldSchool TinyMCE(https://www.tinymce.com) Fonte: https://www.turnkeylinux.org/blog/tinymce-vs-ckeditor
  7. 7. • HTML/DOM===State • Copiar&Colar • Desfazer/Refazer • Crossbrowser&ContentEditable Desafios
  8. 8. NewSchool
  9. 9. NewSchool
  10. 10. NewSchool
  11. 11. React& Draft.js
  12. 12. Draft.js ODraft.jséumframeworkconstruídopeloFacebook usandoReact,queusaummodeloimutávelefacilitaa construçãodeeditoresdetextorico,abstraindoas diferençasentreosnavegadores • OpenSource • Seminterface,éumframework,nãoumeditor • Tudoécustomizável • Controleestritodoconteúdo(ContentEditable+React) • Controleestritodocursor(SelectionAPI)
  13. 13. Draft.js Oestadodoeditorécompostopordoissub-estados imutáveis: • EditorState • ContentState • SelectionState
  14. 14. Draft.js import React from 'react'; import ReactDOM from 'react-dom'; import {Editor, EditorState} from 'draft-js'; class MyEditor extends React.Component { constructor(props) { super(props); this.state = {editorState: EditorState.createEmpty()}; this.onChange = (editorState) => this.setState({editorState}); } render() { return ( <Editor editorState={this.state.editorState} onChange={this.onChange} /> ); } } ReactDOM.render( <MyEditor />, document.getElementById('container') );
  15. 15. Draft.js import React from 'react'; import ReactDOM from 'react-dom'; import {Editor, EditorState} from 'draft-js'; class MyEditor extends React.Component { constructor(props) { super(props); this.state = {editorState: EditorState.createEmpty()}; this.onChange = (editorState) => this.setState({editorState}); } render() { return ( <Editor editorState={this.state.editorState} onChange={this.onChange} /> ); } } ReactDOM.render( <MyEditor />, document.getElementById('container') );
  16. 16. Draft.js Conteúdocontroladoatravésdoestadoimutável Map { content: List [ Map { "text": "lorem ipsum" } ], selection: Map { start: 6, end: 6, block: 0 } } ENTER
  17. 17. Draft.js Égeradoumnovoestadoatravésdemodificadores Map { content: List [ Map { "text": “lorem ipsum" }, Map { "text": "ipsum" } ], selection: Map { start: 0, end: 0, block: 1 } } SplitBlock SetSelection
  18. 18. Draft.js Undo/Redo Map { content: List [ Map { "text": “lorem" }, Map { "text": "ipsum" } ], selection: Map { start: 0, end: 0, block: 1 } } Map { content: List [ { "text": "lorem ipsum" } ], selection: Map { start: 6, end: 6, block: 0 } }
  19. 19. Estadoserializável ConvertendooestadoparaJSON const content = convertFromRaw(rawState) const EditorState = EditorState.createWithContent(state) const rawState = convertToRaw(contentState) CriandooestadoapartirdeumJSON
  20. 20. { "entityMap": {}, "blocks": [ { "key": "ag6qs", "text": "", "type": "unstyled", "depth": 0, "inlineStyleRanges": [], "entityRanges": [], "data": {} } ] } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ContentState
  21. 21. { "entityMap": {}, "blocks": [ { "key": "ag6qs", "text": "megadraft", "type": "unstyled", "depth": 0, "inlineStyleRanges": [], "entityRanges": [], "data": {} }, { "key": "dg2bk", "text": "rock'n'roll", "type": "unstyled", "depth": 0, "inlineStyleRanges": [], "entityRanges": [], "data": {} } ] } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 Blocks
  22. 22. { "entityMap": {}, "blocks": [ { "key": "ag6qs", "text": "rock n roll", "type": "unstyled", "depth": 0, "inlineStyleRanges": [ { "offset": 7, "length": 4, "style": "BOLD" } ], "entityRanges": [], "data": {} } ] } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 inlineStyleRanges
  23. 23. { "entityMap": { "0": { "type": "LINK", "mutability": "MUTABLE", "data": { "url": "https://megadraft.io/LICENSE" } } }, "blocks": [ { "key": "ag6qs", "text": "Megadraft is MIT licensed", "type": "unstyled", "depth": 0, "inlineStyleRanges": [], "entityRanges": [ { "offset": 13, "length": 3, "key": 0 } ], "data": {} } ] } 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 Entity
  24. 24. { "entityMap": {}, "blocks": [ { "key": "ag6qs", "text": "Good usability", "type": "ordered-list-item", "depth": 0, "inlineStyleRanges": [], "entityRanges": [], "data": {} }, { "key": "1pdm1", "text": "A nice default base of plugins", "type": "ordered-list-item", "depth": 1, "inlineStyleRanges": [], "entityRanges": [], "data": {} } ] } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 depth
  25. 25. { "entityMap": {}, "blocks": [ { "key": "ag6qs", "text": "", "type": "image", "depth": 0, "inlineStyleRanges": [], "entityRanges": [], "data": { "url": "http://example.com/image.jpg", "credits": "My credits", "legend": "Legendary", "height": 1920, "width": 1080, "left": 0, "top": 0, "type": "image/jpeg", } } ] } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 data
  26. 26. • blockRenderMap(mapeiatiposdeblocosparatagsHTML) • blockRenderFn(renderizaumblockqualquer) • blockStyleFn(classNamedosblocks) • decorators(envolvetextoemumcomponente) • customStyleMap(defineoestilodeumestiloinline) Customização
  27. 27. ExportaroconteúdodoDraft.js Existemalgunsprojetosqueconvertemomodelo: • https://github.com/sstur/draft-js-export-html • https://github.com/rkpasia/draft-js-exporter • https://github.com/globocom/react-native-draftjs-render • …
  28. 28. Megadraft
  29. 29. Megadraft OMegadraftéumeditordetextoricoconstruídocomos frameworksDraft.jseReact. • Boausabilidade • Umabasepadrãoagradáveldeplugins • Extensibilidade • OpenSource
  30. 30. import {MegadraftEditor, editorStateFromRaw} from "megadraft"; class App extends React.Component { constructor(props) { super(props); this.state = {editorState: editorStateFromRaw(null)}; this.onChange = ::this.onChange; } onChange(editorState) { this.setState({editorState}); } render() { return ( <MegadraftEditor editorState={this.state.editorState} onChange={this.onChange} /> ) } } ReactDOM.render( <App />, document.getElementById("container") ); 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 ComousaroMegadraft
  31. 31. ComousaroMegadraft <link href="node_modules/megadraft/dist/css/megadraft.css" rel="stylesheet">
  32. 32. class Example extends React.Component { ... render() { return ( <MegadraftEditor plugins={[MyPlugin1, MyPlugin2]} ... /> ); } } 1 2 3 4 5 6 7 8 Plugins
  33. 33. PluginGenerator https://github.com/globocom/generator-megadraft-plugin npm install -g yo npm install -g generator-megadraft-plugin yo megadraft-plugin
  34. 34. import ImageButton from "./ImageButton"; import ImageBlock from "./ImageBlock"; export default { // Friendly plugin name title: "Image", // A unique plugin name used to identify the plugin and its blocks type: "image", // React component to be rendered in the block sidebar buttonComponent: ImageButton, // React component for rendering the content block blockComponent: ImageBlock }; 1 2 3 4 5 6 7 8 9 10 11 12 13 PluginStructure
  35. 35. import React, {Component} from "react"; import {DraftJS, insertDataBlock} from "megadraft"; export default class BlockButton extends Component { constructor(props) { this.onClick = ::this.onClick; } onClick(e) { e.preventDefault(); const src = window.prompt("Enter a URL"); const data = {"type": "image", "src": src}; // Calls the onChange method with the new state. this.props.onChange(insertDataBlock(this.props.editorState, data)); } render() { return ( <button className={this.props.className} onClick={this.onClick}> <SomeIcon className="sidemenu__button__icon" /> </button> ); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 buttonComponent
  36. 36. import React, {Component} from "react"; export default class ImageBlock extends Component { render(){ return ( <img src={this.props.data.src} /> ); } } 1 2 3 4 5 6 7 8 9 blockComponent
  37. 37. Slate
  38. 38. queosdeusesdoheavymetalestejamcomvocês Obrigado! GuilhermeVierno vierno.com.br megadraft.io

×