This module contains pre defined commands and transforms, which are the building blocks for modifying the editor.
defaultCommandMap : RichText.Config.Command.CommandMap
A starting point for creating your own command map. Contains deletion, line break, lift, split, select all, and undo/redo behavior.
defaultInputEventCommand : RichText.Internal.Event.InputEvent -> RichText.Config.Command.NamedCommandList
The default input event command does remove range when a range is selected and an insertText event occurs. In this case, we want to remove range and insert the text related to the input data.
defaultKeyCommand : RichText.Internal.Event.KeyboardEvent -> RichText.Config.Command.NamedCommandList
The default key command does remove range when a range is selected and a regular key is pressed. In this case, we want to remove range and insert the character related to that key.
removeRange : RichText.Model.State.State -> Result String RichText.Model.State.State
Delete the nodes in the selection, if there is one. Succeeds if the selection is a range selection and a successful remove operation occurred, otherwise returns the error describing why removing the nodes failed.
before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "hello"
, inlineElement (Element.element image []) []
, plainText "world"
]
)
]
)
)
(Just <| range [ 0, 0 ] 2 [ 0, 2 ] 2)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "he"
, plainText "rld"
]
)
]
)
)
(Just <| caret [ 0, 0 ] 2)
removeRange before == Ok after
--> True
removeRangeAndInsert : String -> RichText.Model.State.State -> Result String RichText.Model.State.State
Removes the contents in the state's range selection and optionally inserts the given text if possible. Returns an error if the selection is collapsed or it cannot remove the selection.
before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "hello"
, inlineElement (Element.element image []) []
, plainText "world"
]
)
]
)
)
(Just <| range [ 0, 0 ] 2 [ 0, 2 ] 2)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "het"
, plainText "rld"
]
)
]
)
)
(Just <| caret [ 0, 0 ] 3)
removeRangeAndInsert "t" before == Ok after
--> True
removeSelectedLeafElement : RichText.Model.State.State -> Result String RichText.Model.State.State
Removes a leaf element if it is the selected element, otherwise fails with an error.
before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "hello"
, inlineElement (Element.element image []) []
, plainText "world"
]
)
]
)
)
(Just <| caret [ 0, 1 ] 0)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "hello"
, plainText "world"
]
)
]
)
)
(Just <| caret [ 0, 0 ] 5)
removeSelectedLeafElement before == Ok after
--> True
backspaceBlock : RichText.Model.State.State -> Result String RichText.Model.State.State
Removes the previous block leaf if the selection is at the beginning of a text block, otherwise returns an error.
before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "p1" ])
, block
(Element.element horizontalRule [])
Leaf
, block
(Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "p2" ])
]
)
)
(Just <| caret [ 2, 0 ] 0)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "p1" ])
, block
(Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "p2" ])
]
)
)
(Just <| caret [ 1, 0 ] 0)
backspaceBlock before == Ok after
--> True
backspaceInlineElement : RichText.Model.State.State -> Result String RichText.Model.State.State
Removes the previous inline element if the selection is an inline element or text with offset 0. Returns an error if it was unable to remove the element.
before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "text"
, inlineElement (Element.element image []) []
, plainText "text2"
]
)
]
)
)
(Just <| caret [ 0, 2 ] 0)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "text"
, plainText "text2"
]
)
]
)
)
(Just <| caret [ 0, 1 ] 0)
backspaceInlineElement before == Ok after
--> True
backspaceText : RichText.Model.State.State -> Result String RichText.Model.State.State
Backspace transform for a single character. This function has a few quirks in order to take advantage of native backspace behavior, namely:
apply
may remove the text node)before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "text"
, markedText "text2" [ mark bold [] ]
]
)
]
)
)
(Just <| caret [ 0, 1 ] 0)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "tex"
, markedText "text2" [ mark bold [] ]
]
)
]
)
)
(Just <| caret [ 0, 0 ] 3)
backspaceText before == Ok after
--> True
backspaceWord : RichText.Model.State.State -> Result String RichText.Model.State.State
Removes the word before the collapsed selection, otherwise returns an error.
before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "this is an ex"
, markedText "ample okay" [ mark bold [] ]
]
)
]
)
)
(Just <| caret [ 0, 1 ] 6)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "this is an "
, markedText "okay" [ mark bold [] ]
]
)
]
)
)
(Just <| caret [ 0, 0 ] 11)
backspaceWord before == Ok after
--> True
selectBackward : RichText.Model.State.State -> Result String RichText.Model.State.State
If the selection is collapsed at the beginning of a text block, this will select the previous selectable node, and change the offset to the end if it's a text node. This is useful for default backspace behavior in case a join backward operation could not be made.
deleteBlock : RichText.Model.State.State -> Result String RichText.Model.State.State
Removes the next block leaf if the selection is at the end of a text block, otherwise fails with an error.
before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "p1" ])
, block
(Element.element horizontalRule [])
Leaf
, block
(Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "p2" ])
]
)
)
(Just <| caret [ 0, 0 ] 2)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "p1" ])
, block
(Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "p2" ])
]
)
)
(Just <| caret [ 0, 0 ] 2)
deleteBlock before == Ok after
--> True
deleteInlineElement : RichText.Model.State.State -> Result String RichText.Model.State.State
Removes the next inline element if the selection is at the end of a text leaf or inline element. Returns an error if it was unable to remove the element.
deleteText : RichText.Model.State.State -> Result String RichText.Model.State.State
Delete (forward) transform for a single character. This function has a few quirks in order to take advantage of native delete behavior, namely:
apply
may remove the text node)before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "text"
, markedText "text2" [ mark bold [] ]
]
)
]
)
)
(Just <| caret [ 0, 0 ] 4)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "text"
, markedText "ext2" [ mark bold [] ]
]
)
]
)
)
(Just <| caret [ 0, 1 ] 0)
deleteText before == Ok after
--> True
deleteWord : RichText.Model.State.State -> Result String RichText.Model.State.State
Removes the word after the collapsed selection, otherwise returns an error.
before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "this is an ex"
, markedText "ample okay" [ mark bold [] ]
]
)
]
)
)
(Just <| caret [ 0, 0 ] 11)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "this is an "
, markedText " okay" [ mark bold [] ]
]
)
]
)
)
(Just <| caret [ 0, 0 ] 11)
deleteWord before == Ok after
--> True
selectForward : RichText.Model.State.State -> Result String RichText.Model.State.State
If the selection is collapsed at the end of a text block, this will select the next selectable node at offset 0. This is useful for default delete behavior in case a join forward operation could not be made.
insertBlock : RichText.Model.Node.Block -> RichText.Model.State.State -> Result String RichText.Model.State.State
Transform that inserts the given block at the selection. This is useful for inserting things like horizontal rules or other block leaf elements.
If the selection is a range selection, the contents of that selection are first removed, then the insert command happens. If the inserted block is selectable, then the resulting selection will be the block, otherwise it will be the next selectable block or inline. Returns an error if the block could not be inserted.
before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "test" ])
]
)
)
(Just <| caret [ 0, 0 ] 2)
horizontalRuleBlock : Block
horizontalRuleBlock =
block
(Element.element horizontalRule [])
Leaf
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "te" ])
, horizontalRuleBlock
, block
(Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "st" ])
]
)
)
(Just <| caret [ 1 ] 0)
insertBlock horizontalRuleBlock before == Ok after
--> True
insertInline : RichText.Model.Node.Inline -> RichText.Model.State.State -> Result String RichText.Model.State.State
Inserts the inline at the current selection. If the inline is selectable, it selects it at offset 0, otherwise the selection becomes the next selectable item if it exists. Returns an error if it cannot insert.
img : Inline
img =
inlineElement (Element.element image []) []
before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "text"
]
)
]
)
)
(Just <| caret [ 0, 0 ] 2)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "te"
, img
, plainText "xt"
]
)
]
)
)
(Just <| caret [ 0, 1 ] 0)
insertInline before == Ok after
--> True
insertLineBreak : RichText.Config.Command.Transform
Inserts a hard break at the current selection.
before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "text"
]
)
]
)
)
(Just <| caret [ 0, 0 ] 2)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "te"
, inlineElement (Element.element hardBreak []) []
, plainText "xt"
]
)
]
)
)
(Just <| caret [ 0, 2 ] 0)
insertLineBreak before == Ok after
--> True
insertText : String -> RichText.Model.State.State -> Result String RichText.Model.State.State
Inserts text at the state's selection, otherwise returns an error.
before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "text"
]
)
]
)
)
(Just <| caret [ 0, 0 ] 2)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "teinsertxt" ]
)
]
)
)
(Just <| caret [ 0, 0 ] 8)
insertText before == Ok after
--> True
insertNewline : List String -> RichText.Model.State.State -> Result String RichText.Model.State.State
Insert a newline at the selection in elements with the name whitelisted by the String list. This is used by the code block element, since it only allows text (no line breaks or marks). This is a somewhat specialized method, but may be useful outside of its narrow context.
insertAfterBlockLeaf : RichText.Model.Node.Block -> RichText.Model.State.State -> Result String RichText.Model.State.State
Inserts the block after a block leaf.
emptyParagraph : Block
emptyParagraph =
block
(Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "" ])
before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "test" ])
, block
(Element.element horizontalRule [])
Leaf
]
)
)
(Just <| caret [ 1 ] 0)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "test" ])
, block
(Element.element horizontalRule [])
Leaf
, emptyParagraph
]
)
)
(Just <| caret [ 2, 0 ] 0)
insertAfterBlockLeaf emptyParagraph before == Ok after
--> True
joinBackward : RichText.Model.State.State -> Result String RichText.Model.State.State
If the selection is collapsed and at the start of a text block, tries to join the current block the previous one. Otherwise, returns an error.
before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "text"
]
)
, block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "text2"
]
)
]
)
)
(Just <| caret [ 1, 0 ] 0)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "text"
, plainText "text2"
]
)
]
)
)
(Just <| caret [ 0, 0 ] 4)
joinBackward before == Ok after
--> True
joinForward : RichText.Model.State.State -> Result String RichText.Model.State.State
If the selection is collapsed and at the end of a text block, tries to join the current block the next one. Otherwise, returns an error.
before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "text" ])
, block
(Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "text2" ])
]
)
)
(Just <| caret [ 0, 0 ] 4)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <|
Array.fromList
[ plainText "text"
, plainText "text2"
]
)
]
)
)
(Just <| caret [ 0, 0 ] 4)
joinForward before == Ok after
--> True
lift : RichText.Model.State.State -> Result String RichText.Model.State.State
Lifts the selected block or the closest ancestor block out of its parent node. If the current selection is a range selection, this function lifts all blocks that are in the range. Returns an error if no lift can be done.
before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element blockquote [])
(blockChildren <|
Array.fromList
[ block (Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "text" ])
]
)
]
)
)
(Just <| caret [ 0, 0, 0 ] 0)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "text" ])
]
)
)
(Just <| caret [ 0, 0 ] 0)
lift before == Ok after
--> True
liftEmpty : RichText.Model.State.State -> Result String RichText.Model.State.State
Same as lift
but only succeeds if the selection is an empty text block.
before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element blockquote [])
(blockChildren <|
Array.fromList
[ block (Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "" ])
]
)
]
)
)
(Just <| caret [ 0, 0, 0 ] 0)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "" ])
]
)
)
(Just <| caret [ 0, 0 ] 0)
liftEmpty before == Ok after
--> True
splitBlock : (RichText.Model.Node.Path -> RichText.Model.Node.Block -> Maybe ( RichText.Model.Node.Path, RichText.Model.Node.Block )) -> RichText.Model.State.State -> Result String RichText.Model.State.State
Split the ancestor block determined by the passed in function of the selection. If the selection is a range selection, also delete its content.
before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block (Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "" ])
]
)
)
(Just <| caret [ 0, 0 ] 0)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block (Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "" ])
, block (Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "" ])
]
)
)
(Just <| caret [ 1, 0 ] 0)
splitBlock findTextBlockAncestor before == Ok after
--> True
splitBlockHeaderToNewParagraph : List String -> RichText.Model.Element.Element -> RichText.Model.State.State -> Result String RichText.Model.State.State
Does the split block logic, but also additionally changes the second part of the split to the given element if it's an empty text block. This is useful for splitting a header to a paragraph block.
before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block (Element.element heading [])
(inlineChildren <| Array.fromList [ plainText "" ])
]
)
)
(Just <| caret [ 0, 0 ] 0)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block (Element.element heading [])
(inlineChildren <| Array.fromList [ plainText "" ])
, block (Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "" ])
]
)
)
(Just <| caret [ 1, 0 ] 0)
splitBlockHeaderToNewParagraph before == after
--> True
splitTextBlock : RichText.Config.Command.Transform
Same as splitBlock
but the searches for a text block ancestor if one exists.
before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block (Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "" ])
]
)
)
(Just <| caret [ 0, 0 ] 0)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block (Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "" ])
, block (Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "" ])
]
)
)
(Just <| caret [ 1, 0 ] 0)
splitTextBlock before == Ok after
--> True
Toggle commands for elements and marks
toggleTextBlock : RichText.Model.Element.Element -> RichText.Model.Element.Element -> Basics.Bool -> RichText.Model.State.State -> Result String RichText.Model.State.State
Changes the selected block or blocks to the onElement if one or more blocks is not that element. Otherwise, it changes it to the off element. If an element is not in the allowedElements, then it is unaffected.
The arguments are as follows:
onElement
- The element to change to if there is one or more block that is not that elementoffElement
- The element to change to if all blocks are the onElement
convertToPlainText
- if true, strips the inline content of all marks and inline elements.before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block (Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "text" ])
]
)
)
(Just <| caret [ 0, 0 ] 0)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element heading [])
(inlineChildren <| Array.fromList [ plainText "text" ])
]
)
)
(Just <| caret [ 0, 0 ] 0)
toggleTextBlock (Element.element heading []) (Element.element paragraph []) False before == Ok after
toggleMark : RichText.Model.Mark.MarkOrder -> RichText.Model.Mark.Mark -> RichText.Model.Mark.ToggleAction -> RichText.Model.State.State -> Result String RichText.Model.State.State
Applies the toggle action for the mark. The affected marks are sorted by the given mark order.
boldMark : Mark
boldMark =
mark bold []
markdownMarkOrder : MarkOrder
markdownMarkOrder =
markOrderFromSpec markdown
before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block (Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "text" ])
]
)
)
(Just <| caret [ 0, 0 ] 0)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <| Array.fromList [ markedText "" [ boldMark ], plainText "text" ])
]
)
)
(Just <| caret [ 0, 0 ] 0)
toggleMark markdownMarkOrder boldMark Add example == Ok
selectAll : RichText.Model.State.State -> Result String RichText.Model.State.State
Updates the state's selection to span the first and last element of the document.
before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block (Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "text" ])
]
)
)
(Just <| caret [ 0, 0 ] 0)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "text" ])
]
)
)
(Just <| singleNodeRange [ 0, 0 ] 0 4)
selectAll before == Ok after
--> True
wrap : (RichText.Model.Node.Block -> RichText.Model.Node.Block) -> RichText.Model.Element.Element -> RichText.Model.State.State -> Result String RichText.Model.State.State
Wraps the selection in the given element. The first argument is a mapping function for each
block element affected by the wrap. For normal transforms, using identity
is okay, but for things
like lists, you may want to apply a function to wrap an additional list item block around each node.
before : State
before =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block (Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "text" ])
]
)
)
(Just <| caret [ 0, 0 ] 0)
after : State
after =
state
(block
(Element.element doc [])
(blockChildren <|
Array.fromList
[ block
(Element.element blockquote [])
(blockChildren <|
Array.fromList
[ block
(Element.element paragraph [])
(inlineChildren <| Array.fromList [ plainText "text" ])
]
)
]
)
)
(Just <| caret [ 0, 0, 0 ] 0)
wrap identity (Element.element blockquote []) before == Ok after
--> True