mweiss / elm-rte-toolkit / RichText.Commands

This module contains pre defined commands and transforms, which are the building blocks for modifying the editor.

Commands

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.

Transforms

Remove selection

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

Backspace

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:

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.

Deletion

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:

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.

Insert

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

Join

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

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

Split

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

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:

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

Selection

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

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