rich text editor using Elm
You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Brian Hicks 7f7a9d55d6 make Document opaque 4 years ago
nix nixify 4 years ago
src make Document opaque 4 years ago
.gitignore let parcel install stuff, I guess 4 years ago
.projections.json add projectionist projections 4 years ago add references section 4 years ago
elm.json add elm-test 4 years ago
shell.nix let parcel install stuff, I guess 4 years ago


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

This is all very aspirational yet, though!


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 =
	    [ Retain 5 { add = [ Bold ], remove = [] }
	    , Retain 2 { add = [], remove = [] }
	    , Delete 5
	    , Insert (Text "Humans" [])

this produces:

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

The Custom Element

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

    <!-- rendered content from Elm -->
  <div contenteditable></div>

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.