module Component.Modal ( In(..) , Content , view ) where import Control.Monad (void) import qualified Data.Map as M import qualified Data.Map.Lazy as LM import Data.Text (Text) import qualified Data.Text as T import Data.Time.Clock (NominalDiffTime) 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.Reflex as ReflexUtil -- Content = CurtainClickEvent -> (CancelEvent, ConfirmEvent) type Content t m = Event t () -> m (Event t (), Event t ()) data In t m = In { _in_show :: Event t () , _in_content :: Content t m } view :: forall t m a. MonadWidget t m => In t m -> m (Event t ()) view input = do rec let show = Show <$ (_in_show input) startHiding = R.attachWithMaybe (\a _ -> if a then Just StartHiding else Nothing) (R.current canBeHidden) (R.leftmost [ hide, curtainClick ]) canBeHidden <- R.holdDyn True $ R.leftmost [ False <$ startHiding , True <$ endHiding ] endHiding <- R.delay (0.2 :: NominalDiffTime) (EndHiding <$ startHiding) let action = R.leftmost [ show, startHiding, endHiding ] modalClass <- R.holdDyn "" (fmap getModalClass action) (elem, dyn) <- R.buildElement "div" (getAttributes <$> modalClass) $ ReflexUtil.visibleIfEvent (isVisible <$> action) (R.blank >> return (R.never, R.never, R.never)) (do (curtain, _) <- R.elAttr' "div" (M.singleton "class" "g-Modal__Curtain") $ R.blank let curtainClick = R.domEvent R.Click curtain (hide, content) <- R.divClass "g-Modal__Content" (_in_content input curtainClick) return (curtainClick, hide, content)) performShowEffects action elem let curtainClick = R.switchDyn $ (\(a, _, _) -> a) <$> dyn let hide = R.switchDyn $ (\(_, b, _) -> b) <$> dyn let content = R.switchDyn $ (\(_, _, c) -> c) <$> dyn -- Delay the event in order to let time for the modal to disappear R.delay (0.5 :: NominalDiffTime) content getAttributes :: Text -> LM.Map Text Text getAttributes modalClass = M.singleton "class" $ T.intercalate " " [ "g-Modal", modalClass] performShowEffects :: forall t m a. MonadWidget t m => Event t Action -> Element.Element -> m () performShowEffects showEvent elem = do body <- ReflexUtil.getBody let showEffects = flip fmap showEvent (\case Show -> do Node.appendChild body elem Element.setClassName body ("g-Body--Modal" :: JSString) StartHiding -> return () EndHiding -> do Node.removeChild body elem Element.setClassName body ("" :: JSString) ) R.performEvent_ $ void `fmap` showEffects data Action = Show | StartHiding | EndHiding getModalClass :: Action -> Text getModalClass Show = "g-Modal--Show" getModalClass StartHiding = "g-Modal--Hiding" getModalClass _ = "" isVisible :: Action -> Bool isVisible Show = True isVisible StartHiding = True isVisible EndHiding = False