Skip to content

Instantly share code, notes, and snippets.

@ni-ko-o-kin
Created March 11, 2020 11:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ni-ko-o-kin/1baf6e5e91e1ad811a15242de7a605a1 to your computer and use it in GitHub Desktop.
Save ni-ko-o-kin/1baf6e5e91e1ad811a15242de7a605a1 to your computer and use it in GitHub Desktop.
Phantom Builder Pattern with Elm
module Main exposing (main, view)
import Browser
import Html exposing (Html, button, div, text)
import Html.Attributes exposing (style)
main =
Browser.sandbox
{ init = ()
, update = \_ _ -> ()
, view = view
}
view : () -> Html a
view _ =
initButton "Click me!"
|> withColor Pink
|> withSize Large
-- |> withSize Small -- compile error
-- |> withColor Red -- compile error
|> buttonToHtml
type Color
= Pink
| Blue
| Red
type Size
= Small
| Medium
| Large
type Button a
= Button
{ text : String
, color : Maybe Color
, size : Maybe Size
}
initButton : String -> Button { canAddColor : (), canAddSize : () }
initButton text =
Button
{ text = text
, color = Nothing
, size = Nothing
}
buttonToHtml : Button a -> Html msg
buttonToHtml (Button config) =
let
styles =
[ Just [ style "margin" "10px" ]
, Maybe.map colorToStyles config.color
, Maybe.map sizeToStyles config.size
]
|> List.filterMap identity
|> List.concat
in
button styles [ text config.text ]
withColor : Color -> Button { a | canAddColor : () } -> Button a
withColor color (Button config) =
Button { config | color = Just color }
withSize : Size -> Button { a | canAddSize : () } -> Button a
withSize size (Button config) =
Button { config | size = Just size }
colorToStyles : Color -> List (Html.Attribute msg)
colorToStyles color =
case color of
Pink ->
[ style "color" "pink" ]
Blue ->
[ style "color" "blue" ]
Red ->
[ style "color" "red" ]
sizeToStyles : Size -> List (Html.Attribute msg)
sizeToStyles size =
case size of
Small ->
[ style "padding" "0px", style "font-size" "0.5rem" ]
Medium ->
[ style "padding" "5px", style "font-size" "1rem" ]
Large ->
[ style "padding" "10px", style "font-size" "2rem" ]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment