myxine-client-0.0.0.1: src/Myxine/Handlers.hs
module Myxine.Handlers (Handlers, on, handle, handledEvents) where
import Data.Maybe
import Data.Dependent.Map (DMap, Some)
import qualified Data.Dependent.Map as DMap
import Myxine.Event
import Myxine.Target
-- | Create a handler for a specific event type by specifying the type of event
-- and the monadic callback to be invoked when the event occurs.
--
-- The provided callback will be given the @'EventType' props@ of the event, the
-- properties @props@ of this particular event, a list of 'Target's on which the
-- event fired, in order from most to least specific, and the current @model@ of
-- a page. It has the option to do arbitrary 'IO', and to return a
-- possibly-changed @model@.
--
-- Notice that each variant of 'EventType' has a type-level index describing
-- what kind of data is carried by events of that type. This means that, for
-- instance, if you want to handle a 'Click' event, which has the type
-- 'EventType MouseEvent', your event handler as created by 'on' will be given
-- access to a 'MouseEvent' data structure when it is invoked. That is to say:
--
-- @
-- 'on' 'Click' (\properties@'MouseEvent'{} targets model ->
-- do print properties
-- print targets
-- print model)
-- :: 'Show' model => 'Handlers' model
-- @
--
-- A full listing of all available 'EventType's and their corresponding property
-- records can be found in the below section on [types and properties of
-- events](#Types).
on :: EventType props -> (props -> [Target] -> model -> IO model) -> Handlers model
on event h = Handlers (DMap.singleton event (Handler h))
{-# INLINE on #-}
-- | Dispatch all the event handler callbacks for a given event type and its
-- corresponding data. Event handlers for this event type will be called in the
-- order they were registered (left to right) with the result of the previous
-- handler fed as the input to the next one.
handle :: Handlers model -> EventType props -> props -> [Target] -> model -> IO model
handle (Handlers allHandlers) event props path model =
let Handler handler =
fromMaybe (Handler (const (const (const (pure model)))))
(DMap.lookup event allHandlers)
in handler props path model
{-# INLINE handle #-}
-- | Get a list of all the events which are handled by these handlers.
handledEvents :: Handlers model -> [Some EventType]
handledEvents (Handlers handlers) = DMap.keys handlers
-- | A set of handlers for events, possibly empty. Create new 'Handlers' using
-- 'on', and combine 'Handlers' together using their 'Monoid' instance.
newtype Handlers model
= Handlers (DMap EventType (Handler model))
instance Semigroup (Handlers model) where
Handlers hs <> Handlers hs' =
Handlers (DMap.unionWithKey (const (<>)) hs hs')
instance Monoid (Handlers model) where
mempty = Handlers mempty
-- | A handler for a single event type with associated data @props@.
newtype Handler model props
= Handler (props -> [Target] -> model -> IO model)
instance Semigroup (Handler model props) where
Handler h <> Handler g =
Handler (\props p a -> h props p a >>= g props p)
instance Monoid (Handler model props) where
mempty = Handler (\_ _ a -> pure a)