Skip to content

Commit 45eec96

Browse files
authored
New interface for external events (#41)
* Simplify example folders; add extra example; add clarification to documentation * Custom events instead of signals * Finish draft and fix tests * Updated examples * Split window and document events so names dont clash * add window focus * More window events * First half of documentation * Finish documentation * Add examples * Finish example * Rebased
1 parent 7c9f3fb commit 45eec96

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+2005
-1754
lines changed

README.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,16 @@ module Counter.Main where
2626
import Prelude
2727
2828
import Effect (Effect)
29-
import Flame (Html, QuerySelector(..))
30-
-- Update strategy for side effects free functions; see docs for other strategies
29+
import Flame (Html, QuerySelector(..), Subscription)
30+
-- Side effects free updating; see docs for other examples
3131
import Flame.Application.NoEffects as FAN
3232
import Flame.Html.Element as HE
3333
import Flame.Html.Attribute as HA
3434
3535
-- | The model represents the state of the app
3636
type Model = Int
3737
38-
-- | This datatype is used to signal events to `update`
38+
-- | Data type used to represent events
3939
data Message = Increment | Decrement
4040
4141
-- | Initial state of the app
@@ -56,12 +56,17 @@ view model = HE.main "main" [
5656
HE.button [HA.onClick Increment] "+"
5757
]
5858
59+
-- | Events that come from outside the `view`
60+
subscribe :: Array (Subscription Message)
61+
subscribe = []
62+
5963
-- | Mount the application on the given selector
6064
main :: Effect Unit
6165
main = FAN.mount_ (QuerySelector "body") {
6266
init,
67+
view,
6368
update,
64-
view
69+
subscribe
6570
}
6671
```
6772

bower.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
"purescript-web-html": "^2.0.0",
1717
"purescript-nullable": "^4.1.1",
1818
"purescript-aff": "^5.1.0",
19-
"purescript-signal": "^10.1.0",
2019
"purescript-foreign-object": "^2.0.1",
2120
"purescript-argonaut-generic": "^6.0.0",
2221
"purescript-argonaut-codecs": "^7.0.0"

docs/_config.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717
# Build settings
1818
markdown: kramdown
1919
highlighter: rouge
20-
plugins:
21-
- jekyll-feed
2220

2321
# Exclude from processing.
2422
# The following items will not be processed, by default. Create a custom list

docs/concepts.md

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,35 +7,42 @@ permalink: /concepts
77
## Main concepts
88

99
A Flame application consists of the following record
10+
1011
```haskell
1112
type Application model message = {
1213
init :: model,
1314
view :: model -> Html message,
14-
update :: model -> message -> model
15+
update :: model -> message -> model,
16+
subscribe :: Array (Subscription message)
1517
}
1618
```
1719
The type variable `model` refers to the state of the application. `message`, on the other hand, describes the kinds of events the application can handle.
1820

1921
### Application state
2022

2123
In the counter example we set our model as a simple type alias
24+
2225
```haskell
2326
type Model = Int
2427
```
28+
2529
that is, the state of our application is a single integer. In a real world application, the model will probably be something more interesting -- Flame makes no assumption about how it is structured.
2630

2731
With our model type declared, we can define the initial state of the application
32+
2833
```haskell
2934
init :: Model
3035
init = 0
3136
```
37+
3238
The first time the application is rendered, Flame calls the view function with `init`.
3339

3440
### Application markup
3541

36-
The `view` function maps the current state to markup. Whenever the model is updated, flame patches the DOM by calling `view` with the new state.
42+
The `view` function maps the current state to markup. Whenever the model is updated, Flame patches the DOM by calling `view` with the new state.
3743

3844
In the counter example, the view is defined as
45+
3946
```haskell
4047
view :: Model -> Html Message
4148
view model = HE.main "main" [
@@ -44,17 +51,21 @@ view model = HE.main "main" [
4451
HE.button [HA.onClick Increment] "+"
4552
]
4653
```
54+
4755
The `message`s raised on events are used to signal how the application state should be updated.
4856

4957
See [Defining views](views) for an in depth look at views.
5058

5159
### State updating
5260

5361
The `update` function handles events, returning an updated model. In a Flame application, we reify native events as a custom data type. In the counter example, we are interested in the following events:
62+
5463
```haskell
5564
data Message = Increment | Decrement
5665
```
66+
5767
and thus our update function looks like
68+
5869
```haskell
5970
update :: Model -> Message -> Model
6071
update model = case _ of
@@ -64,31 +75,34 @@ update model = case _ of
6475

6576
See [Handling events](events) for an in depth look at update strategies.
6677

67-
### External event handling
78+
### Subscriptions
79+
80+
Finally, we can specify events that come from outside of the `view` as an array to `subscribe`. Such events include `window`, `document` -- and even messages arbitrarily raised by user code. These messages will then be handled in the usual way by the `update` function.
6881

69-
Finally, mounting a Flame application record yields a [`Channel`](https://pursuit.purescript.org/packages/purescript-signal/10.1.0/docs/Signal.Channel), which can be fed messages from events outside of our view. This includes `window` or `document` events, such as resize or load, and custom events, all of which are then handled as usual by the application `update` function.
82+
In the counter example no external events are handled, so the subscription list is empty
7083

71-
In the counter example, no external events are handled, so we use the version of `mount` that discards the channel
7284
```haskell
73-
main :: Effect Unit
74-
main = FAN.mount_ "main" {
75-
...
85+
subscribe :: Array (Subscription Message)
86+
subscribe = []
7687
}
7788
```
7889

79-
See [Handling external events](events#handling-external-events) for an in depth look at external events.
90+
See [Handling external events](events#handling-external-events) for an in depth look at subscriptions.
8091

8192
### Rendering
8293

8394
Having all pieces put together, we can either render the application to the DOM, as in the case of the counter example
95+
8496
```haskell
8597
main :: Effect Unit
8698
main = FAN.mount_ (QuerySelector "body") {
8799
init,
100+
view,
88101
update,
89-
view
102+
subscribe
90103
}
91104
```
105+
92106
or as a `String` with `Flame.Renderer.String.render`, which can be used server-side.
93107

94108
See [Rendering the app](rendering) for an in depth look at rendering.

0 commit comments

Comments
 (0)