packages feed

glazier-react 0.4.0.0 → 0.5.0.0

raw patch · 7 files changed

+171/−133 lines, 7 filesdep ~disposablePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: disposable

API changes (from Hackage documentation)

- Glazier.React.Maker: mapAction :: (act -> act') -> Maker act a -> Maker act' a
- Glazier.React.Model: Design :: mdl -> pln -> Design mdl pln
- Glazier.React.Model: SuperModel :: Design mdl pln -> Frame mdl pln -> SuperModel mdl pln
- Glazier.React.Model: [_design] :: SuperModel mdl pln -> Design mdl pln
- Glazier.React.Model: class HasDesign c mdl pln | c -> mdl pln
- Glazier.React.Model: class (HasDesign c mdl pln, HasFrame c mdl pln) => HasSuperModel c mdl pln | c -> mdl pln
- Glazier.React.Model: data Design mdl pln
- Glazier.React.Model: data SuperModel mdl pln
- Glazier.React.Model: design :: HasDesign c mdl pln => Lens' c (Design mdl pln)
- Glazier.React.Model: instance (Control.Disposable.Disposing pln, Control.Disposable.Disposing mdl) => Control.Disposable.Disposing (Glazier.React.Model.Design mdl pln)
- Glazier.React.Model: instance Control.Disposable.Disposing (Glazier.React.Model.Design mdl pln) => Control.Disposable.Disposing (Glazier.React.Model.SuperModel mdl pln)
- Glazier.React.Model: instance GHC.Generics.Generic (Glazier.React.Model.Design mdl pln)
- Glazier.React.Model: instance GHC.Generics.Generic (Glazier.React.Model.SuperModel mdl pln)
- Glazier.React.Model: instance Glazier.React.Model.HasDesign (Glazier.React.Model.Design mdl pln) mdl pln
- Glazier.React.Model: instance Glazier.React.Model.HasDesign (Glazier.React.Model.SuperModel mdl pln) mdl pln
- Glazier.React.Model: instance Glazier.React.Model.HasFrame (Glazier.React.Model.SuperModel mdl pln) mdl pln
- Glazier.React.Model: instance Glazier.React.Model.HasModel (Glazier.React.Model.Design mdl pln) mdl
- Glazier.React.Model: instance Glazier.React.Model.HasModel (Glazier.React.Model.SuperModel mdl pln) mdl
- Glazier.React.Model: instance Glazier.React.Model.HasPlan (Glazier.React.Model.Design mdl pln) pln
- Glazier.React.Model: instance Glazier.React.Model.HasPlan (Glazier.React.Model.SuperModel mdl pln) pln
- Glazier.React.Model: instance Glazier.React.Model.HasSuperModel (Glazier.React.Model.SuperModel mdl pln) mdl pln
- Glazier.React.Model: superModel :: HasSuperModel c mdl pln => Lens' c (SuperModel mdl pln)
- Glazier.React.Widget: Widget :: (Frame m p -> F (Maker a) p) -> (WindowT (Design m p) (ReactMlT Identity) ()) -> (GadgetT a (SuperModel m p) Identity (DList c)) -> Widget c a m p
- Glazier.React.Widget: instance (Control.Disposable.Disposing m, Control.Disposable.Disposing p) => Glazier.React.Widget.IsWidget (Glazier.React.Widget.Widget c a m p)
- Glazier.React.Widget: mkSuperModel :: IsWidget w => w -> ModelOf w -> F (Maker (ActionOf w)) (SuperModel (ModelOf w) (PlanOf w))
+ Glazier.React.Maker: hoistWithAction :: (act -> act') -> F (Maker act) a -> F (Maker act') a
+ Glazier.React.Maker: withAction :: (act -> act') -> Maker act a -> Maker act' a
+ Glazier.React.Model: Gizmo :: Scene mdl pln -> Frame mdl pln -> Gizmo mdl pln
+ Glazier.React.Model: Scene :: mdl -> pln -> Scene mdl pln
+ Glazier.React.Model: [_scene] :: Gizmo mdl pln -> Scene mdl pln
+ Glazier.React.Model: class (HasScene c mdl pln, HasFrame c mdl pln) => HasGizmo c mdl pln | c -> mdl pln
+ Glazier.React.Model: class HasScene c mdl pln | c -> mdl pln
+ Glazier.React.Model: class ToOutline c o | c -> o
+ Glazier.React.Model: data Gizmo mdl pln
+ Glazier.React.Model: data Scene mdl pln
+ Glazier.React.Model: gizmo :: HasGizmo c mdl pln => Lens' c (Gizmo mdl pln)
+ Glazier.React.Model: instance (Control.Disposable.Disposing pln, Control.Disposable.Disposing mdl) => Control.Disposable.Disposing (Glazier.React.Model.Scene mdl pln)
+ Glazier.React.Model: instance Control.Disposable.Disposing (Glazier.React.Model.Scene mdl pln) => Control.Disposable.Disposing (Glazier.React.Model.Gizmo mdl pln)
+ Glazier.React.Model: instance GHC.Generics.Generic (Glazier.React.Model.Gizmo mdl pln)
+ Glazier.React.Model: instance GHC.Generics.Generic (Glazier.React.Model.Scene mdl pln)
+ Glazier.React.Model: instance Glazier.React.Model.HasFrame (Glazier.React.Model.Gizmo mdl pln) mdl pln
+ Glazier.React.Model: instance Glazier.React.Model.HasGizmo (Glazier.React.Model.Gizmo mdl pln) mdl pln
+ Glazier.React.Model: instance Glazier.React.Model.HasModel (Glazier.React.Model.Gizmo mdl pln) mdl
+ Glazier.React.Model: instance Glazier.React.Model.HasModel (Glazier.React.Model.Scene mdl pln) mdl
+ Glazier.React.Model: instance Glazier.React.Model.HasPlan (Glazier.React.Model.Gizmo mdl pln) pln
+ Glazier.React.Model: instance Glazier.React.Model.HasPlan (Glazier.React.Model.Scene mdl pln) pln
+ Glazier.React.Model: instance Glazier.React.Model.HasScene (Glazier.React.Model.Gizmo mdl pln) mdl pln
+ Glazier.React.Model: instance Glazier.React.Model.HasScene (Glazier.React.Model.Scene mdl pln) mdl pln
+ Glazier.React.Model: instance Glazier.React.Model.ToOutline mdl o => Glazier.React.Model.ToOutline (Glazier.React.Model.Gizmo mdl pln) o
+ Glazier.React.Model: instance Glazier.React.Model.ToOutline mdl ol => Glazier.React.Model.ToOutline (Glazier.React.Model.Scene mdl pln) ol
+ Glazier.React.Model: outline :: ToOutline c o => c -> o
+ Glazier.React.Model: scene :: HasScene c mdl pln => Lens' c (Scene mdl pln)
+ Glazier.React.Widget: [Widget] :: (Disposing m, Disposing p, ToOutline m o) => (o -> F (Maker a) m) -> (Frame m p -> F (Maker a) p) -> WindowT (Scene m p) (ReactMlT Identity) () -> GadgetT a (Gizmo m p) Identity (DList c) -> Widget c a o m p
+ Glazier.React.Widget: data WithGizmo
+ Glazier.React.Widget: data WithOutline
+ Glazier.React.Widget: instance (Control.Disposable.Disposing m, Control.Disposable.Disposing p, Glazier.React.Model.ToOutline m o) => Glazier.React.Widget.IsWidget (Glazier.React.Widget.Widget c a o m p)
+ Glazier.React.Widget: mkGizmo :: IsWidget w => w -> ModelOf w -> F (Maker (ActionOf w)) (Gizmo (ModelOf w) (PlanOf w))
+ Glazier.React.Widget: mkGizmo' :: IsWidget w => w -> OutlineOf w -> F (Maker (ActionOf w)) (Gizmo (ModelOf w) (PlanOf w))
+ Glazier.React.Widget: mkModel :: IsWidget w => w -> OutlineOf w -> F (Maker (ActionOf w)) (ModelOf w)
+ Glazier.React.Widget: type FrameOf w = Frame (ModelOf w) (PlanOf w)
+ Glazier.React.Widget: type GadgetOf w = GadgetT (ActionOf w) (GizmoOf w) Identity (DList (CommandOf w))
+ Glazier.React.Widget: type GizmoOf w = Gizmo (ModelOf w) (PlanOf w)
+ Glazier.React.Widget: type SceneOf w = Scene (ModelOf w) (PlanOf w)
+ Glazier.React.Widget: type WindowOf w = WindowT (SceneOf w) (ReactMlT Identity) ()
- Glazier.React.Command.Run: componentSetState :: HasSuperModel sm mdl pln => sm -> [Property] -> JSVal -> IO ()
+ Glazier.React.Command.Run: componentSetState :: HasGizmo giz mdl pln => giz -> [Property] -> JSVal -> IO ()
- Glazier.React.Maker: [MkRenderer] :: Frame mdl pln -> (JSVal -> WindowT (Design mdl pln) ReactMl ()) -> (Callback (JSVal -> IO JSVal) -> nxt) -> Maker act nxt
+ Glazier.React.Maker: [MkRenderer] :: Frame mdl pln -> (JSVal -> WindowT (Scene mdl pln) ReactMl ()) -> (Callback (JSVal -> IO JSVal) -> nxt) -> Maker act nxt
- Glazier.React.Maker: [PutFrame] :: Frame mdl pln -> Design mdl pln -> nxt -> Maker act nxt
+ Glazier.React.Maker: [PutFrame] :: Frame mdl pln -> Scene mdl pln -> nxt -> Maker act nxt
- Glazier.React.Maker: getComponent :: forall m_aq59 act_apP1. MonadFree (Maker act_apP1) m_aq59 => m_aq59 ReactComponent
+ Glazier.React.Maker: getComponent :: forall m_aqf7 act_apYZ. MonadFree (Maker act_apYZ) m_aqf7 => m_aqf7 ReactComponent
- Glazier.React.Maker: mkEmptyFrame :: forall (mdl_XpPh :: Type) (pln_XpPj :: Type) m_aq4X act_apP1. MonadFree (Maker act_apP1) m_aq4X => m_aq4X (Frame mdl_XpPh pln_XpPj)
+ Glazier.React.Maker: mkEmptyFrame :: forall (mdl_XpZf :: Type) (pln_XpZh :: Type) m_aqeV act_apYZ. MonadFree (Maker act_apYZ) m_aqeV => m_aqeV (Frame mdl_XpZf pln_XpZh)
- Glazier.React.Maker: mkHandler :: forall m_aq4T act_apP1. MonadFree (Maker act_apP1) m_aq4T => (JSVal -> MaybeT IO [act_apP1]) -> m_aq4T (Callback (JSVal -> IO ()))
+ Glazier.React.Maker: mkHandler :: forall m_aqeR act_apYZ. MonadFree (Maker act_apYZ) m_aqeR => (JSVal -> MaybeT IO [act_apYZ]) -> m_aqeR (Callback (JSVal -> IO ()))
- Glazier.React.Maker: mkKey :: forall m_aq5c act_apP1. MonadFree (Maker act_apP1) m_aq5c => m_aq5c JSString
+ Glazier.React.Maker: mkKey :: forall m_aqfa act_apYZ. MonadFree (Maker act_apYZ) m_aqfa => m_aqfa JSString
- Glazier.React.Maker: mkRenderer :: forall (mdl_XpPl :: Type) (pln_XpPn :: Type) m_aq50 act_apP1. MonadFree (Maker act_apP1) m_aq50 => Frame mdl_XpPl pln_XpPn -> (JSVal -> WindowT (Design mdl_XpPl pln_XpPn) ReactMl ()) -> m_aq50 (Callback (JSVal -> IO JSVal))
+ Glazier.React.Maker: mkRenderer :: forall (mdl_XpZj :: Type) (pln_XpZl :: Type) m_aqeY act_apYZ. MonadFree (Maker act_apYZ) m_aqeY => Frame mdl_XpZj pln_XpZl -> (JSVal -> WindowT (Scene mdl_XpZj pln_XpZl) ReactMl ()) -> m_aqeY (Callback (JSVal -> IO JSVal))
- Glazier.React.Maker: putFrame :: forall (mdl_XpPp :: Type) (pln_XpPr :: Type) m_aq55 act_apP1. MonadFree (Maker act_apP1) m_aq55 => Frame mdl_XpPp pln_XpPr -> Design mdl_XpPp pln_XpPr -> m_aq55 ()
+ Glazier.React.Maker: putFrame :: forall (mdl_XpZn :: Type) (pln_XpZp :: Type) m_aqf3 act_apYZ. MonadFree (Maker act_apYZ) m_aqf3 => Frame mdl_XpZn pln_XpZp -> Scene mdl_XpZn pln_XpZp -> m_aqf3 ()
- Glazier.React.Model: [_frame] :: SuperModel mdl pln -> Frame mdl pln
+ Glazier.React.Model: [_frame] :: Gizmo mdl pln -> Frame mdl pln
- Glazier.React.Model: [_model] :: Design mdl pln -> mdl
+ Glazier.React.Model: [_model] :: Scene mdl pln -> mdl
- Glazier.React.Model: [_plan] :: Design mdl pln -> pln
+ Glazier.React.Model: [_plan] :: Scene mdl pln -> pln
- Glazier.React.Model: type Frame mdl pln = MVar (Design mdl pln)
+ Glazier.React.Model: type Frame mdl pln = MVar (Scene mdl pln)
- Glazier.React.Widget: class (Disposing (ModelOf w), Disposing (PlanOf w)) => IsWidget w
+ Glazier.React.Widget: class (Disposing (ModelOf w), Disposing (PlanOf w), ToOutline (ModelOf w) (OutlineOf w)) => IsWidget w
- Glazier.React.Widget: data Widget c a m p
+ Glazier.React.Widget: data Widget c a o m p
- Glazier.React.Widget: gadget :: IsWidget w => w -> GadgetT (ActionOf w) (SuperModel (ModelOf w) (PlanOf w)) Identity (DList (CommandOf w))
+ Glazier.React.Widget: gadget :: IsWidget w => w -> GadgetT (ActionOf w) (Gizmo (ModelOf w) (PlanOf w)) Identity (DList (CommandOf w))
- Glazier.React.Widget: window :: IsWidget w => w -> WindowT (Design (ModelOf w) (PlanOf w)) (ReactMlT Identity) ()
+ Glazier.React.Widget: window :: IsWidget w => w -> WindowT (Scene (ModelOf w) (PlanOf w)) (ReactMlT Identity) ()

Files

README.md view
@@ -103,75 +103,71 @@ ## Modelling [`Glazier.React.Model`](https://github.com/louispan/glazier-react/blob/master/src/Glazier/React/Model.hs) contain many nuanced concepts of Model. +### Schema+The `Schema` is a template of the pure data for stateful logic (the nouns). It is parameterized by a type variable which specializes it to either an `Outline` or 'Model'.++### Outline+The `Outline` is the pure data for stateful logic (the nouns). It may contain 'Outline's of child widgets.+The `Outline` does not contain enough information for rendering the child widgets.+ ### Model-The `Model` is the pure data used for rendering and stateful logic (the nouns).-It may contain `SuperModel` (see below) of other widgets.+The `Model` is similar to `Outline`, except that it may also contain `Gizmos` of child widgets.+It may contain `Gizmo` (see below) of other widgets.+The `Model` contains enough information to render child widgets, but not this widget.  ### Plan The `Plan` contains the callbacks for integrating with React (the verbs). It also contains a javascript reference to the instance of shim component used for the widget. This reference is used to trigger rendering with  [`setState`](https://facebook.github.io/react/docs/react-component.html#setstate). -### Design-`Design` is basically a tuple of `Model` and `Plan`. It is a separate data type in order to generate convenient lenses to the fields.-`Design` is all that a `Window` needs to purely generate rendering instructions.+### Scene+`Scene` is basically a tuple of `Model` and `Plan`. It is a separate data type in order to generate convenient lenses to the fields.+`Scene` is all that a `Window` needs to purely generate rendering instructions.  ### Frame-`Frame` is a type synonym of `MVar Design`. It is a mutable holder of a copy of `Design`. This is so how the official state from Haskell is communicated to the React [`render`](https://facebook.github.io/react/docs/react-component.html#render) callback. The [`render`](https://facebook.github.io/react/docs/react-component.html#render) callback will read the latest copy of `Design` from the `MVar` and pass it to the widget `Window` for rendering.+`Frame` is a type synonym of `MVar Scene`. It is a mutable holder of a copy of `Scene`. This is so how the official state from Haskell is communicated to the React [`render`](https://facebook.github.io/react/docs/react-component.html#render) callback. The [`render`](https://facebook.github.io/react/docs/react-component.html#render) callback will read the latest copy of `Scene` from the `MVar` and pass it to the widget `Window` for rendering. -### SuperModel-`SuperModel` is basically a tuple of `Design` and `Frame`. It is a separate data type in order to generate convenient lenses to the fields.+### Gizmo+`Gizmo` is basically a tuple of `Scene` and `Frame`. It is a separate data type in order to generate convenient lenses to the fields. This contains everything a widget needs for rendering and state processing.-Most state processing is performed using the pure `Design`. The `Frame` is only used for the `RenderCommand`, to copy the latest `Design` into the `Frame` when re-rendering is required.+Most state processing is performed using the pure `Model`. The `Frame` is only used for the `RenderCommand`, to put the latest `Scene` into the `Frame` when re-rendering is required.  ## Maker `MVars` for `Frame`s and `Callback`s for `Plan`s may only be created in IO.  Using Free Monads, [`Glazier.React.Maker`](https://github.com/louispan/glazier-react/blob/master/src/Glazier/React/Maker.hs) provides a safe way to create them without allowing other arbitrary IO. -The `Maker` can also be used create the initial `SuperModel` state for the widgets.+The `Maker` can also be used create the initial `Gizmo` state for the widgets. The `Maker` DSL has an `action` type parameter which indicated the type of action that is dispatched by the widget. The `action` type can be mapped and hoisted to a larger `action` type, allow for embedding the smaller widget action in larger widget actions. -For example, the [TodoMVC application](https://github.com/louispan/glazier-react-examples/blob/32b5b077faa499e7501cb8e5417105b340de9ad3/examples/todo/haskell/app/Main.hs#L44) uses `Maker` to create the initial application `SuperModel` which involves making and hoisting the `SuperModel` of the input, list of todos widget, and footer widget.- ## Disposable GHCJS `Callback`s has resources that are not automatically collected by the garbage collector. `Callback`s need to be released manually. The [disposable](https://github.com/louispan/disposable) library provides a safe and easy way to convert the `Callback` into a storable `SomeDisposable` that can be queued up to be released after the next rendering frame. -[disposable](https://github.com/louispan/disposable) allows generic instances of `Disposing` to be easily created, which make it easy to create instances of `Disposing`-for a `Plan` of `Callback`s,  and therefore the parent container`Design`, `SuperModel`, and `Model` (which may contain other widget `SuperModel`s)+[disposable](https://github.com/louispan/disposable) allows generic instances of `Disposing` to be easily created, which make it easy to create instances of `Disposing` for a `Plan` of `Callback`s,  and therefore for the parent container `Scene`, `Gizmo`, and `Model` (which may contain other widget `Gizmo`s)  The [`List` widget](https://github.com/louispan/glazier-react-widget/blob/54a771f492b864ff422e31949284ea4b23aa02c6/src/Glazier/React/Widgets/List.hs#L181) shows how the disposables can be queued for destruction after the next rendered frame.  ## Widget A [`Glazier.React.Widget`](https://github.com/louispan/glazier-react/blob/master/src/Glazier/React/Widget.hs) is the combination of:-+The `Maker` instruction on how to create the `Model` of that widget from an `Outline`:+```+mkModel :: Outline -> F (Maker Action) Model+``` The `Maker` instruction on how to create the `Plan` of that widget: ``` mkPlan :: Frame Model Plan -> F (Maker Action) Plan ``` The rendering instructions for that widget: ```-window:: WindowT (Design Model Plan) (ReactMlT Identity) ()+window:: WindowT (Scene Model Plan) (ReactMlT Identity) () ``` The state changes from `Action` events: ```-gadget :: GadgetT Action (SuperModel Model Plan) Identity (DList Command)+gadget :: GadgetT Action (Gizmo Model Plan) Identity (DList Command) ```-This is everything you need in order to create, render and interact with a widget.+This is everything you need in order to serialize, deserialize, create, render and interact with a widget.  `Glazier.React.IsWidget` is a typeclass that provides handy XXXOf type functions to get to the type of `Command`, `Action`, `Model`, `Plan` of the Widget. It also ensures that the `Model` and `Plan` is an instance of `Disposing`. -```-instance (CD.Disposing m, CD.Disposing p) =>-         IsWidget (Widget c a m p) where-    type CommandOf (Widget c a m p) = c-    type ActionOf (Widget c a m p) = a-    type ModelOf (Widget c a m p) = m-    type PlanOf (Widget c a m p) = p-    mkPlan (Widget f _ _) = f-    window (Widget _ f _) = f-    gadget (Widget _ _ f) = f-``` -This is useful for creating widgets that is composed of other Widgets. For example:-The [List widget](https://github.com/louispan/glazier-react-widget/blob/54a771f492b864ff422e31949284ea4b23aa02c6/src/Glazier/React/Widgets/List.hs#L122) uses the IsWidget typeclass in order to ensure that the `itemWidget` can be disposed.+This is useful for creating widgets that is composed of other Widgets.  ## Widget best practices Please refer to [`glazier-react-widget`](https://github.com/louispan/glazier-react-widget) for documentation on the best practices for creating `Glazier.React.Widgets`
glazier-react.cabal view
@@ -1,5 +1,5 @@ name:                glazier-react-version:             0.4.0.0+version:             0.5.0.0 synopsis:            ReactJS binding using Glazier and Pipes.Fluid description:         ReactJS binding using Glazier and Pipes.Fluid, which is                      more functional and composable than Elm/Flux.@@ -32,7 +32,7 @@   build-depends:       base >= 4.7 && < 5                      , containers >= 0.5 && < 0.6                      , deepseq >= 1.4 && < 1.5-                     , disposable >= 0.2.0.3 && < 1+                     , disposable >= 0.2.0.4 && < 1                      , dlist >= 0.8 && < 0.9                      , free >= 4.12 && < 5                      , glazier >= 0.10 && < 1
src/Glazier/React/Command/Run.hs view
@@ -14,11 +14,11 @@ import qualified JavaScript.Extras as JE import qualified JavaScript.Object as JO -componentSetState :: R.HasSuperModel sm mdl pln => sm -> [JE.Property] -> J.JSVal -> IO ()-componentSetState sm props j = do-    let dsn = sm ^. R.design-        frm = sm ^. R.frame-    void $ swapMVar frm dsn+componentSetState :: R.HasGizmo giz mdl pln => giz -> [JE.Property] -> J.JSVal -> IO ()+componentSetState giz props j = do+    let scn = giz ^. R.scene+        frm = giz ^. R.frame+    void $ swapMVar frm scn     js_componentSetState (JE.fromProperties props) j  #ifdef __GHCJS__
src/Glazier/React/Maker.hs view
@@ -8,6 +8,7 @@ module Glazier.React.Maker where  import Control.Monad.Free.Class+import Control.Monad.Free.Church import Control.Monad.Free.TH import Control.Monad.Trans.Maybe import qualified GHCJS.Foreign.Callback as J@@ -30,12 +31,12 @@         -> Maker act nxt     MkRenderer         :: R.Frame mdl pln-        -> (J.JSVal -> G.WindowT (R.Design mdl pln) R.ReactMl ())+        -> (J.JSVal -> G.WindowT (R.Scene mdl pln) R.ReactMl ())         -> (J.Callback (J.JSVal -> IO J.JSVal) -> nxt)         -> Maker act nxt     PutFrame         :: R.Frame mdl pln-        -> R.Design mdl pln+        -> R.Scene mdl pln         -> nxt         -> Maker act nxt     GetComponent@@ -48,18 +49,21 @@ instance Functor (Maker act) where   fmap f (MkHandler handler g) = MkHandler handler (f . g)   fmap f (MkEmptyFrame g) = MkEmptyFrame (f . g)-  fmap f (MkRenderer ms render g) = MkRenderer ms render (f . g)-  fmap f (PutFrame frm dsn x) = PutFrame frm dsn (f x)+  fmap f (MkRenderer frm render g) = MkRenderer frm render (f . g)+  fmap f (PutFrame frm scn x) = PutFrame frm scn (f x)   fmap f (GetComponent g) = GetComponent (f . g)   fmap f (MkKey g) = MkKey (f . g)  makeFree ''Maker  -- | Allows changing the action type of Maker-mapAction :: (act -> act') -> Maker act a -> Maker act' a-mapAction f (MkHandler handler g) = MkHandler (\v -> fmap f <$> handler v) g-mapAction _ (MkEmptyFrame g) = MkEmptyFrame g-mapAction _ (MkRenderer ms render g) = MkRenderer ms render g-mapAction _ (PutFrame frm dsn x) = PutFrame frm dsn x-mapAction _ (GetComponent g) = GetComponent g-mapAction _ (MkKey g) = MkKey g+withAction :: (act -> act') -> Maker act a -> Maker act' a+withAction f (MkHandler handler g) = MkHandler (\v -> fmap f <$> handler v) g+withAction _ (MkEmptyFrame g) = MkEmptyFrame g+withAction _ (MkRenderer frm render g) = MkRenderer frm render g+withAction _ (PutFrame frm scn x) = PutFrame frm scn x+withAction _ (GetComponent g) = GetComponent g+withAction _ (MkKey g) = MkKey g++hoistWithAction :: (act -> act') -> F (Maker act) a -> F (Maker act') a+hoistWithAction f = hoistF (withAction f)
src/Glazier/React/Maker/Run.hs view
@@ -38,11 +38,11 @@  run _ _ _ (R.MkEmptyFrame g) = newEmptyMVar >>= g -run _ _ _ (R.MkRenderer ms render g) = J.syncCallback1' (onRender ms render') >>= g+run _ _ _ (R.MkRenderer frm render g) = J.syncCallback1' (onRender frm render') >>= g   where     render' v = hoist (hoist generalize) (render v) -run _ _ _ (R.PutFrame frm dsn g) = putMVar frm dsn >> g+run _ _ _ (R.PutFrame frm scn g) = putMVar frm scn >> g  run _ component _ (R.GetComponent g) = g component 
src/Glazier/React/Model.hs view
@@ -21,65 +21,85 @@ class HasModel c mdl | c -> mdl where     model :: Lens' c mdl +-- | Convert to the pure serializable model for saving and restoring+class ToOutline c o | c -> o where+    outline :: c -> o+ -- | A record of Model and Plan-data Design mdl pln = Design+data Scene mdl pln = Scene     { _model :: mdl     , _plan :: pln     } deriving (G.Generic) --- | All designs should be disposable to make it easier for cleanup of callbacks.-instance (CD.Disposing pln, CD.Disposing mdl) => CD.Disposing (Design mdl pln)+class HasScene c mdl pln | c -> mdl pln where+    scene :: Lens' c (Scene mdl pln) -instance HasPlan (Design mdl pln) pln where-    plan f (Design mdl pln) = fmap (\pln' -> Design mdl pln') (f pln)+instance HasScene (Scene mdl pln) mdl pln where+    scene = id+    {-# INLINE scene #-}++-- | All scenes should be disposable to make it easier for cleanup of callbacks.+instance (CD.Disposing pln, CD.Disposing mdl) => CD.Disposing (Scene mdl pln)++instance HasPlan (Scene mdl pln) pln where+    plan f (Scene mdl pln) = fmap (\pln' -> Scene mdl pln') (f pln)     {-# INLINE plan #-} -instance HasModel (Design mdl pln) mdl where-    model f (Design mdl pln) = fmap (\mdl' -> Design mdl' pln) (f mdl)+instance HasModel (Scene mdl pln) mdl where+    model f (Scene mdl pln) = fmap (\mdl' -> Scene mdl' pln) (f mdl)     {-# INLINE model #-} -class HasDesign c mdl pln | c -> mdl pln where-    design :: Lens' c (Design mdl pln)--instance HasDesign (Design mdl pln) mdl pln where-    design = id+-- | A Scene can be converted to Outline by using the Model+instance ToOutline mdl ol => ToOutline (Scene mdl pln) ol where+    outline = view (model . to outline)+    {-# INLINE outline #-} --- | Frame is a Mvar of Design. React rendering callback uses this MVar for rendering.-type Frame mdl pln = MVar (Design mdl pln)+-- | Frame is a Mvar of Scene. React rendering callback uses this MVar for rendering.+type Frame mdl pln = MVar (Scene mdl pln)  class HasFrame c mdl pln | c -> mdl pln where     frame :: Lens' c (Frame mdl pln)  instance HasFrame (Frame mdl pln) mdl pln where     frame = id+    {-# INLINE frame #-} --- | A record of Design and Frame.-data SuperModel mdl pln = SuperModel-    { _design :: Design mdl pln+-- | A record of Scene and Frame.+data Gizmo mdl pln = Gizmo+    { _scene :: Scene mdl pln     , _frame :: Frame mdl pln     } deriving (G.Generic)  -- | Undecidableinstances!--- But this is safe because Design is definitely smaller than SuperModel-instance CD.Disposing (Design mdl pln) => CD.Disposing (SuperModel mdl pln) where-    disposing s = CD.disposing $ s ^. design+-- But this is safe because Scene is definitely smaller than Gizmo+instance CD.Disposing (Scene mdl pln) => CD.Disposing (Gizmo mdl pln) where+    disposing s = CD.disposing $ s ^. scene+    {-# INLINE disposing #-} -class (HasDesign c mdl pln, HasFrame c mdl pln) => HasSuperModel c mdl pln | c -> mdl pln where-    superModel :: Lens' c (SuperModel mdl pln)+class (HasScene c mdl pln, HasFrame c mdl pln) => HasGizmo c mdl pln | c -> mdl pln where+    gizmo :: Lens' c (Gizmo mdl pln) -instance HasSuperModel (SuperModel mdl pln) mdl pln where-    superModel = id+instance HasGizmo (Gizmo mdl pln) mdl pln where+    gizmo = id+    {-# INLINE gizmo #-} -instance HasFrame (SuperModel mdl pln) mdl pln where-    frame f (SuperModel dsn frm) = fmap (\frm' -> SuperModel dsn frm') (f frm)+instance HasFrame (Gizmo mdl pln) mdl pln where+    frame f (Gizmo scn frm) = fmap (\frm' -> Gizmo scn frm') (f frm)     {-# INLINE frame #-} -instance HasDesign (SuperModel mdl pln) mdl pln where-    design f (SuperModel dsn frm) = fmap (\dsn' -> SuperModel dsn' frm) (f dsn)-    {-# INLINE design #-}+instance HasScene (Gizmo mdl pln) mdl pln where+    scene f (Gizmo scn frm) = fmap (\scn' -> Gizmo scn' frm) (f scn)+    {-# INLINE scene #-} -instance HasPlan (SuperModel mdl pln) pln where-    plan = design . plan+instance HasPlan (Gizmo mdl pln) pln where+    plan = scene . plan+    {-# INLINE plan #-} -instance HasModel (SuperModel mdl pln) mdl where-    model = design . model+instance HasModel (Gizmo mdl pln) mdl where+    model = scene . model+    {-# INLINE model #-}++-- | A Gizmo can be converted to Outline by using the Model+instance ToOutline mdl o => ToOutline (Gizmo mdl pln) o where+    outline = view (model . to outline)+    {-# INLINE outline #-}
src/Glazier/React/Widget.hs view
@@ -1,8 +1,8 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}  module Glazier.React.Widget where @@ -16,71 +16,89 @@ import qualified Glazier.React.Model as R  type family CommandOf w where-    CommandOf (Widget c a m p) = c+    CommandOf (Widget c a o m p) = c  type family ActionOf w where-    ActionOf (Widget c a m p) = a+    ActionOf (Widget c a o m p) = a +type family OutlineOf w where+    OutlineOf (Widget c a o m p) = o+ type family ModelOf w where-    ModelOf (Widget c a m p) = m+    ModelOf (Widget c a o m p) = m  type family PlanOf w where-    PlanOf (Widget c a m p) = p+    PlanOf (Widget c a o m p) = p --- | Undecidable instances! But this is safe because 'ModelOf w' and 'PlanOf w'--- is guaranteed to be smaller than closed type family 'DesignOf w'.-type family DesignOf w where-    DesignOf w = R.Design (ModelOf w) (PlanOf w)+type SceneOf w = R.Scene (ModelOf w) (PlanOf w) --- | Undecidable instances! But this is safe because 'ModelOf w' and 'PlanOf w'--- is guaranteed to be smaller than closed type family 'FrameOf w'.-type family FrameOf w where-    FrameOf w = R.Frame (ModelOf w) (PlanOf w)+type FrameOf w = R.Frame (ModelOf w) (PlanOf w) --- | Undecidable instances! But this is safe because 'ModelOf w' and 'PlanOf w'--- is guaranteed to be smaller than closed type family 'SuperModelOf w'.-type family SuperModelOf w where-    SuperModelOf w = R.SuperModel (ModelOf w) (PlanOf w)+type GizmoOf w = R.Gizmo (ModelOf w) (PlanOf w) +type WindowOf w = G.WindowT (SceneOf w) (R.ReactMlT Identity) ()++type GadgetOf w = G.GadgetT (ActionOf w) (GizmoOf w) Identity (D.DList (CommandOf w))++-- | tag used to choose Schema that contains Gizmos+data WithGizmo+-- | tag used to choose Schema that contains Outlines+data WithOutline++-- | You can't use type family as a type variable for a data type. The workaround is to use+-- a tag to choose between different type family functions.+-- ModelType takes a tag to choose between Gizmo or Outline.+-- This enables creating a @data@ type that can specialize to+-- using the tag.+type family SchemaType tag w where+    SchemaType WithGizmo w = GizmoOf w+    SchemaType WithOutline w = OutlineOf w+ -- | Record of functions for a widget. Contains everything you need to make the model, -- render, and run the event processing.-data Widget c a m p = Widget-    (R.Frame m p -> F (R.Maker a) p)-    (G.WindowT (R.Design m p) (R.ReactMlT Identity) ())-    (G.GadgetT a (R.SuperModel m p) Identity (D.DList c))+-- This is a GADT to enforce the Disposing and ToOutline constraints at the time+-- of creating the Widget record.+data Widget c a o m p where+    Widget+         :: (CD.Disposing m, CD.Disposing p, R.ToOutline m o)+         => (o -> F (R.Maker a) m)+         -> (R.Frame m p -> F (R.Maker a) p)+         -> G.WindowT (R.Scene m p) (R.ReactMlT Identity) ()+         -> G.GadgetT a (R.Gizmo m p) Identity (D.DList c)+         -> Widget c a o m p  -- | This typeclass is convenient as it carries the 'Disposing Model' and 'Disposing Plan' constraints -- and allows treating 'Widget c a m p' as a type 'w' class (CD.Disposing (ModelOf w)-      , CD.Disposing (PlanOf w)) => IsWidget w where+      , CD.Disposing (PlanOf w)+      , R.ToOutline (ModelOf w) (OutlineOf w)) => IsWidget w where+    -- | Make a Model from an Outline+    mkModel :: w -> OutlineOf w -> F (R.Maker (ActionOf w)) (ModelOf w)+    -- | Given an empty frame, make the Plan that uses the frame for rendering     mkPlan :: w -> R.Frame (ModelOf w) (PlanOf w) -> F (R.Maker (ActionOf w)) (PlanOf w)-    window :: w -> G.WindowT (R.Design (ModelOf w) (PlanOf w)) (R.ReactMlT Identity) ()-    gadget :: w -> G.GadgetT (ActionOf w) (R.SuperModel (ModelOf w) (PlanOf w)) Identity (D.DList (CommandOf w))--instance (CD.Disposing m, CD.Disposing p) => IsWidget (Widget c a m p) where-    mkPlan (Widget f _ _) = f-    window (Widget _ f _) = f-    gadget (Widget _ _ f) = f---- data Widget c a m p where---     Widget :: (CD.Disposing m, CD.Disposing p) =>---         (R.Frame m p -> F (R.Maker a) p)---         -> G.WindowT (R.Design m p) (R.ReactMlT Identity) ()---         -> G.GadgetT a (R.SuperModel m p) Identity (D.DList c)---         -> Widget c a m p---- mkPlan :: Widget c a m p -> R.Frame m p -> F (R.Maker a) p--- mkPlan (Widget f _ _) = f---- window :: Widget c a m p -> G.WindowT (R.Design m p) (R.ReactMlT Identity) ()--- window (Widget _ f _) = f+    -- | Rendering function that uses the Scene of Model and Plan+    window :: w -> G.WindowT (R.Scene (ModelOf w) (PlanOf w)) (R.ReactMlT Identity) ()+    -- | Update function that processes Action to update the Frame and Scene+    gadget :: w -> G.GadgetT (ActionOf w) (R.Gizmo (ModelOf w) (PlanOf w)) Identity (D.DList (CommandOf w)) --- gadget :: Widget c a m p -> G.GadgetT a (R.SuperModel m p) Identity (D.DList c)--- gadget (Widget _ _ f) = f+instance (CD.Disposing m, CD.Disposing p, R.ToOutline m o) => IsWidget (Widget c a o m p) where+    mkModel (Widget f _ _ _) = f+    mkPlan (Widget _ f _ _) = f+    window (Widget _ _ f _) = f+    gadget (Widget _ _ _ f) = f -mkSuperModel :: IsWidget w => w -> ModelOf w -> F (R.Maker (ActionOf w)) (R.SuperModel (ModelOf w) (PlanOf w))-mkSuperModel w mdl = do+-- | Make the required Frame and Plan for a Model+mkGizmo :: IsWidget w => w -> ModelOf w -> F (R.Maker (ActionOf w)) (R.Gizmo (ModelOf w) (PlanOf w))+mkGizmo w mdl = do     frm <- R.mkEmptyFrame-    dsn <- R.Design mdl <$> mkPlan w frm-    R.putFrame frm dsn-    pure (R.SuperModel dsn frm)+    scn <- R.Scene mdl <$> mkPlan w frm+    R.putFrame frm scn+    pure (R.Gizmo scn frm)++-- | Make the required Frame and Plan from an Outline+mkGizmo' ::+  IsWidget w =>+  w+  -> OutlineOf w+  -> F (R.Maker (ActionOf w)) (R.Gizmo (ModelOf w) (PlanOf w))+mkGizmo' w i = mkModel w i >>= mkGizmo w