packages feed

Shpadoinkle-backend-pardiff 0.1.0.1 → 0.2.0.0

raw patch · 4 files changed

+104/−68 lines, 4 filesdep +ghcjs-domdep +monad-controldep +transformers-basedep ~basedep ~randomdep ~thesePVP ok

version bump matches the API change (PVP)

Dependencies added: ghcjs-dom, monad-control, transformers-base

Dependency ranges changed: base, random, these

API changes (from Hackage documentation)

- Shpadoinkle.Backend.ParDiff: instance (Control.Monad.IO.Unlift.MonadUnliftIO m, Language.Javascript.JSaddle.Types.MonadJSM m, GHC.Classes.Eq a, GHC.Show.Show a, Shpadoinkle.Territory t) => Shpadoinkle.Backend (Shpadoinkle.Backend.ParDiff.ParDiffT t a) m a
- Shpadoinkle.Backend.ParDiff: instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Shpadoinkle.Backend.ParDiff.ParDiffT s model m)
- Shpadoinkle.Backend.ParDiff: instance Control.Monad.IO.Unlift.MonadUnliftIO m => Control.Monad.IO.Unlift.MonadUnliftIO (Shpadoinkle.Backend.ParDiff.ParDiffT s r m)
- Shpadoinkle.Backend.ParDiff: instance Control.Monad.Trans.Class.MonadTrans (Shpadoinkle.Backend.ParDiff.ParDiffT s model)
- Shpadoinkle.Backend.ParDiff: instance GHC.Base.Alternative m => GHC.Base.Alternative (Shpadoinkle.Backend.ParDiff.ParDiffT s model m)
- Shpadoinkle.Backend.ParDiff: instance GHC.Base.Applicative m => GHC.Base.Applicative (Shpadoinkle.Backend.ParDiff.ParDiffT s model m)
- Shpadoinkle.Backend.ParDiff: instance GHC.Base.Functor Shpadoinkle.Backend.ParDiff.ParVProp
- Shpadoinkle.Backend.ParDiff: instance GHC.Base.Functor m => GHC.Base.Functor (Shpadoinkle.Backend.ParDiff.ParDiffT s model m)
- Shpadoinkle.Backend.ParDiff: instance GHC.Base.Monad m => Control.Monad.Reader.Class.MonadReader (s model) (Shpadoinkle.Backend.ParDiff.ParDiffT s model m)
- Shpadoinkle.Backend.ParDiff: instance GHC.Base.Monad m => GHC.Base.Monad (Shpadoinkle.Backend.ParDiff.ParDiffT s model m)
- Shpadoinkle.Backend.ParDiff: instance Language.Javascript.JSaddle.Types.MonadJSM m => Language.Javascript.JSaddle.Types.MonadJSM (Shpadoinkle.Backend.ParDiff.ParDiffT s model m)
+ Shpadoinkle.Backend.ParDiff: instance (Control.Monad.IO.Unlift.MonadUnliftIO m, Language.Javascript.JSaddle.Types.MonadJSM m, GHC.Classes.Eq a, GHC.Show.Show a) => Shpadoinkle.Core.Backend (Shpadoinkle.Backend.ParDiff.ParDiffT a) m a
+ Shpadoinkle.Backend.ParDiff: instance Control.Monad.Base.MonadBase n m => Control.Monad.Base.MonadBase n (Shpadoinkle.Backend.ParDiff.ParDiffT model m)
+ Shpadoinkle.Backend.ParDiff: instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Shpadoinkle.Backend.ParDiff.ParDiffT model m)
+ Shpadoinkle.Backend.ParDiff: instance Control.Monad.IO.Unlift.MonadUnliftIO m => Control.Monad.IO.Unlift.MonadUnliftIO (Shpadoinkle.Backend.ParDiff.ParDiffT r m)
+ Shpadoinkle.Backend.ParDiff: instance Control.Monad.Trans.Class.MonadTrans (Shpadoinkle.Backend.ParDiff.ParDiffT model)
+ Shpadoinkle.Backend.ParDiff: instance Control.Monad.Trans.Control.MonadBaseControl n m => Control.Monad.Trans.Control.MonadBaseControl n (Shpadoinkle.Backend.ParDiff.ParDiffT model m)
+ Shpadoinkle.Backend.ParDiff: instance Control.Monad.Trans.Control.MonadTransControl (Shpadoinkle.Backend.ParDiff.ParDiffT model)
+ Shpadoinkle.Backend.ParDiff: instance GHC.Base.Alternative m => GHC.Base.Alternative (Shpadoinkle.Backend.ParDiff.ParDiffT model m)
+ Shpadoinkle.Backend.ParDiff: instance GHC.Base.Applicative m => GHC.Base.Applicative (Shpadoinkle.Backend.ParDiff.ParDiffT model m)
+ Shpadoinkle.Backend.ParDiff: instance GHC.Base.Functor m => GHC.Base.Functor (Shpadoinkle.Backend.ParDiff.ParDiffT model m)
+ Shpadoinkle.Backend.ParDiff: instance GHC.Base.Monad m => Control.Monad.Reader.Class.MonadReader (GHC.Conc.Sync.TVar model) (Shpadoinkle.Backend.ParDiff.ParDiffT model m)
+ Shpadoinkle.Backend.ParDiff: instance GHC.Base.Monad m => GHC.Base.Monad (Shpadoinkle.Backend.ParDiff.ParDiffT model m)
+ Shpadoinkle.Backend.ParDiff: instance Language.Javascript.JSaddle.Types.MonadJSM m => Language.Javascript.JSaddle.Types.MonadJSM (Shpadoinkle.Backend.ParDiff.ParDiffT model m)
- Shpadoinkle.Backend.ParDiff: ParDiffT :: ReaderT (s model) m a -> ParDiffT s model m a
+ Shpadoinkle.Backend.ParDiff: ParDiffT :: ReaderT (TVar model) m a -> ParDiffT model m a
- Shpadoinkle.Backend.ParDiff: [unParDiff] :: ParDiffT s model m a -> ReaderT (s model) m a
+ Shpadoinkle.Backend.ParDiff: [unParDiff] :: ParDiffT model m a -> ReaderT (TVar model) m a
- Shpadoinkle.Backend.ParDiff: newtype ParDiffT s model m a
+ Shpadoinkle.Backend.ParDiff: newtype ParDiffT model m a
- Shpadoinkle.Backend.ParDiff: runParDiff :: t model -> ParDiffT t model m ~> m
+ Shpadoinkle.Backend.ParDiff: runParDiff :: TVar model -> ParDiffT model m ~> m
- Shpadoinkle.Backend.ParDiff: stage :: FromJSVal b => MonadJSM m => ParDiffT s a m b
+ Shpadoinkle.Backend.ParDiff: stage :: FromJSVal b => MonadJSM m => ParDiffT a m b

