packages feed

ghcjs-vdom-0.2.0.0: src/GHCJS/VDOM/Component.hs

{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE GHCForeignImportPrim #-}
{-# LANGUAGE UnliftedFFITypes #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE MagicHash #-}

module GHCJS.VDOM.Component ( VComp
                            , toNode
                            , mkComponent
                            , render
                            , diff
                            , patch
                            ) where

import           Control.Monad

import           GHCJS.Foreign.QQ

import           GHCJS.VDOM.Internal.Types

import qualified GHCJS.VDOM.Internal       as I
import           GHCJS.VDOM.Internal       (j)
import qualified GHCJS.VDOM.Internal.Thunk as I

import           GHC.Exts
import           GHC.Types (IO(..))
import           Unsafe.Coerce

toNode :: VComp -> VNode
toNode (VComp v) = VNode v
{-# INLINE toNode #-}

mkComponent :: IO VNode -> IO VComp
mkComponent r = do
  let renderE = I.unsafeExportValue r
  c <- VComp <$> [jsu| h$vdom.c(`renderE, null, null, null) |]
  void $ patch c =<< diff c =<< render c
  return c

foreign import javascript unsafe "$r = $1.hsRender;"
  js_hsRender :: VComp -> State# RealWorld -> (# State# RealWorld, Any #)

render :: VComp -> IO VNode
render c = join $ IO (\s -> case js_hsRender c s of
  (# s', r #) -> (# s', unsafeCoerce r #))
{-# INLINE render #-}

diff :: VComp -> VNode -> IO Patch
diff (VComp c) (VNode v) = do
  thunks <- [jsu| [] |]
  patch  <- [jsu| `c.diff(`v, `thunks) |]
  I.forceThunks thunks
  I.forcePatch [j| `patch.patch |]
  return (Patch patch)
{-# INLINE diff #-}

patch :: VComp -> Patch -> IO Bool
patch (VComp c) (Patch p) = [jsu| `c.patch(`p) |]
{-# INLINE patch #-}