packages feed

glazier-react-0.2.0.0: src/Glazier/React/Widget.hs

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}

module Glazier.React.Widget where

import Control.Concurrent.MVar
import qualified Control.Disposable as CD
import Control.Lens
import qualified GHC.Generics as G

class HasWidgetPlan c pln | c -> pln where
    widgetPlan :: Lens' c pln

class HasWidgetModel c mdl | c -> mdl where
    widgetModel :: Lens' c mdl

data Design mdl pln = Design
    { _widgetModel :: mdl
    , _widgetPlan :: pln
    } deriving (G.Generic)

instance (CD.Disposing pln, CD.Disposing mdl) => CD.Disposing (Design mdl pln)

instance HasWidgetPlan (Design mdl pln) pln where
    widgetPlan f (Design mdl pln) = fmap (\pln' -> Design mdl pln') (f pln)
    {-# INLINE widgetPlan #-}

instance HasWidgetModel (Design mdl pln) mdl where
    widgetModel f (Design mdl pln) = fmap (\mdl' -> Design mdl' pln) (f mdl)
    {-# INLINE widgetModel #-}

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

type Replica mdl pln = MVar (Design mdl pln)

class HasReplica c mdl pln | c -> mdl pln where
    replica :: Lens' c (Replica mdl pln)

instance HasReplica (Replica mdl pln) mdl pln where
    replica = id

data SuperModel mdl pln = SuperModel
    { _design :: Design mdl pln
    , _replica :: Replica mdl pln
    } deriving (G.Generic)

instance CD.Disposing (Design mdl pln) => CD.Disposing (SuperModel mdl pln) where
    disposing s = CD.disposing $ s ^. design

class (HasDesign c mdl pln, HasReplica c mdl pln) => HasSuperModel c mdl pln | c -> mdl pln where
    superModel :: Lens' c (SuperModel mdl pln)

instance HasSuperModel (SuperModel mdl pln) mdl pln where
    superModel = id

instance HasReplica (SuperModel mdl pln) mdl pln where
    replica f (SuperModel dsn rep) = fmap (\rep' -> SuperModel dsn rep') (f rep)
    {-# INLINE replica #-}

instance HasDesign (SuperModel mdl pln) mdl pln where
    design f (SuperModel dsn rep) = fmap (\dsn' -> SuperModel dsn' rep) (f dsn)
    {-# INLINE design #-}

class IsWidget w where
    -- The input to Gadget
    type WidgetAction w :: *

    -- The output of Gadget
    type WidgetCommand w :: *

    -- The pure model for state and rendering
    type WidgetModel w :: *

    -- Callbacks and data required for interfacing with react.
    type WidgetPlan w :: *

type WidgetDesign w = Design (WidgetModel w) (WidgetPlan w)
type WidgetReplica w = Replica (WidgetModel w) (WidgetPlan w)
type WidgetSuperModel w = SuperModel (WidgetModel w) (WidgetPlan w)