Files

LICENSE view
@@ -1,26 +1,27 @@-Shpadoinkle ParDiff, I think I know exactly what it means-Copyright © 2019 Isaac Shpaira+Shpadoinkle ParDiff aka S11 ParDiff+Copyright © 2020 Isaac Shapira All rights reserved.  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:-1. Redistributions of source code must retain the above copyright-notice, this list of conditions and the following disclaimer.-2. Redistributions in binary form must reproduce the above copyright-notice, this list of conditions and the following disclaimer in the-documentation and/or other materials provided with the distribution.-3. Neither the name of the <`3:organization`> nor the-names of its contributors may be used to endorse or promote products-derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY <|2|> ''AS IS'' AND ANY-EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE-DISCLAIMED. IN NO EVENT SHALL <|2|> BE LIABLE FOR ANY-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+ * Redistributions of source code must retain the above copyright notice,+   this list of conditions and the following disclaimer.+ * Redistributions in binary form must reproduce the above copyright+   notice, this list of conditions and the following disclaimer in the+   documentation and/or other materials provided with the distribution.+ * Neither the name of Shpadoinkle nor the names of its contributors may be+   used to endorse or promote products derived from this software without+   specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+POSSIBILITY OF SUCH DAMAGE.
README.md view
@@ -1,6 +1,7 @@ # Shpadoinkle Backend ParDiff  [![Goldwater](https://gitlab.com/fresheyeball/Shpadoinkle/badges/master/pipeline.svg)](https://gitlab.com/fresheyeball/Shpadoinkle)+[![Haddock](https://img.shields.io/badge/haddock-master-informational)](https://shpadoinkle.org/backend-pardiff) [![BSD-3](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) [![built with nix](https://img.shields.io/badge/built%20with-nix-41439a)](https://builtwithnix.org) [![Hackage](https://img.shields.io/hackage/v/Shpadoinkle-backend-pardiff.svg)](https://hackage.haskell.org/package/Shpadoinkle-backend-pardiff)@@ -17,6 +18,6 @@ in a keyed fashion for all nodes, while not requiring additional memory or developer overhead.  The diffing itself is a lawful usage of `alignWith` from the `Data.These` package. By modeling-Html as an Alignable Functor, we get principled diffing with clear separation of concerns.+Html as an Alignable Functor, you get principled diffing with clear separation of concerns. -IO is done via JSaddle and works with both GHC and GHCjs.+IO is done using JSaddle, and works with both GHC and GHCjs.
Shpadoinkle-backend-pardiff.cabal view
@@ -4,12 +4,12 @@ -- -- see: https://github.com/sol/hpack ----- hash: 155c49d78360144d64f13cffb9b7fa4809906b5397bdc653a7a62767650db3c1+-- hash: 4bcd76a2e9419355d33aae706d474880945952e91a1f339a3389fac24504e3c6  name:           Shpadoinkle-backend-pardiff-version:        0.1.0.1+version:        0.2.0.0 synopsis:       A Virtual Dom in pure Haskell, based on Html as an Alignable Functor.-description:    Virtual Dom diffing in pure Haskell. The Diffing is a lawful usage of @alignWith@ from the @Data.These@ package. This implimentation stores a reference to the @RawNode@ for each node in the virtual tree, merging keyed and unkeyed virtual dom techniques.+description:    Virtual DOM diffing in pure Haskell. The diffing is a lawful usage of @alignWith@ from the @Data.These@ package. This implementation stores a reference to the @RawNode@ for each node in the virtual tree, merging keyed and unkeyed virtual DOM techniques. category:       Web author:         Isaac Shapira maintainer:     fresheyeball@protonmail.com@@ -34,18 +34,21 @@   ghc-options: -Wall -Wcompat -fwarn-redundant-constraints -fwarn-incomplete-uni-patterns -fwarn-tabs -fwarn-incomplete-record-updates -fwarn-identities   build-depends:       Shpadoinkle-    , base >=4.12.0 && <4.15+    , base >=4.12.0 && <4.16     , compactable >=0.1.2 && <0.2     , containers >=0.6.0 && <0.7     , file-embed >=0.0.11 && <0.1+    , ghcjs-dom >=0.9.4 && <0.20     , jsaddle >=0.9.7 && <0.20     , lens >=4.17.1 && <5.0+    , monad-control >=1.0.2 && <1.1     , mtl >=2.2.2 && <2.3     , neat-interpolation >=0.3.2 && <0.6-    , random >=1.1 && <1.2+    , random >=1.1 && <1.3     , semialign >=1 && <1.2     , text >=1.2.3 && <1.3-    , these >=1.0.1 && <1.1+    , these >=1 && <1.2+    , transformers-base >=0.4.5 && <0.5     , unliftio >=0.2.12 && <0.3     , uuid >=1.3.13 && <1.4   default-language: Haskell2010
Shpadoinkle/Backend/ParDiff.hs view
@@ -12,10 +12,12 @@ {-# LANGUAGE QuasiQuotes                #-} {-# LANGUAGE RankNTypes                 #-} {-# LANGUAGE ScopedTypeVariables        #-}+{-# LANGUAGE TupleSections              #-} {-# LANGUAGE TypeApplications           #-} {-# LANGUAGE TypeFamilies               #-} {-# LANGUAGE TypeOperators              #-} {-# LANGUAGE TypeSynonymInstances       #-}+{-# LANGUAGE UndecidableInstances       #-} {-# LANGUAGE ViewPatterns               #-} {-# OPTIONS_GHC -fno-warn-type-defaults #-} @@ -25,17 +27,17 @@   {-|-   This backend is to serve as a cannonical representation of a well-   behaved backend. Defining well behaved in the context of web development-   is rather difficult, and complex.+   This backend is to serve as a canonical representation of a well-behaved+   backend. Defining well-behaved in the context of web development+   is rather difficult and complex.     The rules of a backend are informal. Roughly, if we give the backend-   some Html, we expect it to update the dom at runtime in the way we expect.+   some Html, we expect it to update the DOM at runtime in the way we expect. -   Since this is cannonical, all other backends are expected to behave-   identically to this one. If differences exist they should be patched,-   so that we retain renderer polymorphism. Such that we can change out-   the renderer of our application, without updating the application logic+   Since this is canonical, all other backends are expected to behave+   identically to this one. If differences exist they should be patched+   so that we retain renderer polymorphism, such that we can change out+   the renderer of our application; without updating the application logic    with confidence it will behave as expected. -} @@ -50,7 +52,9 @@ import           Control.Applicative import           Control.Compactable import           Control.Lens+import           Control.Monad.Base import           Control.Monad.Reader+import           Control.Monad.Trans.Control import           Data.Align import           Data.Foldable import           Data.Kind@@ -63,7 +67,7 @@ import           Data.Traversable import           Data.UUID import           GHC.Generics-import           Language.Javascript.JSaddle hiding (( # ))+import           Language.Javascript.JSaddle hiding (JSM, MonadJSM, ( # )) import           NeatInterpolation import           System.Random import           UnliftIO@@ -74,24 +78,35 @@ default (Text)  -newtype ParDiffT s model m a = ParDiffT { unParDiff :: ReaderT (s model) m a }+newtype ParDiffT model m a = ParDiffT { unParDiff :: ReaderT (TVar model) m a }   deriving   ( Functor   , Applicative   , Alternative   , Monad   , MonadIO-  , MonadReader (s model)+  , MonadReader (TVar model)   , MonadTrans+  , MonadTransControl   )   #ifndef ghcjs_HOST_OS-deriving instance MonadJSM m => MonadJSM (ParDiffT s model m)+deriving instance MonadJSM m => MonadJSM (ParDiffT model m) #endif  -instance MonadUnliftIO m => MonadUnliftIO (ParDiffT s r m) where+instance MonadBase n m => MonadBase n (ParDiffT model m) where+  liftBase = liftBaseDefault+++instance MonadBaseControl n m => MonadBaseControl n (ParDiffT model m) where+  type StM (ParDiffT model m) a = ComposeSt (ParDiffT model) m a+  liftBaseWith = defaultLiftBaseWith+  restoreM = defaultRestoreM+++instance MonadUnliftIO m => MonadUnliftIO (ParDiffT r m) where   {-# INLINE askUnliftIO #-}   askUnliftIO = ParDiffT . ReaderT $ \r ->                 withUnliftIO $ \u ->@@ -103,7 +118,8 @@     inner (run' . flip runReaderT r . unParDiff)  -runParDiff :: t model -> ParDiffT t model m ~> m+-- | 'ParDiffT' is a @newtype@ of 'ReaderT', this is the 'runReaderT' equivalent.+runParDiff :: TVar model -> ParDiffT model m ~> m runParDiff t (ParDiffT r) = runReaderT r t  @@ -120,8 +136,8 @@     ParTextNode _ t   -> "ParTextNode _ " <> show t  -data ParVProp a = ParVText Text | ParVListen UUID (RawNode -> RawEvent -> JSM a) | ParVFlag Bool-  deriving (Functor, Generic)+data ParVProp a = ParVText Text | ParVListen UUID (RawNode -> RawEvent -> JSM (Continuation JSM a)) | ParVFlag Bool+  deriving (Generic)   instance Show (ParVProp a) where@@ -131,16 +147,17 @@     ParVFlag b     -> "ParVFlag " <> show b  -props :: Territory s => (m ~> JSM) -> s a -> Map Text (Prop (ParDiffT s a m) a) -> RawNode -> JSM ()+props :: Monad m => (m ~> JSM) -> TVar a -> Map Text (Prop (ParDiffT a m) a) -> RawNode -> JSM () props toJSM i ps (RawNode raw) = do   raw' <- makeObject raw   void . traverse (uncurry $ prop toJSM i raw') $ M.toList ps  -prop :: Territory s => (m ~> JSM) -> s a -> Object -> Text -> Prop (ParDiffT s a m) a -> JSM ()+prop :: Monad m => (m ~> JSM) -> TVar a -> Object -> Text -> Prop (ParDiffT a m) a -> JSM () prop toJSM i raw k = \case   PText t     -> setProp' raw k t-  PListener f -> setListener i (\x y -> toJSM . runParDiff i $ f x y) raw k+  PListener f -> setListener i (\x y -> hoist (toJSM . runParDiff i)+                                         <$> f x y) raw k   PFlag True  -> setProp' raw k =<< toJSVal True   PFlag False -> return () @@ -154,11 +171,13 @@   if b then return () else unsafeSetProp (toJSString k) t' raw'  -setListener :: Territory s => s a -> (RawNode -> RawEvent -> JSM a) -> Object -> Text -> JSM ()+setListener :: TVar a -> (RawNode -> RawEvent -> JSM (Continuation JSM a)) -> Object -> Text -> JSM () setListener i m o k = do   elm <- RawNode <$> toJSVal o   setProp' o ("on" <> k) . fun $ \_ _ -> \case-    e:_ -> writeUpdate i . const $ m elm (RawEvent e)+    e:_ -> do+      x <- m elm (RawEvent e)+      writeUpdate i x     _ -> return ()  @@ -184,17 +203,17 @@   return pn  -makeProp :: (m ~> JSM) -> t a -> Prop (ParDiffT t a m) a -> JSM (ParVProp a)+makeProp :: Monad m => (m ~> JSM) -> TVar a -> Prop (ParDiffT a m) a -> JSM (ParVProp a) makeProp toJSM i = \case   PText t     -> return $ ParVText t   PListener m -> do     u <- liftIO randomIO-    return . ParVListen u $ \x y -> toJSM . runParDiff i $ m x y+    return . ParVListen u $ \x y -> hoist (toJSM . runParDiff i) <$> m x y   PFlag b     -> return $ ParVFlag b  -setup' :: MonadJSM m => JSM () -> ParDiffT s a m ()-setup' cb = liftJSM $ do+setup' :: JSM () -> JSM ()+setup' cb = do   void $ eval @Text [text|       window.deleteProp = (k, obj) => {         delete obj[k]@@ -202,7 +221,7 @@       window.container = document.createElement('div')       document.body.appendChild(container)     |]-  liftJSM cb+  cb   voidJSM :: MonadJSM m => JSM a -> m ()@@ -218,8 +237,23 @@     _          -> voidJSM $ jsg2 "deleteProp" (toJSString k) obj'  -managePropertyState :: Territory s => MonadJSM m => s a -> Object -> Map Text (ParVProp a) -> Map Text (ParVProp a) -> m ()-managePropertyState i obj' old new' = void $+managePropertyState :: MonadJSM m => TVar a -> Object -> Map Text (ParVProp a) -> Map Text (ParVProp a) -> m ()+managePropertyState i obj' old new' = void $ do+  -- The following step may be necessary if the old DOM and the new VDOM both have checked == False+  -- but the user just checked this checkbox / radio button and the browser set its+  -- checked property to true without setting its checked attribute.+  -- As far as we know this issue only occurs with the checked property.+  -- As far as we know this issue only occurs with the value properties of input controls,+  -- which include but are not necessarily limited to:+  --  * The value properties of input, select, and textarea elements+  --  * The checked properties of input type={checkbox,radio} elements+  --  * The src properties of image elements+  --  * The files properties of file elements+  -- Of these properties, checked is the only one where we know that the absence of the attribute+  -- in both the old and new (V)DOMs is consistent with the property needing to be updated+  -- because the property was updated with the corresponding attribute being absent the whole time.+  maybe (return ()) (const . voidJSM $ setProp' obj' "checked" =<< toJSVal False)+    $ M.lookup "checked" new' >>= guard . (\case { ParVFlag False -> True; _ -> False })   M.toList (align old new') `for` \(k, x) -> case x of     -- only old had it, delete     This _                 -> case k of@@ -241,7 +275,7 @@     These (ParVFlag t)           (ParVFlag t')                 | t /= t' -> setFlag obj' k t'-    -- new listner, set+    -- new listener, set     That  (ParVListen _ h) -> voidJSM $ setListener i h obj' k     -- changed listener, set     These (ParVListen u _) (ParVListen u' h) | u /= u' -> voidJSM $ setListener i h obj' k@@ -255,8 +289,7 @@   => MonadJSM m #endif   => Show a-  => Territory s-  => RawNode -> [ParVNode a] -> [ParVNode a] -> ParDiffT s a m [ParVNode a]+  => RawNode -> [ParVNode a] -> [ParVNode a] -> ParDiffT a m [ParVNode a] patchChildren parent@(RawNode p) old new'' =   traverseMaybe (\case @@ -282,8 +315,7 @@   => MonadJSM m #endif   => Show a-  => Territory s-  => RawNode -> Maybe (ParVNode a) -> ParVNode a -> ParDiffT s a m (ParVNode a)+  => RawNode -> Maybe (ParVNode a) -> ParVNode a -> ParDiffT a m (ParVNode a) patch' parent old new' = do   i <- ask   case (old, new') of@@ -316,7 +348,7 @@       return $ ParNode raw name ps' cs''  -    -- node definately has changed+    -- node definitely has changed     (Just old', _) -> do        RawNode p <- return parent@@ -340,8 +372,7 @@   => MonadUnliftIO m   => Eq a   => Show a-  => Territory s-  => (m ~> JSM) -> Html (ParDiffT s a m) a -> ParDiffT s a m (ParVNode a)+  => (m ~> JSM) -> Html (ParDiffT a m) a -> ParDiffT a m (ParVNode a) interpret' toJSM = \case    TextNode t -> do@@ -378,13 +409,13 @@   ( MonadUnliftIO m   , MonadJSM m   , Eq a-  , Show a-  , Territory t ) => Backend (ParDiffT t a) m a where-  type VNode (ParDiffT t a) m = ParVNode a+  , Show a ) => Backend (ParDiffT a) m a where+  type VNode (ParDiffT a) m = ParVNode a   interpret = interpret'   setup = setup'   patch = patch'  -stage :: FromJSVal b => MonadJSM m => ParDiffT s a m b+-- | Get the DOM node produced by 'setup'.+stage :: FromJSVal b => MonadJSM m => ParDiffT a m b stage = liftJSM $ fromJSValUnchecked =<< jsg "container"