{-# LANGUAGE FlexibleInstances, GADTs, MultiParamTypeClasses, FlexibleContexts, IncoherentInstances, LambdaCase, DataKinds #-} -- Note on IncoherentInstances: the two instances below will both work fine -- for `GeneralizeSignal Void Void`. They should never be called. module React.Local (GeneralizeSignal(..), locally) where import Control.Applicative import Data.Void import React.Types -- | -- Implement when a local signal can be generalized to a higher level one. Used -- by 'locally' class GeneralizeSignal sigloc siggen where generalizeSignal :: sigloc -> siggen instance GeneralizeSignal a a where generalizeSignal = id instance GeneralizeSignal Void a where generalizeSignal = absurd -- | -- 'locally' exists to make it simple to embed classes with local concerns. An -- example will be helpful: -- -- We have some page which can respond to many different events. -- -- @ -- data Transition -- = UserTyping JSString -- | Toggle -- ... -- -- globalPage_ :: [AttrOrHandler Transition] -> ReactNode Transition -- @ -- -- And we want to be able to embed some components that don't care about all -- that. 'inputBox_' can only output 'JSString' and 'pageHeader_' can't send -- any signals at all. -- -- @ -- inputBox_ :: ReactNode JSString -- pageHeader_ :: ReactNode Void -- @ -- -- With locally we can easily embed them in 'globalPage_': -- -- @ -- instance GeneralizeSignal JSString Transition where -- generalizeSignal = UserTyping -- -- -- (globalPage_) -- renderFn = \props state -> div_ [ class_ "global-page" ] $ do -- locally pageHeader_ -- ... -- locally inputBox_ -- ... -- @ locally :: GeneralizeSignal sigloc siggen => ReactNode sigloc -> ReactNode siggen locally = LocalNode generalizeSignal