create-foldkit-app 0.29.0 → 0.29.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/dist/templates/base/AGENTS.md +5 -112
  2. package/dist/templates/base/FOLDKIT.md +144 -0
  3. package/dist/templates/examples/api-cache/src/main.ts +36 -40
  4. package/dist/templates/examples/auth/src/main.ts +16 -15
  5. package/dist/templates/examples/auth/src/page/loggedIn/update.ts +10 -11
  6. package/dist/templates/examples/auth/src/page/loggedOut/page/login.ts +44 -55
  7. package/dist/templates/examples/auth/src/page/loggedOut/update.ts +8 -12
  8. package/dist/templates/examples/auth/src/update.ts +67 -73
  9. package/dist/templates/examples/canvas-art/src/main.ts +32 -31
  10. package/dist/templates/examples/charting/src/init.test.ts +6 -3
  11. package/dist/templates/examples/charting/src/init.ts +4 -4
  12. package/dist/templates/examples/charting/src/update.ts +34 -38
  13. package/dist/templates/examples/counter/src/main.ts +13 -13
  14. package/dist/templates/examples/counters/src/counter.ts +9 -8
  15. package/dist/templates/examples/counters/src/main.ts +20 -26
  16. package/dist/templates/examples/crash-view/src/main.ts +5 -3
  17. package/dist/templates/examples/embedding/src/main.ts +11 -9
  18. package/dist/templates/examples/form/src/main.ts +79 -89
  19. package/dist/templates/examples/generative-art/src/main.ts +6 -4
  20. package/dist/templates/examples/generative-art/src/update.ts +26 -23
  21. package/dist/templates/examples/interrupting-commands/src/main.ts +68 -66
  22. package/dist/templates/examples/job-application/src/main.ts +3 -4
  23. package/dist/templates/examples/job-application/src/step/attachments.ts +16 -19
  24. package/dist/templates/examples/job-application/src/step/coverLetter.ts +5 -5
  25. package/dist/templates/examples/job-application/src/step/education/education.ts +12 -17
  26. package/dist/templates/examples/job-application/src/step/education/entry.ts +29 -42
  27. package/dist/templates/examples/job-application/src/step/personalInfo.ts +35 -44
  28. package/dist/templates/examples/job-application/src/step/skills/entry.ts +15 -21
  29. package/dist/templates/examples/job-application/src/step/skills/skills.ts +12 -17
  30. package/dist/templates/examples/job-application/src/step/workHistory/entry.ts +41 -58
  31. package/dist/templates/examples/job-application/src/step/workHistory/workHistory.ts +12 -17
  32. package/dist/templates/examples/job-application/src/update.ts +26 -29
  33. package/dist/templates/examples/kanban/src/main.ts +3 -4
  34. package/dist/templates/examples/kanban/src/update.ts +31 -31
  35. package/dist/templates/examples/managed-resource-layer/src/main.ts +30 -34
  36. package/dist/templates/examples/map/src/main.ts +48 -56
  37. package/dist/templates/examples/pixel-art/src/comparison.bench.test.ts +34 -13
  38. package/dist/templates/examples/pixel-art/src/main.bench.ts +3 -3
  39. package/dist/templates/examples/pixel-art/src/main.ts +3 -4
  40. package/dist/templates/examples/pixel-art/src/update.ts +109 -100
  41. package/dist/templates/examples/query-sync/src/main.ts +27 -25
  42. package/dist/templates/examples/route-transitions/src/main.ts +46 -43
  43. package/dist/templates/examples/route-transitions/src/story.test.ts +11 -11
  44. package/dist/templates/examples/routing/src/main.ts +16 -14
  45. package/dist/templates/examples/routing/src/page/people.ts +23 -28
  46. package/dist/templates/examples/shopping-cart/src/main.ts +41 -42
  47. package/dist/templates/examples/shopping-cart/src/page/products.ts +28 -35
  48. package/dist/templates/examples/slow-warnings/src/main.ts +23 -32
  49. package/dist/templates/examples/snake/src/main.ts +135 -143
  50. package/dist/templates/examples/ssg/src/main.ts +20 -17
  51. package/dist/templates/examples/ssr/src/main.ts +20 -24
  52. package/dist/templates/examples/state-machine/src/main.ts +24 -11
  53. package/dist/templates/examples/state-machine/src/story.test.ts +2 -2
  54. package/dist/templates/examples/stopwatch/src/main.ts +42 -50
  55. package/dist/templates/examples/todo/src/main.ts +152 -160
  56. package/dist/templates/examples/ui-showcase/src/main.ts +53 -54
  57. package/dist/templates/examples/ui-showcase/src/scene.test.ts +2 -2
  58. package/dist/templates/examples/ui-showcase/src/story.test.ts +2 -2
  59. package/dist/templates/examples/ui-showcase/src/ui/init.ts +6 -7
  60. package/dist/templates/examples/ui-showcase/src/ui/update.ts +265 -336
  61. package/dist/templates/examples/view-transitions/src/main.ts +18 -17
  62. package/dist/templates/examples/weather/src/main.ts +33 -40
  63. package/dist/templates/examples/web-components/src/main.ts +14 -17
  64. package/dist/templates/examples/websocket-chat/src/main.ts +44 -50
  65. package/dist/templates/release.json +8 -8
  66. package/dist/templates/rendering/ssg/src/main.ts +20 -17
  67. package/dist/templates/rendering/ssr/src/main.ts +20 -24
  68. package/package.json +1 -1
