-----------------------------------------------------------------------------
{-# LANGUAGE CPP                       #-}
{-# LANGUAGE QuasiQuotes               #-}
{-# LANGUAGE NamedFieldPuns            #-}
{-# LANGUAGE RecordWildCards           #-}
{-# LANGUAGE TemplateHaskell           #-}
-----------------------------------------------------------------------------
{-# OPTIONS_GHC -Wno-duplicate-exports #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  Miso
-- Copyright   :  (C) 2016-2025 David M. Johnson (@dmjio)
-- License     :  BSD3-style (see the file LICENSE)
-- Maintainer  :  David M. Johnson <code@dmj.io>
-- Stability   :  experimental
-- Portability :  non-portable
----------------------------------------------------------------------------
module Miso
  ( -- * API
    -- ** Miso
    miso
  , (🍜)
    -- ** App
  , App
  , startApp
  , renderApp
    -- ** Component
  , Component
  , component
  , (+>)
  , mount_
    -- ** Sink
  , withSink
  , Sink
    -- ** Mail
  , mail
  , checkMail
  , parent
  , mailParent
  , broadcast
    -- ** Subscriptions
  , startSub
  , stopSub
  , Sub
    -- ** Effect
  , issue
  , batch
  , io
  , io_
  , sync
  , sync_
  , for
#ifdef WASM
  -- ** JS file embedding
  , evalFile
#endif
    -- * Reactivity (Data bindings)
    -- | Primitives for synchronizing parent and child models.
  , module Miso.Binding
    -- * DSL
    -- | A JavaScript DSL for easy FFI interoperability
  , module Miso.DSL
    -- * Effect
    -- | 'Effect', 'Sub', and 'Sink' types for defining update functions and subscriptions.
  , module Miso.Effect
    -- * Event
    -- | Functions for specifying component lifecycle events and event handlers.
  , module Miso.Event
    -- * Fetch
    -- | Interface to the Fetch API for making HTTP requests.
  , module Miso.Fetch
    -- * PubSub
    -- | Publish / Subscribe primitives for communication between components.
  , module Miso.PubSub
    -- * Property
    -- | Construct custom properties on DOM elements.
  , module Miso.Property
    -- * Reload
    -- | Support for clearing the page during live-reloading w/ WASM browser mode.
  , module Miso.Reload
    -- * Subscriptions
    -- | Subscriptions for external events (mouse, keyboard, window, history, etc.).
  , module Miso.Subscription
    -- * Storage
    -- | Web Storage API (Local and Session storage) interface.
  , module Miso.Storage
    -- * Types
    -- | Core types for Miso applications.
  , module Miso.Types
    -- * Util
    -- | Utility functions for views, parsing, and general purpose combinators.
  , module Miso.Util
    -- * FFI
    -- | Foreign Function Interface (FFI) utilities for interacting with JavaScript.
  , module Miso.FFI
    -- * State management
    -- | State management for Miso applications.
  , module Miso.State
  ) where
-----------------------------------------------------------------------------
import           Control.Monad (void)
-----------------------------------------------------------------------------
import           Miso.Binding
import           Miso.Diff
import           Miso.DSL
import           Miso.Effect
import           Miso.Event
import           Miso.Fetch
import           Miso.FFI
import qualified Miso.FFI.Internal as FFI
import           Miso.Property
import           Miso.PubSub
import           Miso.Reload
import           Miso.Router
import           Miso.Runtime
import           Miso.State
import           Miso.Storage
import           Miso.Subscription
import           Miso.Types
import           Miso.Util
----------------------------------------------------------------------------
-- | Runs an isomorphic @miso@ application.
-- Assumes the pre-rendered DOM is already present.
-- Always mounts to \<body\>. Copies page into the virtual DOM.
--
-- To get an IO action that starts the application, use 'run' on the result of this function.
--
-- @
-- main :: IO ()
-- main = miso defaultEvents (\\uri -> ..))
-- @
miso :: Eq model => Events -> (URI -> App model action) -> IO ()
miso :: forall model action.
Eq model =>
Events -> (URI -> App model action) -> IO ()
miso Events
events URI -> App model action
f = IO (ComponentState ROOT model action) -> IO ()
forall a. IO a -> IO ()
withJS (IO (ComponentState ROOT model action) -> IO ())
-> IO (ComponentState ROOT model action) -> IO ()
forall a b. (a -> b) -> a -> b
$ do
  vcomp <- URI -> App model action
f (URI -> App model action) -> IO URI -> IO (App model action)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO URI
getURI
  body <- FFI.getBody
  initialize events rootComponentId Hydrate isRoot vcomp (pure body)
-----------------------------------------------------------------------------
-- | Synonym for 'startApp'.
--
-- To get an t'IO' action that starts the application, use 'run' on the result of this function.
--
-- @
-- main :: IO ()
-- main = startApp defaultEvents app
-- @
--
startApp :: Eq model => Events -> App model action -> IO ()
startApp :: forall model action.
Eq model =>
Events -> App model action -> IO ()
startApp Events
events App model action
vcomp = IO (ComponentState ROOT model action) -> IO ()
forall a. IO a -> IO ()
withJS (Events -> App model action -> IO (ComponentState ROOT model action)
forall parent model action.
(Eq parent, Eq model) =>
Events
-> Component parent model action
-> IO (ComponentState parent model action)
initComponent Events
events App model action
vcomp)
-----------------------------------------------------------------------------
-- | Alias for 'Miso.miso'.
(🍜) :: Eq model => Events -> (URI -> App model action) -> IO ()
🍜 :: forall model action.
Eq model =>
Events -> (URI -> App model action) -> IO ()
(🍜) = Events -> (URI -> App model action) -> IO ()
forall model action.
Eq model =>
Events -> (URI -> App model action) -> IO ()
miso
----------------------------------------------------------------------------
-- | Runs a 'miso' application, but with a custom rendering engine.
--
-- The 'MisoString' specified here is the variable name of a globally-scoped
-- JS object that implements the context interface per @ts\/miso\/context\/dom.ts@
-- This is necessary for native support.
--
-- To get an IO action that starts the application, use 'run' on the result of this function.
--
-- @
-- main :: IO ()
-- main = renderApp defaultEvents "my-context" app
-- @
renderApp
  :: Eq model
  => Events
  -> MisoString
  -- ^ Name of the JS object that contains the drawing context
  -> App model action
  -- ^ Component application
  -> IO ()
renderApp :: forall model action.
Eq model =>
Events -> MisoString -> App model action -> IO ()
renderApp Events
events MisoString
renderer App model action
vcomp =
  IO (ComponentState ROOT model action) -> IO ()
forall a. IO a -> IO ()
withJS (MisoString -> IO ()
FFI.setDrawingContext MisoString
renderer IO ()
-> IO (ComponentState ROOT model action)
-> IO (ComponentState ROOT model action)
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Events -> App model action -> IO (ComponentState ROOT model action)
forall parent model action.
(Eq parent, Eq model) =>
Events
-> Component parent model action
-> IO (ComponentState parent model action)
initComponent Events
events App model action
vcomp)
----------------------------------------------------------------------------
-- | Top-level t'Miso.Types.Component' initialization helper for 'renderApp'.
initComponent
  :: (Eq parent, Eq model)
  => Events
  -> Component parent model action
  -> IO (ComponentState parent model action)
initComponent :: forall parent model action.
(Eq parent, Eq model) =>
Events
-> Component parent model action
-> IO (ComponentState parent model action)
initComponent Events
events vcomp :: Component parent model action
vcomp@Component {model
Bool
[Binding parent model]
[JS]
[CSS]
[Sub action]
Maybe action
Maybe (IO model)
Maybe MisoString
LogLevel
model -> View model action
action -> Effect parent model action
Value -> Maybe action
model :: model
hydrateModel :: Maybe (IO model)
update :: action -> Effect parent model action
view :: model -> View model action
subs :: [Sub action]
styles :: [CSS]
scripts :: [JS]
mountPoint :: Maybe MisoString
logLevel :: LogLevel
mailbox :: Value -> Maybe action
bindings :: [Binding parent model]
eventPropagation :: Bool
mount :: Maybe action
unmount :: Maybe action
unmount :: forall parent model action.
Component parent model action -> Maybe action
mount :: forall parent model action.
Component parent model action -> Maybe action
eventPropagation :: forall parent model action. Component parent model action -> Bool
bindings :: forall parent model action.
Component parent model action -> [Binding parent model]
mailbox :: forall parent model action.
Component parent model action -> Value -> Maybe action
logLevel :: forall parent model action.
Component parent model action -> LogLevel
mountPoint :: forall parent model action.
Component parent model action -> Maybe MisoString
scripts :: forall parent model action. Component parent model action -> [JS]
styles :: forall parent model action. Component parent model action -> [CSS]
subs :: forall parent model action.
Component parent model action -> [Sub action]
view :: forall parent model action.
Component parent model action -> model -> View model action
update :: forall parent model action.
Component parent model action
-> action -> Effect parent model action
hydrateModel :: forall parent model action.
Component parent model action -> Maybe (IO model)
model :: forall parent model action. Component parent model action -> model
..} = do
  root <- MisoString -> IO JSVal
mountElement (Maybe MisoString -> MisoString
getMountPoint Maybe MisoString
mountPoint)
  initialize events rootComponentId Draw isRoot vcomp (pure root)
----------------------------------------------------------------------------
isRoot :: Bool
isRoot :: Bool
isRoot = Bool
True
----------------------------------------------------------------------------
#ifdef PRODUCTION
#define MISO_JS_PATH "js/miso.prod.js"
#else
#define MISO_JS_PATH "js/miso.js"
#endif
withJS :: IO a -> IO ()
withJS :: forall a. IO a -> IO ()
withJS IO a
action = IO a -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO a -> IO ()) -> IO a -> IO ()
forall a b. (a -> b) -> a -> b
$ do
#ifdef WASM
  $(evalFile MISO_JS_PATH)
#endif
  action
-----------------------------------------------------------------------------