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.
- package/dist/templates/base/AGENTS.md +5 -112
- package/dist/templates/base/FOLDKIT.md +144 -0
- package/dist/templates/examples/api-cache/src/main.ts +36 -40
- package/dist/templates/examples/auth/src/main.ts +16 -15
- package/dist/templates/examples/auth/src/page/loggedIn/update.ts +10 -11
- package/dist/templates/examples/auth/src/page/loggedOut/page/login.ts +44 -55
- package/dist/templates/examples/auth/src/page/loggedOut/update.ts +8 -12
- package/dist/templates/examples/auth/src/update.ts +67 -73
- package/dist/templates/examples/canvas-art/src/main.ts +32 -31
- package/dist/templates/examples/charting/src/init.test.ts +6 -3
- package/dist/templates/examples/charting/src/init.ts +4 -4
- package/dist/templates/examples/charting/src/update.ts +34 -38
- package/dist/templates/examples/counter/src/main.ts +13 -13
- package/dist/templates/examples/counters/src/counter.ts +9 -8
- package/dist/templates/examples/counters/src/main.ts +20 -26
- package/dist/templates/examples/crash-view/src/main.ts +5 -3
- package/dist/templates/examples/embedding/src/main.ts +11 -9
- package/dist/templates/examples/form/src/main.ts +79 -89
- package/dist/templates/examples/generative-art/src/main.ts +6 -4
- package/dist/templates/examples/generative-art/src/update.ts +26 -23
- package/dist/templates/examples/interrupting-commands/src/main.ts +68 -66
- package/dist/templates/examples/job-application/src/main.ts +3 -4
- package/dist/templates/examples/job-application/src/step/attachments.ts +16 -19
- package/dist/templates/examples/job-application/src/step/coverLetter.ts +5 -5
- package/dist/templates/examples/job-application/src/step/education/education.ts +12 -17
- package/dist/templates/examples/job-application/src/step/education/entry.ts +29 -42
- package/dist/templates/examples/job-application/src/step/personalInfo.ts +35 -44
- package/dist/templates/examples/job-application/src/step/skills/entry.ts +15 -21
- package/dist/templates/examples/job-application/src/step/skills/skills.ts +12 -17
- package/dist/templates/examples/job-application/src/step/workHistory/entry.ts +41 -58
- package/dist/templates/examples/job-application/src/step/workHistory/workHistory.ts +12 -17
- package/dist/templates/examples/job-application/src/update.ts +26 -29
- package/dist/templates/examples/kanban/src/main.ts +3 -4
- package/dist/templates/examples/kanban/src/update.ts +31 -31
- package/dist/templates/examples/managed-resource-layer/src/main.ts +30 -34
- package/dist/templates/examples/map/src/main.ts +48 -56
- package/dist/templates/examples/pixel-art/src/comparison.bench.test.ts +34 -13
- package/dist/templates/examples/pixel-art/src/main.bench.ts +3 -3
- package/dist/templates/examples/pixel-art/src/main.ts +3 -4
- package/dist/templates/examples/pixel-art/src/update.ts +109 -100
- package/dist/templates/examples/query-sync/src/main.ts +27 -25
- package/dist/templates/examples/route-transitions/src/main.ts +46 -43
- package/dist/templates/examples/route-transitions/src/story.test.ts +11 -11
- package/dist/templates/examples/routing/src/main.ts +16 -14
- package/dist/templates/examples/routing/src/page/people.ts +23 -28
- package/dist/templates/examples/shopping-cart/src/main.ts +41 -42
- package/dist/templates/examples/shopping-cart/src/page/products.ts +28 -35
- package/dist/templates/examples/slow-warnings/src/main.ts +23 -32
- package/dist/templates/examples/snake/src/main.ts +135 -143
- package/dist/templates/examples/ssg/src/main.ts +20 -17
- package/dist/templates/examples/ssr/src/main.ts +20 -24
- package/dist/templates/examples/state-machine/src/main.ts +24 -11
- package/dist/templates/examples/state-machine/src/story.test.ts +2 -2
- package/dist/templates/examples/stopwatch/src/main.ts +42 -50
- package/dist/templates/examples/todo/src/main.ts +152 -160
- package/dist/templates/examples/ui-showcase/src/main.ts +53 -54
- package/dist/templates/examples/ui-showcase/src/scene.test.ts +2 -2
- package/dist/templates/examples/ui-showcase/src/story.test.ts +2 -2
- package/dist/templates/examples/ui-showcase/src/ui/init.ts +6 -7
- package/dist/templates/examples/ui-showcase/src/ui/update.ts +265 -336
- package/dist/templates/examples/view-transitions/src/main.ts +18 -17
- package/dist/templates/examples/weather/src/main.ts +33 -40
- package/dist/templates/examples/web-components/src/main.ts +14 -17
- package/dist/templates/examples/websocket-chat/src/main.ts +44 -50
- package/dist/templates/release.json +8 -8
- package/dist/templates/rendering/ssg/src/main.ts +20 -17
- package/dist/templates/rendering/ssr/src/main.ts +20 -24
- package/package.json +1 -1
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
Stream,
|
|
8
8
|
pipe,
|
|
9
9
|
} from 'effect'
|
|
10
|
-
import {
|
|
10
|
+
import { Runtime, Subscription, type Update } from 'foldkit'
|
|
11
11
|
import { type Document, type Html, HtmlBuilder, createLazy } from 'foldkit/html'
|
|
12
12
|
import { defineMessageUnion } from 'foldkit/message'
|
|
13
13
|
import { evo } from 'foldkit/struct'
|
|
@@ -160,76 +160,67 @@ const prependWarning =
|
|
|
160
160
|
(warnings: ReadonlyArray<SlowWarning>): ReadonlyArray<SlowWarning> =>
|
|
161
161
|
pipe(warnings, Array.prepend(warning), Array.take(MAX_WARNING_COUNT))
|
|
162
162
|
|
|
163
|
-
type UpdateReturn = readonly [Model, ReadonlyArray<Command.Command<Message>>]
|
|
164
|
-
|
|
165
163
|
export const update = (model: Model, message: Message) =>
|
|
166
|
-
Message.match<
|
|
164
|
+
Message.match<Update.Return<Model, Message>>(message, {
|
|
167
165
|
ClickedRunUpdateWork: () => {
|
|
168
166
|
burnCpu(UPDATE_WORK_MS)
|
|
169
167
|
|
|
170
|
-
return
|
|
171
|
-
evo(model, {
|
|
168
|
+
return {
|
|
169
|
+
model: evo(model, {
|
|
172
170
|
activeWorkload: () => 'Update',
|
|
173
171
|
}),
|
|
174
|
-
|
|
175
|
-
]
|
|
172
|
+
}
|
|
176
173
|
},
|
|
177
|
-
ClickedRunViewWork: () =>
|
|
178
|
-
evo(model, {
|
|
174
|
+
ClickedRunViewWork: () => ({
|
|
175
|
+
model: evo(model, {
|
|
179
176
|
activeWorkload: () => 'View',
|
|
180
177
|
}),
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
evo(model, {
|
|
178
|
+
}),
|
|
179
|
+
ClickedRunPatchWork: () => ({
|
|
180
|
+
model: evo(model, {
|
|
185
181
|
activeWorkload: () => 'Patch',
|
|
186
182
|
patchRows: () => PATCH_ROW_COUNT,
|
|
187
183
|
patchRun: Number.increment,
|
|
188
184
|
}),
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
evo(model, {
|
|
185
|
+
}),
|
|
186
|
+
ClickedRunSubscriptionDependenciesWork: () => ({
|
|
187
|
+
model: evo(model, {
|
|
193
188
|
activeWorkload: () => 'SubscriptionDependencies',
|
|
194
189
|
}),
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
evo(model, {
|
|
190
|
+
}),
|
|
191
|
+
ClickedClearWarnings: () => ({
|
|
192
|
+
model: evo(model, {
|
|
199
193
|
activeWorkload: () => 'Idle',
|
|
200
194
|
warnings: () => [],
|
|
201
195
|
}),
|
|
202
|
-
|
|
203
|
-
],
|
|
196
|
+
}),
|
|
204
197
|
RecordedSlowWarning: ({ report }) => {
|
|
205
198
|
const warning: SlowWarning = {
|
|
206
199
|
id: model.nextWarningId,
|
|
207
200
|
...report,
|
|
208
201
|
}
|
|
209
202
|
|
|
210
|
-
return
|
|
211
|
-
evo(model, {
|
|
203
|
+
return {
|
|
204
|
+
model: evo(model, {
|
|
212
205
|
activeWorkload: () => 'Idle',
|
|
213
206
|
nextWarningId: Number.increment,
|
|
214
207
|
warnings: prependWarning(warning),
|
|
215
208
|
}),
|
|
216
|
-
|
|
217
|
-
]
|
|
209
|
+
}
|
|
218
210
|
},
|
|
219
211
|
})
|
|
220
212
|
|
|
221
213
|
// INIT
|
|
222
214
|
|
|
223
|
-
export const init: Runtime.ApplicationInit<Model, Message> = () =>
|
|
224
|
-
{
|
|
215
|
+
export const init: Runtime.ApplicationInit<Model, Message> = () => ({
|
|
216
|
+
model: {
|
|
225
217
|
activeWorkload: 'Idle',
|
|
226
218
|
nextWarningId: 1,
|
|
227
219
|
warnings: [],
|
|
228
220
|
patchRows: 0,
|
|
229
221
|
patchRun: 0,
|
|
230
222
|
},
|
|
231
|
-
|
|
232
|
-
]
|
|
223
|
+
})
|
|
233
224
|
|
|
234
225
|
// SUBSCRIPTION
|
|
235
226
|
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
Stream,
|
|
8
8
|
pipe,
|
|
9
9
|
} from 'effect'
|
|
10
|
-
import { Command, Runtime, Subscription } from 'foldkit'
|
|
10
|
+
import { 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'
|
|
@@ -53,8 +53,8 @@ export type Message = typeof Message.Type
|
|
|
53
53
|
export const init: Runtime.ApplicationInit<Model, Message> = () => {
|
|
54
54
|
const snake = Snake.create(GAME.INITIAL_POSITION)
|
|
55
55
|
|
|
56
|
-
return
|
|
57
|
-
{
|
|
56
|
+
return {
|
|
57
|
+
model: {
|
|
58
58
|
snake,
|
|
59
59
|
apple: { x: 15, y: 15 },
|
|
60
60
|
direction: GAME.INITIAL_DIRECTION,
|
|
@@ -63,161 +63,153 @@ export const init: Runtime.ApplicationInit<Model, Message> = () => {
|
|
|
63
63
|
points: 0,
|
|
64
64
|
highScore: 0,
|
|
65
65
|
},
|
|
66
|
-
[GenerateApplePosition({ snake: snake })],
|
|
67
|
-
|
|
66
|
+
commands: [GenerateApplePosition({ snake: snake })],
|
|
67
|
+
}
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
// UPDATE
|
|
71
71
|
|
|
72
|
+
type UpdateReturn = Update.Return<Model, Message>
|
|
73
|
+
|
|
72
74
|
export const update = (model: Model, message: Message) =>
|
|
73
|
-
Message.match<
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
M.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
M.whenOr('ArrowUp', 'w', () => 'Up'),
|
|
94
|
-
M.whenOr('ArrowDown', 's', () => 'Down'),
|
|
95
|
-
M.whenOr('ArrowLeft', 'a', () => 'Left'),
|
|
96
|
-
M.whenOr('ArrowRight', 'd', () => 'Right'),
|
|
97
|
-
M.exhaustive,
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
if (model.gameState === 'Playing') {
|
|
101
|
-
return [
|
|
102
|
-
evo(model, {
|
|
103
|
-
nextDirection: () => nextDirection,
|
|
104
|
-
}),
|
|
105
|
-
[],
|
|
106
|
-
]
|
|
107
|
-
} else {
|
|
108
|
-
return [model, []]
|
|
109
|
-
}
|
|
110
|
-
},
|
|
111
|
-
),
|
|
112
|
-
M.when(' ', () => {
|
|
113
|
-
const nextGameState = M.value(model.gameState).pipe(
|
|
114
|
-
M.withReturnType<GameState>(),
|
|
115
|
-
M.when('NotStarted', () => 'Playing'),
|
|
116
|
-
M.when('Playing', () => 'Paused'),
|
|
117
|
-
M.when('Paused', () => 'Playing'),
|
|
118
|
-
M.when('GameOver', () => 'GameOver'),
|
|
75
|
+
Message.match<UpdateReturn>(message, {
|
|
76
|
+
PressedKey: ({ key }) =>
|
|
77
|
+
M.value(key).pipe(
|
|
78
|
+
M.withReturnType<UpdateReturn>(),
|
|
79
|
+
M.whenOr(
|
|
80
|
+
'ArrowUp',
|
|
81
|
+
'ArrowDown',
|
|
82
|
+
'ArrowLeft',
|
|
83
|
+
'ArrowRight',
|
|
84
|
+
'w',
|
|
85
|
+
'a',
|
|
86
|
+
's',
|
|
87
|
+
'd',
|
|
88
|
+
moveKey => {
|
|
89
|
+
const nextDirection = M.value(moveKey).pipe(
|
|
90
|
+
M.withReturnType<Direction.Direction>(),
|
|
91
|
+
M.whenOr('ArrowUp', 'w', () => 'Up'),
|
|
92
|
+
M.whenOr('ArrowDown', 's', () => 'Down'),
|
|
93
|
+
M.whenOr('ArrowLeft', 'a', () => 'Left'),
|
|
94
|
+
M.whenOr('ArrowRight', 'd', () => 'Right'),
|
|
119
95
|
M.exhaustive,
|
|
120
96
|
)
|
|
121
|
-
return [
|
|
122
|
-
evo(model, {
|
|
123
|
-
gameState: () => nextGameState,
|
|
124
|
-
}),
|
|
125
|
-
[],
|
|
126
|
-
]
|
|
127
|
-
}),
|
|
128
|
-
M.when('r', () => {
|
|
129
|
-
const nextSnake = Snake.create(GAME.INITIAL_POSITION)
|
|
130
|
-
|
|
131
|
-
return [
|
|
132
|
-
evo(model, {
|
|
133
|
-
snake: () => nextSnake,
|
|
134
|
-
direction: () => GAME.INITIAL_DIRECTION,
|
|
135
|
-
nextDirection: () => GAME.INITIAL_DIRECTION,
|
|
136
|
-
gameState: () => 'NotStarted',
|
|
137
|
-
points: () => 0,
|
|
138
|
-
}),
|
|
139
|
-
[GenerateApplePosition({ snake: nextSnake })],
|
|
140
|
-
]
|
|
141
|
-
}),
|
|
142
|
-
M.orElse(() => [model, []]),
|
|
143
|
-
),
|
|
144
|
-
|
|
145
|
-
TickedClock: () => {
|
|
146
|
-
if (model.gameState !== 'Playing') {
|
|
147
|
-
return [model, []]
|
|
148
|
-
}
|
|
149
97
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
98
|
+
if (model.gameState === 'Playing') {
|
|
99
|
+
return {
|
|
100
|
+
model: evo(model, {
|
|
101
|
+
nextDirection: () => nextDirection,
|
|
102
|
+
}),
|
|
103
|
+
}
|
|
104
|
+
} else {
|
|
105
|
+
return { model }
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
),
|
|
109
|
+
M.when(' ', () => {
|
|
110
|
+
const nextGameState = M.value(model.gameState).pipe(
|
|
111
|
+
M.withReturnType<GameState>(),
|
|
112
|
+
M.when('NotStarted', () => 'Playing'),
|
|
113
|
+
M.when('Playing', () => 'Paused'),
|
|
114
|
+
M.when('Paused', () => 'Playing'),
|
|
115
|
+
M.when('GameOver', () => 'GameOver'),
|
|
116
|
+
M.exhaustive,
|
|
117
|
+
)
|
|
118
|
+
return {
|
|
119
|
+
model: evo(model, {
|
|
120
|
+
gameState: () => nextGameState,
|
|
169
121
|
}),
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
122
|
+
}
|
|
123
|
+
}),
|
|
124
|
+
M.when('r', () => {
|
|
125
|
+
const nextSnake = Snake.create(GAME.INITIAL_POSITION)
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
model: evo(model, {
|
|
129
|
+
snake: () => nextSnake,
|
|
130
|
+
direction: () => GAME.INITIAL_DIRECTION,
|
|
131
|
+
nextDirection: () => GAME.INITIAL_DIRECTION,
|
|
132
|
+
gameState: () => 'NotStarted',
|
|
133
|
+
points: () => 0,
|
|
134
|
+
}),
|
|
135
|
+
commands: [GenerateApplePosition({ snake: nextSnake })],
|
|
136
|
+
}
|
|
137
|
+
}),
|
|
138
|
+
M.orElse(() => ({ model })),
|
|
139
|
+
),
|
|
177
140
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
141
|
+
TickedClock: () => {
|
|
142
|
+
if (model.gameState !== 'Playing') {
|
|
143
|
+
return { model }
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const currentDirection = Direction.isOpposite(
|
|
147
|
+
model.direction,
|
|
148
|
+
model.nextDirection,
|
|
149
|
+
)
|
|
150
|
+
? model.direction
|
|
151
|
+
: model.nextDirection
|
|
152
|
+
|
|
153
|
+
const newHead = Position.move(model.snake[0], currentDirection)
|
|
154
|
+
const willEatApple = Position.equivalence(newHead, model.apple)
|
|
155
|
+
|
|
156
|
+
const nextSnake = willEatApple
|
|
157
|
+
? Snake.grow(model.snake, currentDirection)
|
|
158
|
+
: Snake.move(model.snake, currentDirection)
|
|
159
|
+
|
|
160
|
+
if (Snake.hasCollision(nextSnake)) {
|
|
161
|
+
return {
|
|
162
|
+
model: evo(model, {
|
|
163
|
+
gameState: () => 'GameOver',
|
|
164
|
+
highScore: highScore => Math.max(model.points, highScore),
|
|
184
165
|
}),
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const commands = willEatApple
|
|
170
|
+
? [GenerateApplePosition({ snake: nextSnake })]
|
|
171
|
+
: []
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
model: evo(model, {
|
|
175
|
+
snake: () => nextSnake,
|
|
176
|
+
direction: () => currentDirection,
|
|
177
|
+
points: points =>
|
|
178
|
+
willEatApple ? points + GAME.POINTS_PER_APPLE : points,
|
|
193
179
|
}),
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
RestartedGame: () => {
|
|
198
|
-
const startPos: Position.Position = { x: 10, y: 10 }
|
|
199
|
-
const nextSnake = Snake.create(startPos)
|
|
200
|
-
|
|
201
|
-
return [
|
|
202
|
-
evo(model, {
|
|
203
|
-
snake: () => nextSnake,
|
|
204
|
-
direction: () => 'Right',
|
|
205
|
-
nextDirection: () => 'Right',
|
|
206
|
-
gameState: () => 'NotStarted',
|
|
207
|
-
points: () => 0,
|
|
208
|
-
}),
|
|
209
|
-
[GenerateApplePosition({ snake: nextSnake })],
|
|
210
|
-
]
|
|
211
|
-
},
|
|
180
|
+
commands,
|
|
181
|
+
}
|
|
182
|
+
},
|
|
212
183
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
184
|
+
PausedGame: () => ({
|
|
185
|
+
model: evo(model, {
|
|
186
|
+
gameState: gameState =>
|
|
187
|
+
gameState === 'Playing' ? 'Paused' : 'Playing',
|
|
188
|
+
}),
|
|
189
|
+
}),
|
|
190
|
+
|
|
191
|
+
RestartedGame: () => {
|
|
192
|
+
const startPosition: Position.Position = { x: 10, y: 10 }
|
|
193
|
+
const nextSnake = Snake.create(startPosition)
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
model: evo(model, {
|
|
197
|
+
snake: () => nextSnake,
|
|
198
|
+
direction: () => 'Right',
|
|
199
|
+
nextDirection: () => 'Right',
|
|
200
|
+
gameState: () => 'NotStarted',
|
|
201
|
+
points: () => 0,
|
|
216
202
|
}),
|
|
217
|
-
[],
|
|
218
|
-
|
|
203
|
+
commands: [GenerateApplePosition({ snake: nextSnake })],
|
|
204
|
+
}
|
|
219
205
|
},
|
|
220
|
-
|
|
206
|
+
|
|
207
|
+
CompletedGenerateApplePosition: ({ position }) => ({
|
|
208
|
+
model: evo(model, {
|
|
209
|
+
apple: () => position,
|
|
210
|
+
}),
|
|
211
|
+
}),
|
|
212
|
+
})
|
|
221
213
|
|
|
222
214
|
// COMMAND
|
|
223
215
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Effect, Match as M, Schema as S } from 'effect'
|
|
2
|
-
import { Command, Runtime } from 'foldkit'
|
|
2
|
+
import { Command, Runtime, type Update } from 'foldkit'
|
|
3
3
|
import { type Document, type Html, type HtmlBuilder } from 'foldkit/html'
|
|
4
4
|
import { defineMessageUnion } from 'foldkit/message'
|
|
5
5
|
import { UrlRequest, load, pushUrl } from 'foldkit/navigation'
|
|
@@ -30,10 +30,9 @@ export type Message = typeof Message.Type
|
|
|
30
30
|
|
|
31
31
|
// INIT
|
|
32
32
|
|
|
33
|
-
export const init: Runtime.RoutingApplicationInit<Model, Message> = url =>
|
|
34
|
-
{ route: urlToAppRoute(url), count: 0 },
|
|
35
|
-
|
|
36
|
-
]
|
|
33
|
+
export const init: Runtime.RoutingApplicationInit<Model, Message> = url => ({
|
|
34
|
+
model: { route: urlToAppRoute(url), count: 0 },
|
|
35
|
+
})
|
|
37
36
|
|
|
38
37
|
// COMMAND
|
|
39
38
|
|
|
@@ -53,29 +52,33 @@ const LoadExternal = Command.define('LoadExternal', {
|
|
|
53
52
|
|
|
54
53
|
// UPDATE
|
|
55
54
|
|
|
56
|
-
type UpdateReturn =
|
|
55
|
+
type UpdateReturn = Update.Return<Model, Message>
|
|
57
56
|
const withUpdateReturn = M.withReturnType<UpdateReturn>()
|
|
58
57
|
|
|
59
58
|
export const update = (model: Model, message: Message) =>
|
|
60
59
|
Message.match<UpdateReturn>(message, {
|
|
61
|
-
ClickedIncrement: () =>
|
|
60
|
+
ClickedIncrement: () => ({
|
|
61
|
+
model: evo(model, { count: count => count + 1 }),
|
|
62
|
+
}),
|
|
62
63
|
ClickedLink: ({ request }) =>
|
|
63
64
|
M.value(request).pipe(
|
|
64
65
|
withUpdateReturn,
|
|
65
66
|
M.tagsExhaustive({
|
|
66
|
-
Internal: ({ url }) =>
|
|
67
|
+
Internal: ({ url }) => ({
|
|
67
68
|
model,
|
|
68
|
-
[NavigateInternal({ url: urlToString(url) })],
|
|
69
|
-
|
|
70
|
-
External: ({ href }) =>
|
|
69
|
+
commands: [NavigateInternal({ url: urlToString(url) })],
|
|
70
|
+
}),
|
|
71
|
+
External: ({ href }) => ({
|
|
72
|
+
model,
|
|
73
|
+
commands: [LoadExternal({ href })],
|
|
74
|
+
}),
|
|
71
75
|
}),
|
|
72
76
|
),
|
|
73
|
-
ChangedUrl: ({ url }) =>
|
|
74
|
-
evo(model, { route: () => urlToAppRoute(url) }),
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
CompletedLoadExternal: () => [model, []],
|
|
77
|
+
ChangedUrl: ({ url }) => ({
|
|
78
|
+
model: evo(model, { route: () => urlToAppRoute(url) }),
|
|
79
|
+
}),
|
|
80
|
+
CompletedNavigateInternal: () => ({ model }),
|
|
81
|
+
CompletedLoadExternal: () => ({ model }),
|
|
79
82
|
})
|
|
80
83
|
|
|
81
84
|
// VIEW
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Effect, Schema as S } from 'effect'
|
|
2
|
-
import { Command, Runtime } from 'foldkit'
|
|
2
|
+
import { Command, Runtime, type Update } from 'foldkit'
|
|
3
3
|
import { type Document, type Html, type HtmlBuilder } from 'foldkit/html'
|
|
4
4
|
import { defineMessageUnion } from 'foldkit/message'
|
|
5
5
|
import { evo } from 'foldkit/struct'
|
|
@@ -39,26 +39,23 @@ export type Message = typeof Message.Type
|
|
|
39
39
|
// UPDATE
|
|
40
40
|
|
|
41
41
|
export const update = (model: Model, message: Message) =>
|
|
42
|
-
Message.match<
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
[PersistCount({ count: nextCount })],
|
|
50
|
-
]
|
|
51
|
-
},
|
|
52
|
-
ClickedIncrement: () => {
|
|
53
|
-
const nextCount = model.count + 1
|
|
54
|
-
return [
|
|
55
|
-
evo(model, { count: () => nextCount }),
|
|
56
|
-
[PersistCount({ count: nextCount })],
|
|
57
|
-
]
|
|
58
|
-
},
|
|
59
|
-
CompletedPersistCount: () => [model, []],
|
|
42
|
+
Message.match<Update.Return<Model, Message>>(message, {
|
|
43
|
+
ClickedDecrement: () => {
|
|
44
|
+
const nextCount = model.count - 1
|
|
45
|
+
return {
|
|
46
|
+
model: evo(model, { count: () => nextCount }),
|
|
47
|
+
commands: [PersistCount({ count: nextCount })],
|
|
48
|
+
}
|
|
60
49
|
},
|
|
61
|
-
|
|
50
|
+
ClickedIncrement: () => {
|
|
51
|
+
const nextCount = model.count + 1
|
|
52
|
+
return {
|
|
53
|
+
model: evo(model, { count: () => nextCount }),
|
|
54
|
+
commands: [PersistCount({ count: nextCount })],
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
CompletedPersistCount: () => ({ model }),
|
|
58
|
+
})
|
|
62
59
|
|
|
63
60
|
// COMMAND
|
|
64
61
|
|
|
@@ -78,14 +75,13 @@ export const PersistCount = Command.define('PersistCount', {
|
|
|
78
75
|
|
|
79
76
|
// INIT
|
|
80
77
|
|
|
81
|
-
export const init: Runtime.ApplicationInit<Model, Message, Flags> = flags =>
|
|
82
|
-
{
|
|
78
|
+
export const init: Runtime.ApplicationInit<Model, Message, Flags> = flags => ({
|
|
79
|
+
model: {
|
|
83
80
|
count: flags.initialCount,
|
|
84
81
|
renderedAt: flags.renderedAt,
|
|
85
82
|
renderedOn: flags.renderedOn,
|
|
86
83
|
},
|
|
87
|
-
|
|
88
|
-
]
|
|
84
|
+
})
|
|
89
85
|
|
|
90
86
|
// VIEW
|
|
91
87
|
|
|
@@ -334,14 +334,13 @@ export const initialModel = Model.make({
|
|
|
334
334
|
nextTransitionLogId: 0,
|
|
335
335
|
})
|
|
336
336
|
|
|
337
|
-
export const init: Runtime.ApplicationInit<Model, Message> = () =>
|
|
338
|
-
initialModel,
|
|
339
|
-
|
|
340
|
-
]
|
|
337
|
+
export const init: Runtime.ApplicationInit<Model, Message> = () => ({
|
|
338
|
+
model: initialModel,
|
|
339
|
+
})
|
|
341
340
|
|
|
342
341
|
// UPDATE
|
|
343
342
|
|
|
344
|
-
type UpdateReturn =
|
|
343
|
+
type UpdateReturn = Update.Return<Model, Message>
|
|
345
344
|
|
|
346
345
|
export const TRANSITION_LOG_LIMIT = 20
|
|
347
346
|
|
|
@@ -376,8 +375,8 @@ const stepMachine =
|
|
|
376
375
|
summary: resultToTransitionSummary(result),
|
|
377
376
|
}
|
|
378
377
|
|
|
379
|
-
return
|
|
380
|
-
evo(model, {
|
|
378
|
+
return {
|
|
379
|
+
model: evo(model, {
|
|
381
380
|
checkout: () => nextCheckout,
|
|
382
381
|
transitionLog: flow(
|
|
383
382
|
Array.prepend(transitionLogEntry),
|
|
@@ -385,8 +384,8 @@ const stepMachine =
|
|
|
385
384
|
),
|
|
386
385
|
nextTransitionLogId: Number.increment,
|
|
387
386
|
}),
|
|
388
|
-
transitionCommands,
|
|
389
|
-
|
|
387
|
+
commands: transitionCommands,
|
|
388
|
+
}
|
|
390
389
|
}
|
|
391
390
|
|
|
392
391
|
const foldEditionRadioGroupOutMessage = M.type<RadioGroup.OutMessage>().pipe(
|
|
@@ -410,11 +409,25 @@ const foldEditionRadioGroup = Update.foldChild({
|
|
|
410
409
|
foldOutMessage: foldEditionRadioGroupOutMessage,
|
|
411
410
|
})
|
|
412
411
|
|
|
413
|
-
export const update = (model: Model, message: Message)
|
|
412
|
+
export const update = (model: Model, message: Message) =>
|
|
414
413
|
M.value(message).pipe(
|
|
415
414
|
M.withReturnType<UpdateReturn>(),
|
|
416
415
|
M.tag('GotEditionRadioGroupMessage', ({ message }) =>
|
|
417
416
|
foldEditionRadioGroup(model, message),
|
|
418
417
|
),
|
|
419
|
-
M.
|
|
418
|
+
M.tag(
|
|
419
|
+
'ClickedContinue',
|
|
420
|
+
'ClickedBack',
|
|
421
|
+
'ClickedCancel',
|
|
422
|
+
'ClickedPlaceOrder',
|
|
423
|
+
'ClickedStartOver',
|
|
424
|
+
'ToggledPaymentMethod',
|
|
425
|
+
'SelectedEdition',
|
|
426
|
+
'ToggledTermsAccepted',
|
|
427
|
+
'UpdatedPromoCode',
|
|
428
|
+
'SubmittedPromoCode',
|
|
429
|
+
'SucceededPlaceOrder',
|
|
430
|
+
() => stepMachine(message)(model),
|
|
431
|
+
),
|
|
432
|
+
M.exhaustive,
|
|
420
433
|
)
|
|
@@ -183,8 +183,8 @@ describe('update', () => {
|
|
|
183
183
|
Message.SelectedEdition({ isShippingRequired: index % 2 === 0 }),
|
|
184
184
|
),
|
|
185
185
|
Array.reduce(initialModel, (model, message) => {
|
|
186
|
-
const
|
|
187
|
-
return
|
|
186
|
+
const messageUpdate = update(model, message)
|
|
187
|
+
return messageUpdate.model
|
|
188
188
|
}),
|
|
189
189
|
)
|
|
190
190
|
|