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)