react/src/React/JSaddle.hs
2023-07-04 11:35:18 -04:00

93 lines
2.8 KiB
Haskell

{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -Wno-orphans #-}
-- | Everything in this module belongs in JSaddle, GHCJS-DOM, or similar
module React.JSaddle where
import Prelude hiding ((!!))
import Data.Text (Text)
import qualified Data.Text as T
import Data.Map (Map)
import qualified Data.Map as Map
import Control.Monad
import Data.String
import React.Misc
#ifdef ghcjs_HOST_OS
import Data.Coerce (coerce)
import GHCJS.Foreign.Callback
import qualified JavaScript.Array as Array (toListIO)
import Language.Javascript.JSaddle
#else
import GHCJS.Prim.Internal (primToJSVal)
import Language.Javascript.JSaddle hiding (Ref)
#endif
#ifndef ghcjs_HOST_OS
instance PToJSVal Text where
pToJSVal s = primToJSVal $ PrimVal_String s
instance PToJSVal Int where
pToJSVal i = primToJSVal $ PrimVal_Number $ fromIntegral i
#endif
instance PToJSVal Function where
pToJSVal (Function _ o) = pToJSVal o
instance PToJSVal Object where
pToJSVal (Object v) = v
instance IsString JSVal where
fromString = pToJSVal . T.pack
instance ToJSVal v => ToJSVal (Map Text v) where
toJSVal m = do
o@(Object oVal) <- obj
forM_ (Map.toList m) $ \(k, v) -> do
(o <# k) =<< toJSVal v
pure oVal
consoleLog :: ToJSVal a => a -> JSM JSVal
consoleLog x = (global ! t "console") # t "log" $ [x]
type JSCallAsFunction' = JSVal -- ^ Function object
-> JSVal -- ^ this
-> [JSVal] -- ^ Function arguments
-> JSM JSVal -- ^ Return value
function' :: JSCallAsFunction' -- ^ Haskell function to call
-> JSM Function' -- ^ Returns a JavaScript function object that will
-- call the Haskell one when it is called
#ifdef ghcjs_HOST_OS
function' f = do
callback <- syncCallback2' $ \this args -> do
rargs <- Array.toListIO (coerce args)
f this this rargs -- TODO pass function object through
Function' callback <$> makeFunctionWithCallback' callback
#else
function' f = do
(cb, f') <- newSyncCallback'' f --TODO: "ContinueAsync" behavior
return $ Function' cb $ Object f'
#endif
#ifdef ghcjs_HOST_OS
data Function' = Function' {functionCallback' :: Callback (JSVal -> JSVal -> IO JSVal), functionObject' :: Object}
#else
data Function' = Function' {functionCallback' :: CallbackId, functionObject' :: Object}
#endif
#ifdef ghcjs_HOST_OS
foreign import javascript unsafe "$r = function () { return $1(this, arguments); }"
makeFunctionWithCallback' :: Callback (JSVal -> JSVal -> IO JSVal) -> IO Object
#endif
instance ToJSVal Function' where
toJSVal = toJSVal . functionObject'
instance PToJSVal Function' where
pToJSVal (Function' _ o) = pToJSVal o