Skip to content

Commit

Permalink
Uses newtype for element to allow for event polymorphism (#10)
Browse files Browse the repository at this point in the history
* Works from newtype vocabulary with polymorphic types

* Adds polymorphic newtypes

* Adds polymorphic newtypes

Co-authored-by: Mike Solomon <mike@wavr.so>
  • Loading branch information
Mike Solomon and Mike Solomon authored Mar 31, 2022
1 parent f74ebbc commit 533ebcc
Show file tree
Hide file tree
Showing 27 changed files with 5,959 additions and 4,981 deletions.
16 changes: 9 additions & 7 deletions codegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,16 +86,18 @@ def print_(x): return o.append(x)
print_(f'''data {term}
{x}
:: forall dom engine
. Event (Attribute {term})
-> Array (Element_ dom engine)
-> Element_ dom engine
:: forall event payload
. IsEvent event
=> event (Attribute {term})
-> Array (Element event payload)
-> Element event payload
{x} = elementify "{astag(x)}"
{x}_
:: forall dom engine
. Array (Element_ dom engine)
-> Element_ dom engine
:: forall event payload
. IsEvent event
=> Array (Element event payload)
-> Element event payload
{x}_ = {x} empty
instance tagToDeku{term} :: TagToDeku "{astag(x)}" {term}
''')
Expand Down
4 changes: 3 additions & 1 deletion examples/docs/Component.purs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module Deku.Example.Docs.Component where

import Prelude

import Control.Plus (class Plus)
import Deku.Attribute (cb, (:=))
import Deku.Control (text_)
import Deku.Core (Element)
Expand All @@ -10,6 +11,7 @@ import Deku.Example.Docs.Types (Page(..))
import Deku.Example.Docs.Util (scrollToTop)
import Deku.Pursx (nut, (~~))
import Effect (Effect)
import FRP.Event (class IsEvent)
import Type.Proxy (Proxy(..))

px = Proxy :: Proxy """<div>
Expand Down Expand Up @@ -39,7 +41,7 @@ px = Proxy :: Proxy """<div>
<p>In this section, we built a simple component. In the next section, we'll recreate the exact same element using a different input syntax called <a ~next~ style="cursor:pointer;">Pursx</a>.</p>
</div>"""

components :: (Page -> Effect Unit) -> Element
components :: forall event payload. IsEvent event => Plus event => (Page -> Effect Unit) -> Element event payload
components dpage = px ~~
{ code: nut
( D.pre_ [D.code_
Expand Down
18 changes: 9 additions & 9 deletions examples/docs/Docs.purs
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,37 @@ module Deku.Example.Docs where
import Prelude

import Control.Alt ((<|>))
import Control.Plus (empty)
import Control.Plus (class Plus, empty)
import Data.Foldable (for_, oneOfMap)
import Data.Maybe (Maybe(..))
import Data.Tuple.Nested ((/\))
import Deku.Attribute (cb, (:=))
import Deku.Control (deku, flatten, text_)
import Deku.Core (Element_, Subgraph)
import Deku.Core (Element, Subgraph)
import Deku.DOM as D
import Deku.Example.Docs.Component as Component
import Deku.Example.Docs.Effects as Effects
import Deku.Example.Docs.Events as Events
import Deku.Example.Docs.HelloWorld as HelloWorld
import Deku.Example.Docs.Intro as Intro
import Deku.Example.Docs.Portals as Portals
import Deku.Example.Docs.Pursx1 as Pursx1
import Deku.Example.Docs.Pursx2 as Pursx2
import Deku.Example.Docs.Subgraphs as Subgraph
import Deku.Example.Docs.Portals as Portals
import Deku.Example.Docs.Types (Page(..))
import Deku.Interpret (FFIDOMSnapshot, effectfulDOMInterpret, makeFFIDOMSnapshot)
import Deku.Interpret (effectfulDOMInterpret, makeFFIDOMSnapshot)
import Deku.Subgraph (SubgraphAction(..), subgraph)
import Effect (Effect)
import FRP.Event (Event, create, keepLatest, mapAccum, subscribe)
import FRP.Event (class IsEvent, create, keepLatest, mapAccum, subscribe)
import Web.HTML (window)
import Web.HTML.HTMLDocument (body)
import Web.HTML.HTMLElement (toElement)
import Web.HTML.Window (document)

scene
:: (Page -> Effect Unit)
-> Event Page
-> Element_ FFIDOMSnapshot (Effect Unit)
:: forall event payload. IsEvent event => Plus event => (Page -> Effect Unit)
-> event Page
-> Element event payload
scene push event =
flatten [ D.div_
$ map
Expand Down Expand Up @@ -97,7 +97,7 @@ scene push event =

]
where
page :: (Page -> Effect Unit) -> Subgraph Page Unit Unit
page :: (Page -> Effect Unit) -> Subgraph Page Unit Unit event payload
page dpage Intro _ _ = Intro.intro dpage
page dpage HelloWorld _ _ = HelloWorld.helloWorld dpage
page dpage SimpleComponent _ _ = Component.components dpage
Expand Down
5 changes: 3 additions & 2 deletions examples/docs/Effects.purs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Prelude
import Affjax as AX
import Affjax.ResponseFormat as ResponseFormat
import Control.Alt ((<|>))
import Control.Plus (class Plus)
import Data.Argonaut.Core (stringifyWithIndent)
import Data.Either (Either(..), hush)
import Data.Filterable (filterMap, compact)
Expand All @@ -22,7 +23,7 @@ import Deku.Subgraph (SubgraphAction(..), (@@))
import Effect (Effect)
import Effect.Aff (launchAff_)
import Effect.Class (liftEffect)
import FRP.Event (mapAccum)
import FRP.Event (class IsEvent, mapAccum)
import Type.Proxy (Proxy(..))

data UIAction = Initial | Loading | Result String
Expand Down Expand Up @@ -74,7 +75,7 @@ px = Proxy :: Proxy """<div>
<p>It is also possible to handle events (and by extension effectful actions in events, like network calls) in Pursx. Let's see how in the <a ~next~ style="cursor:pointer;">second Pursx section</a>.</p>
</div>"""

effects :: (Page -> Effect Unit) -> Element
effects :: forall event payload. IsEvent event => Plus event => (Page -> Effect Unit) -> Element event payload
effects dpage = px ~~
{ code: nut (D.pre_ [D.code_ [text_ """module Main where
Expand Down
7 changes: 4 additions & 3 deletions examples/docs/Events.purs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module Deku.Example.Docs.Events where
import Prelude

import Control.Alt ((<|>))
import Control.Plus (class Plus)
import Data.Either (hush)
import Data.Filterable (compact, filter, filterMap)
import Data.Foldable (for_, oneOfMap)
Expand All @@ -17,7 +18,7 @@ import Deku.Example.Docs.Util (scrollToTop)
import Deku.Pursx (nut, (~~))
import Deku.Subgraph (SubgraphAction(..), (@@))
import Effect (Effect)
import FRP.Event (mapAccum)
import FRP.Event (class IsEvent, mapAccum)
import Type.Proxy (Proxy(..))
import Web.DOM.Element (fromEventTarget)
import Web.Event.Event (target)
Expand Down Expand Up @@ -52,7 +53,7 @@ px = Proxy :: Proxy
<p>In this section, saw how to react to events using the looping function in combination with change. In the next section, we'll use a similar mechanism to deal with arbitrary <a ~next~ style="cursor:pointer;">effects</a>.</p>
</div>"""

events :: (Page -> Effect Unit) -> Element
events :: forall event payload. IsEvent event => Plus event => (Page -> Effect Unit) -> Element event payload
events dpage = px ~~
{ code: nut
( D.pre_
Expand Down Expand Up @@ -91,7 +92,7 @@ main = UIShown 🚀 \push event ->
( (pure "Val: 0") <|>
( mapAccum (const $ \x -> (x + 1) /\ x)
(filter (eq ButtonClicked) event)
1
0
# map (append "Val: " <<< show)
)
)
Expand Down
20 changes: 10 additions & 10 deletions examples/docs/Examples/Portals.purs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import Data.Hashable (class Hashable, hash)
import Data.Tuple.Nested ((/\))
import Deku.Attribute (Attribute, cb, (:=))
import Deku.Control (flatten, text_)
import Deku.Core (Element_, Subgraph_)
import Deku.Core (Element, Subgraph)
import Deku.DOM as D
import Deku.Portal (GatewayToSubgraph, portal)
import Deku.Portal (portal)
import Deku.Subgraph (SubgraphAction(..), (@@))
import Deku.Toplevel ((🚀))
import Effect (Effect)
import FRP.Event (Event)
import FRP.Event (class IsEvent)

data UIEvents = UIShown | ButtonClicked | SliderMoved Number
derive instance Eq UIEvents
Expand All @@ -28,11 +28,11 @@ instance Hashable Sgs where
hash = show >>> hash

mySub
:: forall env push dom engine
. Event Boolean
-> (Event Boolean -> Element_ dom engine)
-> (Event Boolean -> Element_ dom engine)
-> Subgraph_ Sgs env push dom engine
:: forall env push event payload
. IsEvent event => event Boolean
-> (event Boolean -> Element event payload)
-> (event Boolean -> Element event payload)
-> Subgraph Sgs env push event payload
mySub event gateway0 gateway1 sg _ _ = D.div_
[ gateway0
( map
Expand All @@ -52,9 +52,9 @@ mySub event gateway0 gateway1 sg _ _ = D.div_
)
]

img0' :: Event (Attribute D.Img_)
img0' :: forall event. Applicative event => event (Attribute D.Img_)
img0' = pure $ D.Src := "https://picsum.photos/200"
img1' :: Event (Attribute D.Img_)
img1' :: forall event. Applicative event => event (Attribute D.Img_)
img1' = pure $ D.Src := "https://picsum.photos/300"

main :: Effect Unit
Expand Down
18 changes: 10 additions & 8 deletions examples/docs/Examples/Subgraphs.purs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module Deku.Examples.Docs.Examples.Subgraphs where
import Prelude

import Control.Alt ((<|>))
import Data.Filterable (compact, partitionMap)
import Data.Filterable (class Filterable, compact, partitionMap)
import Data.Hashable (class Hashable, hash)
import Data.Maybe (Maybe(..))
import Data.Tuple (snd)
Expand All @@ -15,10 +15,10 @@ import Deku.DOM as D
import Deku.Subgraph (SubgraphAction(..), (@@))
import Deku.Toplevel ((🚀))
import Effect (Effect)
import FRP.Event (Event, mapAccum)
import FRP.Event (class IsEvent, mapAccum)

data UIEvents = UIShown | ButtonClicked | SliderMoved Number
derive instance Eq UIEvents
data UIevents = UIShown | ButtonClicked | SliderMoved Number
derive instance Eq UIevents

data Sgs = Sg0 | Sg1
derive instance Eq Sgs
Expand All @@ -29,14 +29,17 @@ instance Show Sgs where
instance Hashable Sgs where
hash = show >>> hash

counter :: forall a. Event a Event Int
counter :: forall event a. IsEvent event => event a event Int
counter event = map snd $ mapAccum f event 0
where
f a b = (b + 1) /\ (a /\ b)

mySub
:: (Sgs -> Effect Unit)
-> Subgraph Sgs Unit Unit
:: forall event payload
. Filterable event
=> IsEvent event
=> (Sgs -> Effect Unit)
-> Subgraph Sgs Unit Unit event payload
mySub raise Sg0 push event =
let
{ left, right } = partitionMap identity event
Expand All @@ -52,7 +55,6 @@ mySub raise Sg0 push event =
[ text_ "Send to C" ]
, D.div_ [ text (map (append "C: " <<< show) (counter right)) ]
, D.hr_ []

]
]
mySub raise Sg1 push event =
Expand Down
11 changes: 8 additions & 3 deletions examples/docs/HelloWorld.purs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ module Deku.Example.Docs.HelloWorld where

import Prelude

import Control.Plus (class Plus)
import Deku.Attribute (cb, (:=))
import Deku.Control (text_)
import Deku.Core (Element)
import Deku.Core (Element, Element)
import Deku.DOM as D
import Deku.Example.Docs.Types (Page(..))
import Deku.Example.Docs.Util (scrollToTop)
import Deku.Pursx (nut, (~~))
import Effect (Effect)
import FRP.Event (class IsEvent)
import Type.Proxy (Proxy(..))

px = Proxy :: Proxy """<div>
Expand All @@ -36,7 +38,10 @@ px = Proxy :: Proxy """<div>
</div>"""


helloWorld :: (Page -> Effect Unit) -> Element
helloWorld :: forall event payload.
Plus event =>
IsEvent event =>
(Page -> Effect Unit) -> Element event payload
helloWorld dpage = px ~~
{ code: nut (D.pre_ [D.code_ [text_ """module Main where
Expand All @@ -47,7 +52,7 @@ import Deku.Toplevel ((🚀))
import Effect (Effect)
main :: Effect Unit
main = unit 🚀 \_ _ -> text_ "Hello world"""]])
main = unit 🚀 \_ _ -> text_ "Hello world""""]])
, result: nut (D.div_ [text_ "Hello world"])
, next: pure (D.OnClick := (cb (const $ dpage SimpleComponent *> scrollToTop)))
}
4 changes: 3 additions & 1 deletion examples/docs/Intro.purs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ module Deku.Example.Docs.Intro where

import Prelude

import Control.Plus (class Plus)
import Deku.Attribute (cb, (:=))
import Deku.Core (Element)
import Deku.DOM as D
import Deku.Example.Docs.Types (Page(..))
import Deku.Example.Docs.Util (scrollToTop)
import Deku.Pursx ((~~))
import Effect (Effect)
import FRP.Event (class IsEvent)
import Type.Proxy (Proxy(..))

px = Proxy :: Proxy """<div>
Expand All @@ -29,6 +31,6 @@ px = Proxy :: Proxy """<div>
<p>And now, without further ado, check out the <a ~next~ style="cursor:pointer;">hello world section</a>!</p>
</div>"""

intro :: (Page -> Effect Unit) -> Element
intro :: forall event payload. IsEvent event => Plus event => (Page -> Effect Unit) -> Element event payload
intro dpage = px ~~
{ next: pure (D.OnClick := (cb (const $ dpage HelloWorld *> scrollToTop))) }
Loading

0 comments on commit 533ebcc

Please sign in to comment.