This is an alternative site for discovering Elm packages. You may be looking for the official Elm package site instead.
We were not able to find the expected elm-package.json file at this tag.
Tag 3.0.0
Committed At 2018-11-04 02:24:33 UTC

Modules

    README

    Undo/redo in any Elm app

    Add undo/redo to any Elm app with just a few lines of code!

    Trying to add undo/redo in JS can be a nightmare. If anything gets mutated in an unexpected way, your history can get corrupted. Elm is built from the ground up around efficient, immutable data structures. That means adding support for undo/redo is a matter of remembering the state of your app at certain times. Since there is no mutation, there is no risk of things getting corrupted. Given immutability lets you do structural sharing within data structures, it also means these snapshots can be quite compact!

    How it works

    The library is centered around a single data structure, the UndoList.

    type alias UndoList state =
        { past: List state
        , present: state
        , future: List state
        }
    

    An UndoList contains a list of past states, a present state, and a list of future states. By keeping track of the past, present, and future states, undo and redo become just a matter of sliding the present around a bit.

    Example

    Initial counter app

    We will start with a very simple counter application. There is a button, and when it is clicked, a counter is incremented.

    -- BEFORE
    import Html exposing (div, button, text)
    import Html.Events exposing (onClick)
    import Html.App as Html
    
    main =
        Html.beginnerProgram
            { model = 0
            , view = view
            , update = update
            }
    
    type alias Model = Int
    
    type Msg = Increment
    
    update : Msg -> Model -> Model
    update msg model =
        case msg of
            Increment ->
                model + 1
    
    view : Model -> Html Msg
    view model =
        div
            []
            [ button
                [ onClick Increment ]
                [ text "Increment" ]
            , div
                []
                [ text (toString model) ]
            ]
    

    Adding undo

    Suppose that further down the line we decide it would be nice to have an undo button.

    The next code block is the same program updated to use the UndoList module to add this functionality. It is in one big block because it is mostly the same as the original, and we will go into the differences afterwards.

    -- AFTER
    import Html exposing (div, button, text)
    import Html.Events exposing (onClick)
    import Html.App as Html
    import UndoList exposing (UndoList)
    
    main =
        Html.beginnerProgram
            { model = UndoList.fresh 0
            , view = view
            , update = update
            }
    
    type alias Model
        = UndoList Int
    
    type Msg
        = Increment
        | Undo
    
    update : Msg -> Model -> Model
    update msg model =
        case msg of
            Increment ->
                UndoList.new (model.present + 1) model
    
            Undo ->
                UndoList.undo model
    
    view : Model -> Html Msg
    view model =
        div
            []
            [ button
                [ onClick Increment ]
                [ text "Increment" ]
            , button
                [ onClick Undo ]
                [ text "Undo" ]
            , div
                []
                [ text (toString model) ]
            ]
    

    Here are the differences:

    • the Model type changed from Int to UndoList Int
    • the Msg type now has a new constructor Undo
    • the update function now cares for this new Undo message in the pattern matching
    • a button was added to the view function. It sends the Undo message

    Adding redo functionality is quite the same. You can find by yourself as an exercise, or look at the counter example.

    Usage with commands

    When you use Html.App.program instead of Html.App.beginnerProgram as above, you can use commands in your update function.

    Look at the counter with cats example which loads a GIF image whenever you increment the counter, with undo/redo even with asynchronous operations.

    More Details

    This API is designed to work really nicely with The Elm Architecture.

    It has a lot more cool stuff, so read the docs.