module React.Render
( render
, cancelRender
) where
import Control.Applicative
import Control.Monad
import Control.Monad.IO.Class
import Data.Functor.Identity
import Data.IORef
import Data.List
import Data.Maybe
import Data.Monoid
import Data.String
import Haste hiding (fromString)
import Haste.Foreign
import Haste.JSON
import Haste.Prim
import React.Anim
import React.Attrs
import React.Class
import React.Elements
import React.Events
import React.Imports
import React.Interpret
import React.Local
import React.Types
doRender :: Elem -> Double -> ReactClass ty -> IO ()
doRender elem time ReactClass{ classRender,
classTransition,
transitionRef,
runningAnimRef,
animRef,
stateRef } = do
transitions <- readIORef transitionRef
runningAnims <- readIORef runningAnimRef
prevState <- readIORef stateRef
prevAnim <- readIORef animRef
let (newState, newAnims) =
mapAccumL classTransition prevState transitions
newAnims' = concat newAnims
newRunningAnims = map (\conf -> RunningAnim conf time) newAnims'
(runningAnims', endingAnims) = partition
(\(RunningAnim AnimConfig{duration} beganAt) ->
beganAt + duration > time)
(runningAnims <> newRunningAnims)
endingAnims' = zip endingAnims [1..]
runningAnims'' = zip runningAnims' (map (lerp time) runningAnims')
newAnim = stepRunningAnims prevAnim (endingAnims' ++ runningAnims'')
endAnimTrans = mapMaybe
(\anim -> onComplete (config anim) True)
endingAnims
foreignNode <- runIdentity $
interpret (classRender newState) newAnim (updateCb transitionRef)
js_render foreignNode elem
writeIORef stateRef newState
writeIORef animRef newAnim
writeIORef runningAnimRef runningAnims'
writeIORef transitionRef endAnimTrans
updateCb :: IORef [signal] -> signal -> IO ()
updateCb ref update = modifyIORef ref (update:)
render :: Elem
-> ReactClass ty
-> IO RenderHandle
render elem cls@ReactClass{transitionRef, runningAnimRef} = do
let renderCb time = do
transitions <- readIORef transitionRef
runningAnims <- readIORef runningAnimRef
when (length transitions + length runningAnims > 0) $
doRender elem time cls
js_raf $ toPtr renderCb
return ()
doRender elem 0 cls
js_raf $ toPtr renderCb
cancelRender :: RenderHandle -> IO ()
cancelRender = js_cancelRaf