@@ -1,17 +1,11 @@
1
1
  import { Match as M, Option } from 'effect'
2
- import { Command, Update } from 'foldkit'
2
+ import { Update } from 'foldkit'
3
3
  import { evo } from 'foldkit/struct'
4
4
 
5
5
  import { Message, OutMessage } from './message'
6
6
  import { Model } from './model'
7
7
  import * as Login from './page/login'
8
8
 
9
- type UpdateReturn = readonly [
10
- Model,
11
- ReadonlyArray<Command.Command<Message>>,
12
- Option.Option<OutMessage>,
13
- ]
14
-
15
9
  const foldLogin = Update.foldChild({
16
10
  update: Login.update,
17
11
  read: (model: Model) => Option.some(model.loginModel),
@@ -20,13 +14,15 @@ const foldLogin = Update.foldChild({
20
14
  toParentMessage: message => Message.GotLoginMessage({ message }),
21
15
  toParentOutMessage: M.type<Login.OutMessage>().pipe(
22
16
  M.tagsExhaustive({
23
- SucceededLogin: ({ session }) =>
24
- Option.some(OutMessage.SucceededLogin({ session })),
17
+ SucceededLogin: ({ session }) => OutMessage.SucceededLogin({ session }),
25
18
  }),
26
19
  ),
27
20
  })
28
21
 
29
22
  export const update = (model: Model, message: Message) =>
30
- Message.match<UpdateReturn>(message, {
31
- GotLoginMessage: ({ message }) => foldLogin(model, message),
32
- })
23
+ Message.match<Update.ReturnWithOutMessage<Model, Message, OutMessage>>(
24
+ message,
25
+ {
26
+ GotLoginMessage: ({ message }) => foldLogin(model, message),
27
+ },
28
+ )
@@ -51,7 +51,7 @@ const RedirectToHome = Command.define('RedirectToHome', {
51
51
  ),
52
52
  })
53
53
 
54
- type UpdateReturn = readonly [Model, ReadonlyArray<Command.Command<Message>>]
54
+ type UpdateReturn = Update.Return<Model, Message>
55
55
  const withUpdateReturn = M.withReturnType<UpdateReturn>()
56
56
 
57
57
  const foldLoggedOutOutMessage: (
@@ -61,10 +61,10 @@ const foldLoggedOutOutMessage: (
61
61
  M.tagsExhaustive({
62
62
  SucceededLogin:
63
63
  ({ session }) =>
64
- () => [
65
- LoggedIn.init(DashboardRoute(), session),
66
- [SaveSession({ session }), RedirectToDashboard()],
67
- ],
64
+ () => ({
65
+ model: LoggedIn.init(DashboardRoute(), session),
66
+ commands: [SaveSession({ session }), RedirectToDashboard()],
67
+ }),
68
68
  }),
69
69
  )
70
70
 
@@ -87,10 +87,10 @@ const foldLoggedInOutMessage: (
87
87
  ) => Update.Step<Model, Message> = M.type<LoggedIn.OutMessage>().pipe(
88
88
  M.withReturnType<Update.Step<Model, Message>>(),
89
89
  M.tagsExhaustive({
90
- RequestedLogout: () => () => [
91
- LoggedOut.init(HomeRoute()),
92
- [ClearSession(), RedirectToHome()],
93
- ],
90
+ RequestedLogout: () => () => ({
91
+ model: LoggedOut.init(HomeRoute()),
92
+ commands: [ClearSession(), RedirectToHome()],
93
+ }),
94
94
  }),
95
95
  )
96
96
 
@@ -108,72 +108,66 @@ const foldLoggedIn = Update.foldChild({
108
108
  foldOutMessage: foldLoggedInOutMessage,
109
109
  })
110
110
 
111
- export const update = (model: Model, message: Message): UpdateReturn =>
112
- M.value(message).pipe(
113
- withUpdateReturn,
114
- M.tags({
115
- ClickedLink: ({ request }) =>
116
- M.value(request).pipe(
117
- withUpdateReturn,
118
- M.tagsExhaustive({
119
- Internal: ({ url }) => [
120
- model,
121
- [NavigateInternal({ url: urlToString(url) })],
122
- ],
123
- External: ({ href }) => [model, [LoadExternal({ href })]],
111
+ export const update = (model: Model, message: Message) =>
112
+ Message.match<UpdateReturn>(message, {
113
+ ClickedLink: ({ request }) =>
114
+ M.value(request).pipe(
115
+ withUpdateReturn,
116
+ M.tagsExhaustive({
117
+ Internal: ({ url }) => ({
118
+ model,
119
+ commands: [NavigateInternal({ url: urlToString(url) })],
124
120
  }),
125
- ),
126
-
127
- ChangedUrl: ({ url }) => {
128
- const route = urlToAppRoute(url)
129
-
130
- return M.value(model).pipe(
131
- withUpdateReturn,
132
- M.tagsExhaustive({
133
- LoggedOut: loggedOutModel =>
134
- M.value(route).pipe(
135
- withUpdateReturn,
136
- M.tag('Home', 'Login', 'NotFound', route => [
137
- evo(loggedOutModel, { route: () => route }),
138
- [],
139
- ]),
140
- M.orElse(() => [model, [RedirectToLogin()]]),
141
- ),
142
-
143
- LoggedIn: loggedInModel =>
144
- M.value(route).pipe(
145
- withUpdateReturn,
146
- M.tag('Dashboard', 'Settings', 'NotFound', route => [
147
- evo(loggedInModel, { route: () => route }),
148
- [],
149
- ]),
150
- M.orElse(() => [model, [RedirectToDashboard()]]),
151
- ),
121
+ External: ({ href }) => ({
122
+ model,
123
+ commands: [LoadExternal({ href })],
152
124
  }),
153
- )
154
- },
155
-
156
- FailedSaveSession: ({ error }) => [
157
- model,
158
- [LogError({ entries: ['Failed to save session:', error] })],
159
- ],
125
+ }),
126
+ ),
127
+
128
+ ChangedUrl: ({ url }) => {
129
+ const route = urlToAppRoute(url)
130
+
131
+ return M.value(model).pipe(
132
+ withUpdateReturn,
133
+ M.tagsExhaustive({
134
+ LoggedOut: loggedOutModel =>
135
+ M.value(route).pipe(
136
+ withUpdateReturn,
137
+ M.tag('Home', 'Login', 'NotFound', route => ({
138
+ model: evo(loggedOutModel, { route: () => route }),
139
+ })),
140
+ M.orElse(() => ({ model, commands: [RedirectToLogin()] })),
141
+ ),
142
+
143
+ LoggedIn: loggedInModel =>
144
+ M.value(route).pipe(
145
+ withUpdateReturn,
146
+ M.tag('Dashboard', 'Settings', 'NotFound', route => ({
147
+ model: evo(loggedInModel, { route: () => route }),
148
+ })),
149
+ M.orElse(() => ({ model, commands: [RedirectToDashboard()] })),
150
+ ),
151
+ }),
152
+ )
153
+ },
154
+
155
+ FailedSaveSession: ({ error }) => ({
156
+ model,
157
+ commands: [LogError({ entries: ['Failed to save session:', error] })],
158
+ }),
160
159
 
161
- FailedClearSession: ({ error }) => [
162
- model,
163
- [LogError({ entries: ['Failed to clear session:', error] })],
164
- ],
160
+ FailedClearSession: ({ error }) => ({
161
+ model,
162
+ commands: [LogError({ entries: ['Failed to clear session:', error] })],
163
+ }),
165
164
 
166
- GotLoggedOutMessage: ({ message }) => foldLoggedOut(model, message),
165
+ GotLoggedOutMessage: ({ message }) => foldLoggedOut(model, message),
167
166
 
168
- GotLoggedInMessage: ({ message }) => foldLoggedIn(model, message),
169
- }),
170
- M.tag(
171
- 'CompletedNavigateInternal',
172
- 'CompletedLoadExternal',
173
- 'CompletedLogError',
174
- 'SucceededSaveSession',
175
- 'SucceededClearSession',
176
- () => [model, []],
177
- ),
178
- M.exhaustive,
179
- )
167
+ GotLoggedInMessage: ({ message }) => foldLoggedIn(model, message),
168
+ CompletedNavigateInternal: () => ({ model }),
169
+ CompletedLoadExternal: () => ({ model }),
170
+ CompletedLogError: () => ({ model }),
171
+ SucceededSaveSession: () => ({ model }),
172
+ SucceededClearSession: () => ({ model }),
173
+ })
@@ -7,7 +7,7 @@ import {
7
7
  Schema as S,
8
8
  pipe,
9
9
  } from 'effect'
10
- import { Canvas, Command, Runtime, Subscription } from 'foldkit'
10
+ import { Canvas, Command, Runtime, Subscription, type Update } from 'foldkit'
11
11
  import { Document, Html, HtmlBuilder } from 'foldkit/html'
12
12
  import { defineMessageUnion } from 'foldkit/message'
13
13
  import { evo } from 'foldkit/struct'
@@ -75,10 +75,9 @@ export type Message = typeof Message.Type
75
75
 
76
76
  // INIT
77
77
 
78
- export const init: Runtime.ApplicationInit<Model, Message> = () => [
79
- { balls: [], nextId: 0, isRunning: true },
80
- [],
81
- ]
78
+ export const init: Runtime.ApplicationInit<Model, Message> = () => ({
79
+ model: { balls: [], nextId: 0, isRunning: true },
80
+ })
82
81
 
83
82
  // COMMAND
84
83
 
@@ -131,37 +130,39 @@ const advanceBall =
131
130
  }
132
131
 
133
132
  export const update = (model: Model, message: Message) =>
134
- Message.match<readonly [Model, ReadonlyArray<Command.Command<Message>>]>(
135
- message,
136
- {
137
- TickedFrame: ({ deltaTime }) => [
138
- evo(model, {
139
- balls: Array.map(advanceBall(deltaTime / MS_PER_SECOND)),
140
- }),
141
- [],
142
- ],
133
+ Message.match<Update.Return<Model, Message>>(message, {
134
+ TickedFrame: ({ deltaTime }) => ({
135
+ model: evo(model, {
136
+ balls: Array.map(advanceBall(deltaTime / MS_PER_SECOND)),
137
+ }),
138
+ }),
143
139
 
144
- ClickedCanvas: ({ x, y }) => [model, [GenerateBall({ x, y })]],
140
+ ClickedCanvas: ({ x, y }) => ({
141
+ model,
142
+ commands: [GenerateBall({ x, y })],
143
+ }),
145
144
 
146
- CompletedGenerateBall: ({ x, y, vx, vy, radius, color }) => [
147
- evo(model, {
148
- balls: balls => [
149
- ...balls,
150
- { id: model.nextId, x, y, vx, vy, radius, color },
151
- ],
152
- nextId: Number.increment,
145
+ CompletedGenerateBall: ({ x, y, vx, vy, radius, color }) => ({
146
+ model: evo(model, {
147
+ balls: Array.append({
148
+ id: model.nextId,
149
+ x,
150
+ y,
151
+ vx,
152
+ vy,
153
+ radius,
154
+ color,
153
155
  }),
154
- [],
155
- ],
156
+ nextId: Number.increment,
157
+ }),
158
+ }),
156
159
 
157
- ClickedClear: () => [evo(model, { balls: () => [] }), []],
160
+ ClickedClear: () => ({ model: evo(model, { balls: () => [] }) }),
158
161
 
159
- ClickedTogglePlay: () => [
160
- evo(model, { isRunning: running => !running }),
161
- [],
162
- ],
163
- },
164
- )
162
+ ClickedTogglePlay: () => ({
163
+ model: evo(model, { isRunning: running => !running }),
164
+ }),
165
+ })
165
166
 
166
167
  // SUBSCRIPTION
167
168
 
@@ -5,10 +5,13 @@ import { FetchTelemetry } from './command'
5
5
  import { init } from './init'
6
6
 
7
7
  test('seeds loading state and queues a telemetry fetch', () => {
8
- const [model, commands] = init()
8
+ const init_ = init()
9
9
 
10
- expect(model.telemetry._tag).toBe('Loading')
10
+ expect(init_.model.telemetry._tag).toBe('Loading')
11
11
  expect(
12
- Array.some(commands, command => command.name === FetchTelemetry.name),
12
+ Array.some(
13
+ init_.commands ?? [],
14
+ command => command.name === FetchTelemetry.name,
15
+ ),
13
16
  ).toBe(true)
14
17
  })
@@ -12,8 +12,8 @@ import {
12
12
  PERIOD_RADIO_GROUP_ID,
13
13
  } from './radioGroups'
14
14
 
15
- export const init: Runtime.ApplicationInit<Model, Message> = () => [
16
- {
15
+ export const init: Runtime.ApplicationInit<Model, Message> = () => ({
16
+ model: {
17
17
  telemetry: TelemetryAsyncData.Loading(),
18
18
  chartMode: 'Adoption',
19
19
  chartModeRadioGroup: RadioGroup.init({ id: CHART_MODE_RADIO_GROUP_ID }),
@@ -25,5 +25,5 @@ export const init: Runtime.ApplicationInit<Model, Message> = () => [
25
25
  maybeChartError: Option.none(),
26
26
  maybeSelectedDatumId: Option.none(),
27
27
  },
28
- [FetchTelemetry()],
29
- ]
28
+ commands: [FetchTelemetry()],
29
+ })
@@ -14,7 +14,7 @@ import {
14
14
  PeriodRadioGroup,
15
15
  } from './radioGroups'
16
16
 
17
- type UpdateReturn = readonly [Model, ReadonlyArray<Command.Command<Message>>]
17
+ type UpdateReturn = Update.Return<Model, Message>
18
18
 
19
19
  const syncChart = (args: {
20
20
  maybeChartHostId: Model['maybeChartHostId']
@@ -43,11 +43,11 @@ const syncChart = (args: {
43
43
 
44
44
  const refetchTelemetry = (model: Model): UpdateReturn =>
45
45
  Option.match(AsyncData.revalidateOrLoad(model.telemetry), {
46
- onNone: () => [model, []],
47
- onSome: nextTelemetry => [
48
- evo(model, { telemetry: () => nextTelemetry }),
49
- [FetchTelemetry()],
50
- ],
46
+ onNone: () => ({ model }),
47
+ onSome: nextTelemetry => ({
48
+ model: evo(model, { telemetry: () => nextTelemetry }),
49
+ commands: [FetchTelemetry()],
50
+ }),
51
51
  })
52
52
 
53
53
  const selectedControl =
@@ -57,9 +57,9 @@ const selectedControl =
57
57
  evo(model, { maybeSelectedDatumId: () => Option.none() }),
58
58
  )
59
59
 
60
- return [
61
- nextModel,
62
- syncChart({
60
+ return {
61
+ model: nextModel,
62
+ commands: syncChart({
63
63
  maybeChartHostId: nextModel.maybeChartHostId,
64
64
  telemetry: nextModel.telemetry,
65
65
  chartMode: nextModel.chartMode,
@@ -67,7 +67,7 @@ const selectedControl =
67
67
  period: nextModel.period,
68
68
  maybeSelectedDatumId: nextModel.maybeSelectedDatumId,
69
69
  }),
70
- ]
70
+ }
71
71
  }
72
72
 
73
73
  const foldChartModeRadioGroupOutMessage = M.type<
@@ -141,11 +141,11 @@ export const update = (model: Model, message: Message) =>
141
141
 
142
142
  ClickedRetry: () => refetchTelemetry(model),
143
143
 
144
- ClickedChartDatum: ({ datumId }) => [
145
- evo(model, {
144
+ ClickedChartDatum: ({ datumId }) => ({
145
+ model: evo(model, {
146
146
  maybeSelectedDatumId: () => Option.some(datumId),
147
147
  }),
148
- syncChart({
148
+ commands: syncChart({
149
149
  maybeChartHostId: model.maybeChartHostId,
150
150
  telemetry: model.telemetry,
151
151
  chartMode: model.chartMode,
@@ -153,15 +153,15 @@ export const update = (model: Model, message: Message) =>
153
153
  period: model.period,
154
154
  maybeSelectedDatumId: Option.some(datumId),
155
155
  }),
156
- ],
156
+ }),
157
157
 
158
158
  SucceededFetchTelemetry: ({ telemetry }) => {
159
159
  const nextModel = evo(model, {
160
160
  telemetry: () => TelemetryAsyncData.Success({ data: telemetry }),
161
161
  })
162
- return [
163
- nextModel,
164
- syncChart({
162
+ return {
163
+ model: nextModel,
164
+ commands: syncChart({
165
165
  maybeChartHostId: nextModel.maybeChartHostId,
166
166
  telemetry: nextModel.telemetry,
167
167
  chartMode: nextModel.chartMode,
@@ -169,22 +169,21 @@ export const update = (model: Model, message: Message) =>
169
169
  period: nextModel.period,
170
170
  maybeSelectedDatumId: nextModel.maybeSelectedDatumId,
171
171
  }),
172
- ]
172
+ }
173
173
  },
174
174
 
175
- FailedFetchTelemetry: ({ error }) => [
176
- evo(model, {
175
+ FailedFetchTelemetry: ({ error }) => ({
176
+ model: evo(model, {
177
177
  telemetry: () => AsyncData.settle(model.telemetry, Result.fail(error)),
178
178
  }),
179
- [],
180
- ],
179
+ }),
181
180
 
182
- SucceededMountChart: ({ hostId }) => [
183
- evo(model, {
181
+ SucceededMountChart: ({ hostId }) => ({
182
+ model: evo(model, {
184
183
  maybeChartHostId: () => Option.some(hostId),
185
184
  maybeChartError: () => Option.none(),
186
185
  }),
187
- syncChart({
186
+ commands: syncChart({
188
187
  maybeChartHostId: Option.some(hostId),
189
188
  telemetry: model.telemetry,
190
189
  chartMode: model.chartMode,
@@ -192,26 +191,23 @@ export const update = (model: Model, message: Message) =>
192
191
  period: model.period,
193
192
  maybeSelectedDatumId: model.maybeSelectedDatumId,
194
193
  }),
195
- ],
194
+ }),
196
195
 
197
- FailedMountChart: ({ reason }) => [
198
- evo(model, {
196
+ FailedMountChart: ({ reason }) => ({
197
+ model: evo(model, {
199
198
  maybeChartError: () => Option.some(reason),
200
199
  }),
201
- [],
202
- ],
200
+ }),
203
201
 
204
- SucceededSyncChart: () => [
205
- evo(model, {
202
+ SucceededSyncChart: () => ({
203
+ model: evo(model, {
206
204
  maybeChartError: () => Option.none(),
207
205
  }),
208
- [],
209
- ],
206
+ }),
210
207
 
211
- FailedSyncChart: ({ reason }) => [
212
- evo(model, {
208
+ FailedSyncChart: ({ reason }) => ({
209
+ model: evo(model, {
213
210
  maybeChartError: () => Option.some(reason),
214
211
  }),
215
- [],
216
- ],
212
+ }),
217
213
  })
@@ -1,5 +1,5 @@
1
1
  import { Schema as S } from 'effect'
2
- import { Command, Runtime } from 'foldkit'
2
+ import { Runtime, type Update } from 'foldkit'
3
3
  import { Document, HtmlBuilder } from 'foldkit/html'
4
4
  import { defineMessageUnion } from 'foldkit/message'
5
5
  import { evo } from 'foldkit/struct'
@@ -23,21 +23,21 @@ export type Message = typeof Message.Type
23
23
  // UPDATE
24
24
 
25
25
  export const update = (model: Model, message: Message) =>
26
- Message.match<readonly [Model, ReadonlyArray<Command.Command<Message>>]>(
27
- message,
28
- {
29
- ClickedDecrement: () => [evo(model, { count: count => count - 1 }), []],
30
- ClickedIncrement: () => [evo(model, { count: count => count + 1 }), []],
31
- ClickedReset: () => [evo(model, { count: () => 0 }), []],
32
- },
33
- )
26
+ Message.match<Update.Return<Model, Message>>(message, {
27
+ ClickedDecrement: () => ({
28
+ model: evo(model, { count: count => count - 1 }),
29
+ }),
30
+ ClickedIncrement: () => ({
31
+ model: evo(model, { count: count => count + 1 }),
32
+ }),
33
+ ClickedReset: () => ({ model: evo(model, { count: () => 0 }) }),
34
+ })
34
35
 
35
36
  // INIT
36
37
 
37
- export const init: Runtime.ApplicationInit<Model, Message> = () => [
38
- { count: 0 },
39
- [],
40
- ]
38
+ export const init: Runtime.ApplicationInit<Model, Message> = () => ({
39
+ model: { count: 0 },
40
+ })
41
41
 
42
42
  // VIEW
43
43
 
@@ -1,5 +1,5 @@
1
1
  import { Schema as S } from 'effect'
2
- import { Command, Submodel } from 'foldkit'
2
+ import { Submodel, type Update } from 'foldkit'
3
3
  import { defineMessageUnion } from 'foldkit/message'
4
4
  import { evo } from 'foldkit/struct'
5
5
 
@@ -24,13 +24,14 @@ export type Message = typeof Message.Type
24
24
  // UPDATE
25
25
 
26
26
  export const update = (model: Model, message: Message) =>
27
- Message.match<readonly [Model, ReadonlyArray<Command.Command<Message>>]>(
28
- message,
29
- {
30
- ClickedDecrement: () => [evo(model, { count: count => count - 1 }), []],
31
- ClickedIncrement: () => [evo(model, { count: count => count + 1 }), []],
32
- },
33
- )
27
+ Message.match<Update.Return<Model, Message>>(message, {
28
+ ClickedDecrement: () => ({
29
+ model: evo(model, { count: count => count - 1 }),
30
+ }),
31
+ ClickedIncrement: () => ({
32
+ model: evo(model, { count: count => count + 1 }),
33
+ }),
34
+ })
34
35
 
35
36
  // VIEW
36
37
 
@@ -1,5 +1,5 @@
1
1
  import { Array, Option, Schema as S, pipe } from 'effect'
2
- import { Command, Runtime, Update } from 'foldkit'
2
+ import { Runtime, Update } from 'foldkit'
3
3
  import { Document, Html, HtmlBuilder } from 'foldkit/html'
4
4
  import { defineMessageUnion } from 'foldkit/message'
5
5
  import { evo } from 'foldkit/struct'
@@ -55,33 +55,28 @@ const foldCounter = (id: string) =>
55
55
  })
56
56
 
57
57
  export const update = (model: Model, message: Message) =>
58
- Message.match<readonly [Model, ReadonlyArray<Command.Command<Message>>]>(
59
- message,
60
- {
61
- ClickedAddRow: () => [
62
- evo(model, {
63
- rows: Array.append({
64
- id: `counter-${model.nextRowId}`,
65
- counter: Counter.init,
66
- }),
67
- nextRowId: nextRowId => nextRowId + 1,
68
- }),
69
- [],
70
- ],
71
- ClickedRemoveRow: ({ id }) => [
72
- evo(model, {
73
- rows: Array.filter(row => row.id !== id),
58
+ Message.match<Update.Return<Model, Message>>(message, {
59
+ ClickedAddRow: () => ({
60
+ model: evo(model, {
61
+ rows: Array.append({
62
+ id: `counter-${model.nextRowId}`,
63
+ counter: Counter.init,
74
64
  }),
75
- [],
76
- ],
77
- GotCounterMessage: ({ id, message }) => foldCounter(id)(model, message),
78
- },
79
- )
65
+ nextRowId: nextRowId => nextRowId + 1,
66
+ }),
67
+ }),
68
+ ClickedRemoveRow: ({ id }) => ({
69
+ model: evo(model, {
70
+ rows: Array.filter(row => row.id !== id),
71
+ }),
72
+ }),
73
+ GotCounterMessage: ({ id, message }) => foldCounter(id)(model, message),
74
+ })
80
75
 
81
76
  // INIT
82
77
 
83
- export const init: Runtime.ApplicationInit<Model, Message> = () => [
84
- {
78
+ export const init: Runtime.ApplicationInit<Model, Message> = () => ({
79
+ model: {
85
80
  rows: [
86
81
  { id: 'counter-0', counter: Counter.init },
87
82
  { id: 'counter-1', counter: Counter.init },
@@ -89,8 +84,7 @@ export const init: Runtime.ApplicationInit<Model, Message> = () => [
89
84
  ],
90
85
  nextRowId: 3,
91
86
  },
92
- [],
93
- ]
87
+ })
94
88
 
95
89
  // VIEW
96
90
 
@@ -1,5 +1,5 @@
1
1
  import { Schema } from 'effect'
2
- import { Command, Runtime } from 'foldkit'
2
+ import { Runtime, type Update } from 'foldkit'
3
3
  import { Document, HtmlBuilder } from 'foldkit/html'
4
4
  import { defineMessageUnion } from 'foldkit/message'
5
5
 
@@ -23,13 +23,15 @@ export type Message = typeof Message.Type
23
23
  export const update = (
24
24
  _model: Model,
25
25
  _message: Message,
26
- ): readonly [Model, ReadonlyArray<Command.Command<Message>>] => {
26
+ ): Update.Return<Model, Message> => {
27
27
  throw new Error('This is a simulated crash!')
28
28
  }
29
29
 
30
30
  // INIT
31
31
 
32
- export const init: Runtime.ApplicationInit<Model, Message> = () => [null, []]
32
+ export const init: Runtime.ApplicationInit<Model, Message> = () => ({
33
+ model: null,
34
+ })
33
35
 
34
36
  // VIEW
35
37