Skip to content

Instantly share code, notes, and snippets.

@TheSeamau5
Last active August 29, 2015 14:27
Show Gist options
  • Save TheSeamau5/5a38cbe5ce085705ba34 to your computer and use it in GitHub Desktop.
Save TheSeamau5/5a38cbe5ce085705ba34 to your computer and use it in GitHub Desktop.
UI Components
import Signal exposing (Address)
import Html exposing (Html)
import Task exposing (Task)
import Time exposing (Time)
import Window
type Never = Never Never
type alias Init options state effect = options -> (state, Maybe effect)
type alias Update action state effect = action -> state -> (state, Maybe effect)
type alias View action state view = Address action -> state -> view
type alias Loopback action effect = Address action -> effect -> Task Never ()
type UIAction action
= Tick Time
| Resize (Int, Int)
| Action action
type alias Component options action state effect view =
{ init : Init options state effect
, update : Update action state effect
, view : View action state view
}
stateless
: { init : state
, view : state -> view
}
-> Component Never Never state Never view
stateless {init, view} =
{ init = (\_ -> (init, Nothing))
, update = (\_ s -> (s, Nothing))
, view = always view
}
type alias Runner options action state effect view
= options
-> Component options action state effect view
-> Output action state effect view
type alias Output action state effect view =
{ states : Signal state
, actions : Signal (Maybe action)
, effects : Signal (Maybe effect)
, tasks : Signal (Task Never ())
, views : Signal view
}
runUI
: Loopback action effect
-> Runner options (UIAction action) state effect view
runUI loopback options component =
let
mailbox =
Signal.mailbox Nothing
uiaddress =
Signal.forwardTo mailbox.address Just
address =
Signal.forwardTo uiaddress Action
compStartMailbox =
Signal.mailbox ()
appStartTask =
Signal.send compStartMailbox.address ()
resizes =
Signal.map Resize Window.dimensions
actions =
Signal.sampleOn compStartMailbox.signal resizes
|> Signal.merge resizes
|> Signal.merge (Signal.map Tick (Time.every 60)) -- Replace by AnimationFrame.frame
|> Signal.map Just
|> Signal.merge mailbox.signal
update maybeAction (state, effect) =
case maybeAction of
Nothing ->
(state, effect)
Just action ->
component.update action state
view state =
component.view address state
transactions =
Signal.foldp update (component.init options) actions
states =
Signal.map fst transactions
effects =
Signal.map snd transactions
runEffect maybeEffect =
case maybeEffect of
Nothing ->
Task.succeed ()
Just effect ->
loopback address effect
tasks =
effects
|> Signal.map runEffect
|> Signal.merge appStartTask
views =
Signal.map view states
in
{ states = states
, actions = actions
, effects = effects
, tasks = tasks
, views = views
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment