Skip to content

Instantly share code, notes, and snippets.

@TheSeamau5
Last active August 29, 2015 14:22
Show Gist options
  • Save TheSeamau5/fcb3af91a3fc262a5834 to your computer and use it in GitHub Desktop.
Save TheSeamau5/fcb3af91a3fc262a5834 to your computer and use it in GitHub Desktop.
Button in Elm with animation
import Html exposing (Html)
import Html.Attributes exposing (style)
import Html.Events exposing (onClick, onMouseOver, onMouseOut)
import Signal exposing (Signal, Address)
import Time
(=>) = (,)
type alias Options =
{ label : String
, color : String
}
type ButtonState
= Idle
| Active ButtonState
| Hovered
type alias Animation =
{ currentFrame : Int
, frameCount : Int
, isRunning : Bool
}
step : Animation -> Animation
step animation =
if animation.isRunning
then
if animation.currentFrame < animation.frameCount
then
{ animation | currentFrame <- animation.currentFrame + 1 }
else
{ animation | isRunning <- False }
else
animation
play : Animation -> Animation
play animation =
{ animation | isRunning <- True }
restart : Animation -> Animation
restart animation =
{ animation | currentFrame <- 0 }
animation : Int -> Animation
animation n =
Animation 0 n False
type alias Button =
{ idle : Options
, hovered : Options
, active : Options
, state : ButtonState
, animation : Animation
}
type Action
= NoOp
| Click
| Hover
| Release
button : Button
button =
{ idle =
{ label = "Idle"
, color = "white"
}
, hovered =
{ label = "Hovered"
, color = "rgba(46, 204, 113,0.5)"
}
, active =
{ label = "Active"
, color = "rgba(46, 204, 113,1.0)"
}
, state = Idle
, animation = animation 10
}
update : Action -> Button -> Button
update action button =
case action of
NoOp ->
case button.state of
Active previousState ->
{ button | state <- previousState
, animation <- step (button.animation)
}
_ ->
{ button | animation <- step (button.animation) }
Click ->
case button.state of
Active _ ->
{ button | animation <- play (restart button.animation)
}
_ ->
{ button | state <- Active button.state
, animation <- play (restart button.animation)
}
Hover ->
{ button | state <- Hovered
, animation <- step (button.animation)
}
Release ->
{ button | state <- Idle
, animation <- step (button.animation)
}
currentState : Button -> Options
currentState button =
if button.animation.isRunning
then
button.active
else
case button.state of
Idle -> button.idle
Hovered -> button.hovered
Active _ -> button.active
view : Address Action -> Button -> Html
view address button =
let
{label, color} = currentState button
buttonStyles =
[ "background-color" => color
, "transition" => "background-color 0.2s ease-out"
, "border" => "none"
, "width" => "160px"
, "height" => "90px"
, "font-size" => "16pt"
, "border-radius" => "5%"
, "cursor" => "pointer"
]
in
Html.button
[ style buttonStyles
, onClick address Click
, onMouseOver address Hover
, onMouseOut address Release
]
[ Html.text label ]
----
{address, signal} = Signal.mailbox NoOp
signal' =
Signal.merge signal
(Signal.sampleOn (Time.fps 60) (Signal.constant NoOp))
main =
Signal.map (view address)
(Signal.foldp update button signal')
----
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment