Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Text editing & immutable data structures

Text editing & immutable data structures

What has Draft.js eaten

Talk given at Helsinki React.js Meetup in June 2017 https://www.meetup.com/ReactJS-Community/events/239875743/

Vesa Vänskä

June 15, 2017
Tweet

More Decks by Vesa Vänskä

Other Decks in Programming

Transcript

  1. Text editing & immutable data structures What has Draft.js eaten

    Vesa Vänskä, Kisko Labs Vesa Vänskä 2017 @vesan
  2. Code example import {Editor, EditorState} from 'draft-js'; class BasicEditor 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} />; } } Vesa Vänskä 2017 @vesan
  3. Vesa Vänskä → Software Developer & Partner at @kiskolabs →

    Ruby on the backend, JavaScript on the frontend → React.js as the frontend tool of choice for two-ish years Vesa Vänskä 2017 @vesan
  4. Draft.js state structure Immutable.js Immutable.js provides many Persistent Immutable data

    structures including: List, Stack, Map, OrderedMap, Set, OrderedSet and Record. Vesa Vänskä 2017 @vesan
  5. // Immutable.js Map const map1 = Map({ a: 1, b:

    2, c: 3 }) const map2 = map1.set('b', 50) map1.get('b') // 2 map2.get('b') // 50 // Regular Object const map1 = { a: 1, b: 2, c: 3 } const map2 = map1 map2['b'] = 50 map1['b'] // 50 map2['b'] // 50 Vesa Vänskä 2017 @vesan
  6. Draft.js State Structure EditorState → The current text content state

    → The current selection state → The fully decorated representation of the contents → Undo/redo stacks Vesa Vänskä 2017 @vesan
  7. Draft.js State Structure EditorState state tree → Editor → Content

    → Selection → Current inline style Vesa Vänskä 2017 @vesan
  8. Draft.js State Structure ContentState → The entire contents of an

    editor: text, block and inline styles, and entity ranges. → Two selection states of an editor: before and after the rendering of these contents. Vesa Vänskä 2017 @vesan
  9. Draft.js State Structure Block Map → Ordered map that has

    ContentBlocks → Single blocks of content → Information about type of content, attached entities, inline styles and depth Vesa Vänskä 2017 @vesan
  10. Draft.js State Structure SelectionState Represents a selection range in the

    editor. Selection points: anchor & focus values which both have ContentBlock key and offset. Vesa Vänskä 2017 @vesan
  11. SelectionState → anchorKey → anchorOffset → focusKey → focusOffset →

    isBackward → hasFocus Vesa Vänskä 2017 @vesan
  12. How to change the state (high-level) Modifier → replaceText →

    insertText → moveText → applyInlineStyle → removeInlineStyle Vesa Vänskä 2017 @vesan
  13. How to change the state (high-level) Modifier All return new

    ContentState. Vesa Vänskä 2017 @vesan
  14. Extending the rendering For visual changes, you can change the

    block rendering Vesa Vänskä 2017 @vesan
  15. Extending the rendering Custom block map How to map content

    types to components. Vesa Vänskä 2017 @vesan
  16. Extending the rendering Custom block map example const blockRenderMap =

    Immutable.Map({ 'SectionWrapper': { element: 'section', wrapper: <SectionWrapper /> } }); Vesa Vänskä 2017 @vesan
  17. Extending the rendering Custom block renderer example function mediaBlockRenderer(contentBlock) {

    const type = contentBlock.getType(); if (type === 'atomic') { return { component: MediaComponent, editable: false, props: { foo: 'bar', }, }; } } Vesa Vänskä 2017 @vesan
  18. Extending the rendering Editor decorator const decorator = new CompositeDecorator([{

    strategy: numberedHeadingsStrategy, component: NumberedHeading, }]); EditorState.createEmpty(decorator) Vesa Vänskä 2017 @vesan
  19. Extending the rendering Editor decorator strategy const numberedHeadingsStrategy = (contentBlock,

    callback, contentState) => { const type = contentBlock.getType(); const isHeading = ["header-one", "header-two", "header-three", "header-four", "header-five"].includes(type); if (isHeading) { callback(0, contentBlock.getText().length); } } Vesa Vänskä 2017 @vesan
  20. Extending the rendering Editor decorator custom component const NumberedHeading =

    (props) => { let key = props.offsetKey.match(/^([^-]+)-/)[1]; const data = props.contentState.getBlockForKey(key).getData() const number = data && data.get("number"); return ( <span data-before={number !== null ? number + " " : number} className="editor-numbered-heading"> <span>{props.children}</span> </span> ); }; Vesa Vänskä 2017 @vesan