This is an alternative site for discovering Elm packages. You may be looking for the official Elm package site instead.
README

Dialog

Elm Modal Dialogs.

type alias Config msg = { closeMessage : Maybe msg , containerClass : Maybe String , containerId : Maybe String , header : Maybe (Html msg) , body : Maybe (Html msg) , footer : Maybe (Html msg) }

The configuration for the dialog you display. The header, body and footer are all Maybe (Html msg) blocks. Those (Html msg) blocks can be as simple or as complex as any other view function.

Use only the ones you want and set the others to Nothing.

The closeMessage is an optional Signal.Message we will send when the user clicks the 'X' in the top right. If you don't want that X displayed, use Nothing.

The id is an optional element id. This is required if you want to use the aria-labelledby and aria-describedby properties.

view : Maybe (Config msg) -> Html msg

Renders a modal dialog whenever you supply a Config msg.

To use this, include this view in your top-level view function, right at the top of the DOM tree, like so:

type Message
  = ...
  | ...
  | AcknowledgeDialog


view : -> Model -> Html Message
view model =
  div
    []
    [ ...
    , ...your regular view code....
    , ...
    , Dialog.view
        (if model.shouldShowDialog then
          Just { closeMessage = Just AcknowledgeDialog
               , containerClass = Just "your-container-class"
               , header = Just (text "Alert!")
               , body = Just (p [] [text "Let me tell you something important..."])
               , footer = Nothing
               }
         else
          Nothing
        )
    ]

It's then up to you to replace model.shouldShowDialog with whatever logic should cause the dialog to be displayed, and to handle an AcknowledgeDialog message with whatever logic should occur when the user closes the dialog.

See the examples/ directory for examples of how this works for apps large and small.

map : (a -> b) -> Config a -> Config b

This function is useful when nesting components with the Elm Architecture. It lets you transform the messages produced by a subtree.

mapMaybe : (a -> b) -> Maybe (Config a) -> Maybe (Config b)

For convenience, a varient of map which assumes you're dealing with a Maybe (Config a), which is often the case.

module Dialog exposing (Config, view, map, mapMaybe)

{-| Elm Modal Dialogs.

@docs Config, view, map, mapMaybe

-}

import Exts.Html.Bootstrap exposing (..)
import Exts.Maybe exposing (maybe, isJust)
import Html
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Maybe exposing (andThen)


{-| Renders a modal dialog whenever you supply a `Config msg`.

To use this, include this view in your *top-level* view function,
right at the top of the DOM tree, like so:

    type Message
      = ...
      | ...
      | AcknowledgeDialog


    view : -> Model -> Html Message
    view model =
      div
        []
        [ ...
        , ...your regular view code....
        , ...
        , Dialog.view
            (if model.shouldShowDialog then
              Just { closeMessage = Just AcknowledgeDialog
                   , containerClass = Just "your-container-class"
                   , header = Just (text "Alert!")
                   , body = Just (p [] [text "Let me tell you something important..."])
                   , footer = Nothing
                   }
             else
              Nothing
            )
        ]

It's then up to you to replace `model.shouldShowDialog` with whatever
logic should cause the dialog to be displayed, and to handle an
`AcknowledgeDialog` message with whatever logic should occur when the user
closes the dialog.

See the `examples/` directory for examples of how this works for apps
large and small.

-}
view : Maybe (Config msg) -> Html msg
view maybeConfig =
    let
        displayed =
            isJust maybeConfig

        maybeContainerId =
            maybeConfig |> Maybe.andThen .containerId

        ariaAttributes =
            case maybeContainerId of
                Nothing ->
                    []

                Just id ->
                    [ attribute "role" "dialog"
                    , Html.Attributes.id id
                    , attribute "aria-labelledby" (id ++ "_header")
                    , attribute "aria-describedby" (id ++ "_body")
                    ]
    in
        div
            (case
                maybeConfig
                    |> Maybe.andThen .containerClass
             of
                Nothing ->
                    []

                Just containerClass ->
                    [ class containerClass ]
            )
            [ div
                ([ classList
                    [ ( "modal", True )
                    , ( "in", displayed )
                    ]
                 , style
                    [ ( "display"
                      , if displayed then
                            "block"
                        else
                            "none"
                      )
                    ]
                 ]
                )
                [ div ((class "modal-dialog") :: ariaAttributes)
                    [ div [ class "modal-content" ]
                        (case maybeConfig of
                            Nothing ->
                                [ empty ]

                            Just config ->
                                [ wrapHeader config
                                , wrapBody config
                                , wrapFooter config
                                ]
                        )
                    ]
                ]
            , backdrop maybeConfig
            ]


wrapHeader : Config msg -> Html msg
wrapHeader { closeMessage, containerId, header } =
    if closeMessage == Nothing && header == Nothing then
        empty
    else
        let
            ariaAttributes =
                case containerId of
                    Nothing ->
                        []

                    Just id ->
                        [ Html.Attributes.id (id ++ "_header") ]
        in
            div ((class "modal-header") :: ariaAttributes)
                [ maybe empty closeButton closeMessage
                , Maybe.withDefault empty header
                ]


closeButton : msg -> Html msg
closeButton closeMessage =
    button [ class "close", onClick closeMessage, attribute "aria-label" "close" ]
        [ text "x" ]


wrapBody : Config msg -> Html msg
wrapBody { containerId, body } =
    case body of
        Nothing ->
            empty

        Just bodyBody ->
            let
                ariaAttributes =
                    case containerId of
                        Nothing ->
                            []

                        Just id ->
                            [ Html.Attributes.id (id ++ "_body") ]
            in
                div ((class "modal-body") :: ariaAttributes)
                    [ bodyBody ]


wrapFooter : Config msg -> Html msg
wrapFooter { footer } =
    case footer of
        Nothing ->
            empty

        Just footerBody ->
            div [ class "modal-footer" ] [ footerBody ]


backdrop : Maybe (Config msg) -> Html msg
backdrop config =
    div [ classList [ ( "modal-backdrop in", isJust config ) ] ]
        []


{-| The configuration for the dialog you display. The `header`, `body`
and `footer` are all `Maybe (Html msg)` blocks. Those `(Html msg)` blocks can
be as simple or as complex as any other view function.

Use only the ones you want and set the others to `Nothing`.

The `closeMessage` is an optional `Signal.Message` we will send when the user
clicks the 'X' in the top right. If you don't want that X displayed, use `Nothing`.

The `id` is an optional element id.
This is required if you want to use the `aria-labelledby` and `aria-describedby` properties.

-}
type alias Config msg =
    { closeMessage : Maybe msg
    , containerClass : Maybe String
    , containerId : Maybe String
    , header : Maybe (Html msg)
    , body : Maybe (Html msg)
    , footer : Maybe (Html msg)
    }


{-| This function is useful when nesting components with the Elm
Architecture. It lets you transform the messages produced by a
subtree.
-}
map : (a -> b) -> Config a -> Config b
map f config =
    { closeMessage = Maybe.map f config.closeMessage
    , containerClass = config.containerClass
    , containerId = config.containerId
    , header = Maybe.map (Html.map f) config.header
    , body = Maybe.map (Html.map f) config.body
    , footer = Maybe.map (Html.map f) config.footer
    }


{-| For convenience, a varient of `map` which assumes you're dealing with a `Maybe (Config a)`, which is often the case.
-}
mapMaybe : (a -> b) -> Maybe (Config a) -> Maybe (Config b)
mapMaybe =
    Maybe.map << map