module Component.Modal ( ModalIn(..) , ModalOut(..) , modal ) where import Control.Monad (void) import qualified Data.Map as M import qualified Data.Map.Lazy as LM import Data.Text (Text) import qualified GHCJS.DOM.Element as Element import qualified GHCJS.DOM.Node as Node import JSDOM.Types (JSString) import Reflex.Dom (Dynamic, Event, MonadWidget) import qualified Reflex.Dom as R import qualified Reflex.Dom.Class as R import qualified Util.Dom as Dom data ModalIn t m a = ModalIn { _modalIn_show :: Event t () , _modalIn_hide :: Event t () , _modalIn_content :: m a } data ModalOut a = ModalOut { _modalOut_content :: a } modal :: forall t m a. MonadWidget t m => ModalIn t m a -> m (ModalOut a) modal modalIn = do rec let showEvent = R.leftmost [ True <$ _modalIn_show modalIn , False <$ _modalIn_hide modalIn , False <$ curtainClick ] showModal <- R.holdDyn False showEvent (elem, (curtainClick, content)) <- R.buildElement "div" (getAttributes <$> showModal) $ do (curtain, _) <- R.elAttr' "div" (M.singleton "class" "modalCurtain") $ R.blank cont <- R.divClass "modalContent" $ _modalIn_content modalIn return (R.domEvent R.Click curtain, cont) performShowEffects showEvent elem return $ ModalOut { _modalOut_content = content } getAttributes :: Bool -> LM.Map Text Text getAttributes show = M.fromList $ [ ("style", if show then "display:block" else "display:none") , ("class", "modal") ] performShowEffects :: forall t m a. MonadWidget t m => Event t Bool -> Element.Element -> m () performShowEffects showEvent elem = do body <- Dom.getBody let showEffects = flip fmap showEvent (\show -> do if show then do Node.appendChild body elem Element.setClassName body ("modal" :: JSString) else Element.setClassName body ("" :: JSString) ) R.performEvent_ $ void `fmap` showEffects