rich text editor using Elm
 
 
 
 
Go to file
Brian Hicks 7f7a9d55d6 make Document opaque 2019-10-17 14:00:08 -05:00
nix nixify 2019-10-15 22:58:37 -05:00
src make Document opaque 2019-10-17 14:00:08 -05:00
.gitignore let parcel install stuff, I guess 2019-10-16 00:02:24 -05:00
.projections.json add projectionist projections 2019-10-17 13:47:32 -05:00
README.md add references section 2019-10-17 05:12:09 -05:00
elm.json add elm-test 2019-10-17 13:47:32 -05:00
shell.nix let parcel install stuff, I guess 2019-10-16 00:02:24 -05:00

README.md

elm-edit

This is an experimental rich text editor in Elm (minimal magic, but does require a custom element.)

This is all very aspirational yet, though!

Approach

The Big Deal(tm) here is that we render content in Elm but store the document state in a separate pure-functional data structure. This means that all our edits have semantic meaning instead of having to rely on re-reading the DOM.

The Document Format

We use a similar format to Quill. See Edit.Document for the format, and Edit.Delta for how to make edits. For example:

type Attr = Bold | Italic


doc : Document Attr
doc =
    Document [ Text "Hello, World!" [] ]


edited : Document Attr
edited =
    Delta.apply
        (Delta
	    [ Retain 5 { add = [ Bold ], remove = [] }
	    , Retain 2 { add = [], remove = [] }
	    , Delete 5
	    , Insert (Text "Humans" [])
	    ]
	)
	doc

this produces:

Document
    [ Text "Hello" [ Bold ]
    , Text ", " []
    , Text "Humans!" []
    ]

The Custom Element

in Elm, create a DOM structure that looks like this:

<elm-edit>
  <template>
    <!-- rendered content from Elm -->
  </template>
  <div contenteditable></div>
</elm-edit>

the custom element does these things:

  • Manage selection inside the contenteditable node. We can provide cursor/range offset so that we can edit the data structure above. This is similar to the approach taken by Quill, Trix, etc.
  • Sync content from the template to the contenteditable node. This lets us get around virtualdom crashing when nodes get removed by the user.
  • Observe mutation in the contenteditable node. Pass these events back to Elm using custom events. This lets us rely on browser input wherever possible (so pressing alt-n n on a Mac will type ñ, speech-to-text will work, etc)
    • Undo/redo stack Hopefully we can rely on MutationObserver doing the right thing and letting us see when text gets added/removed with ctrl/cmd-z
  • Handle paste events. We can get XML representation of pasted rich text from other programs, which we can handle robustly in an Elm parser.

References