There is no pure Elm rich text editor and according to short research main problem is absence of Selection API. Only way to get or set selection is through ports. When I started thinking about this I found out that Selection api is kind of tricky because current browser API heavily depends on sending DOM elements around.
To get selection I think most Elm way is to define new events that could by assigned to elements like attributes (Html.Events
):
-
onSelectionStart
triggered when selection start on current element, return offset from start of the element -
onSelectionEnd
triggered when selection end in current element, return offset from start of the element -
onSelection
triggered when selection is inside of current element, return tuple(Int, Int)
with start and end offset of selection -
onCaret
triggered on content editable elements on caret movements (click, arrows)
If element with onSelection
is inside of selection it is kind of questionable how it should behave. Intuitively I would say it should be triggered and return (0, end_of_element)
but I can imagine that detecting if element is in selection range can by performance killer (Probably need to walk html tree recursively if element is part of selection) and also if it is used in content editable, selection is already limited to content of element.
Attributes to set selection:
selectionStart=Int
selectionEnd=Int
caret=Int
I think names are self explanatory.
In case that in one rendering there is used selection attribute multiple times, last one would win. Or alternatively there should by runtime error. On one hand there can by tricky errors if some nested hidden view override selection on other hand, well, runtime error. But I did not come up with solution that would use type system to solve this problem.
I would like to know what do you think about this API. Normally I would try to implement it first and then I would publish it, but it require change to virtual dom (at least as I think about it).
This API should allow creation of rich text editors similar to draft.js or something more modular like ProseMirror. Also I got quite inspired by this post.
Thank you for feedback.