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,5 +1,5 @@
1
1
  import { Array, 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 { Dialog, Listbox, RadioGroup } from '@foldkit/ui'
@@ -30,7 +30,7 @@ import {
30
30
  ToolRadioGroup,
31
31
  } from './view/toolbar'
32
32
 
33
- type UpdateReturn = readonly [Model, ReadonlyArray<Command.Command<Message>>]
33
+ type UpdateReturn = Update.Return<Model, Message>
34
34
 
35
35
  const withUpdateReturn = M.withReturnType<UpdateReturn>()
36
36
 
@@ -54,11 +54,10 @@ const applyFill = (model: Model, x: number, y: number) => {
54
54
  const foldErrorDialogOutMessage = M.type<Dialog.OutMessage>().pipe(
55
55
  M.withReturnType<Update.Step<Model, Message>>(),
56
56
  M.tagsExhaustive({
57
- Opened: () => model => [model, []],
58
- Closed: () => model => [
59
- evo(model, { maybeExportError: () => Option.none() }),
60
- [],
61
- ],
57
+ Opened: () => model => ({ model }),
58
+ Closed: () => model => ({
59
+ model: evo(model, { maybeExportError: () => Option.none() }),
60
+ }),
62
61
  }),
63
62
  )
64
63
 
@@ -71,6 +70,15 @@ const foldErrorDialog = Update.foldChild({
71
70
  foldOutMessage: foldErrorDialogOutMessage,
72
71
  })
73
72
 
73
+ const foldErrorDialogOpen = Update.foldChildStep({
74
+ update: Dialog.open,
75
+ read: (model: Model) => Option.some(model.errorDialog),
76
+ write: (model, nextErrorDialog) =>
77
+ evo(model, { errorDialog: () => nextErrorDialog }),
78
+ toParentMessage: message => Message.GotErrorDialogMessage({ message }),
79
+ foldOutMessage: foldErrorDialogOutMessage,
80
+ })
81
+
74
82
  const foldThemeListboxOutMessage: (
75
83
  outMessage: Listbox.OutMessage,
76
84
  ) => Update.Step<Model, Message> = M.type<Listbox.OutMessage>().pipe(
@@ -82,13 +90,13 @@ const foldThemeListboxOutMessage: (
82
90
  const themeIndex = Number(value)
83
91
  const maybeNextTheme = Array.get(PALETTE_THEMES, themeIndex)
84
92
  if (Option.isNone(maybeNextTheme)) {
85
- return [model, []]
93
+ return { model }
86
94
  }
87
95
  const nextModel = evo(model, {
88
96
  paletteThemeIndex: () => themeIndex,
89
97
  selectedColorIndex: () => DEFAULT_COLOR_INDEX,
90
98
  })
91
- return [nextModel, [saveCanvas(nextModel)]]
99
+ return { model: nextModel, commands: [saveCanvas(nextModel)] }
92
100
  },
93
101
  }),
94
102
  )
@@ -105,11 +113,10 @@ const foldThemeListbox = Update.foldChild({
105
113
  const foldGridSizeConfirmDialogOutMessage = M.type<Dialog.OutMessage>().pipe(
106
114
  M.withReturnType<Update.Step<Model, Message>>(),
107
115
  M.tagsExhaustive({
108
- Opened: () => model => [model, []],
109
- Closed: () => model => [
110
- evo(model, { maybePendingGridSize: () => Option.none() }),
111
- [],
112
- ],
116
+ Opened: () => model => ({ model }),
117
+ Closed: () => model => ({
118
+ model: evo(model, { maybePendingGridSize: () => Option.none() }),
119
+ }),
113
120
  }),
114
121
  )
115
122
 
@@ -123,14 +130,33 @@ const foldGridSizeConfirmDialog = Update.foldChild({
123
130
  foldOutMessage: foldGridSizeConfirmDialogOutMessage,
124
131
  })
125
132
 
126
- const selectTool = (model: Model, tool: Tool): UpdateReturn => [
127
- evo(model, { tool: () => tool }),
128
- [],
129
- ]
133
+ const foldGridSizeConfirmDialogOpen = Update.foldChildStep({
134
+ update: Dialog.open,
135
+ read: (model: Model) => Option.some(model.gridSizeConfirmDialog),
136
+ write: (model, nextGridSizeConfirmDialog) =>
137
+ evo(model, { gridSizeConfirmDialog: () => nextGridSizeConfirmDialog }),
138
+ toParentMessage: message =>
139
+ Message.GotGridSizeConfirmDialogMessage({ message }),
140
+ foldOutMessage: foldGridSizeConfirmDialogOutMessage,
141
+ })
142
+
143
+ const foldGridSizeConfirmDialogClose = Update.foldChildStep({
144
+ update: Dialog.close,
145
+ read: (model: Model) => Option.some(model.gridSizeConfirmDialog),
146
+ write: (model, nextGridSizeConfirmDialog) =>
147
+ evo(model, { gridSizeConfirmDialog: () => nextGridSizeConfirmDialog }),
148
+ toParentMessage: message =>
149
+ Message.GotGridSizeConfirmDialogMessage({ message }),
150
+ foldOutMessage: foldGridSizeConfirmDialogOutMessage,
151
+ })
152
+
153
+ const selectTool = (model: Model, tool: Tool): UpdateReturn => ({
154
+ model: evo(model, { tool: () => tool }),
155
+ })
130
156
 
131
157
  const selectColor = (model: Model, colorIndex: PaletteIndex): UpdateReturn => {
132
158
  const nextModel = evo(model, { selectedColorIndex: () => colorIndex })
133
- return [nextModel, [saveCanvas(nextModel)]]
159
+ return { model: nextModel, commands: [saveCanvas(nextModel)] }
134
160
  }
135
161
 
136
162
  const foldToolRadioGroupOutMessage = M.type<RadioGroup.OutMessage<Tool>>().pipe(
@@ -198,32 +224,30 @@ export const update = (model: Model, message: Message) =>
198
224
  PressedCell: ({ x, y }) =>
199
225
  M.value(model.tool).pipe(
200
226
  withUpdateReturn,
201
- M.when('Brush', () => [
202
- evo(model, {
227
+ M.when('Brush', () => ({
228
+ model: evo(model, {
203
229
  grid: () => applyBrush(model, x, y),
204
230
  undoStack: () => pushHistory(model.undoStack, model.grid),
205
231
  redoStack: () => [],
206
232
  isDrawing: () => true,
207
233
  }),
208
- [],
209
- ]),
234
+ })),
210
235
  M.when('Fill', () => {
211
236
  const nextModel = evo(model, {
212
237
  grid: () => applyFill(model, x, y),
213
238
  undoStack: () => pushHistory(model.undoStack, model.grid),
214
239
  redoStack: () => [],
215
240
  })
216
- return [nextModel, [saveCanvas(nextModel)]]
241
+ return { model: nextModel, commands: [saveCanvas(nextModel)] }
217
242
  }),
218
- M.when('Eraser', () => [
219
- evo(model, {
243
+ M.when('Eraser', () => ({
244
+ model: evo(model, {
220
245
  grid: () => applyEraser(model, x, y),
221
246
  undoStack: () => pushHistory(model.undoStack, model.grid),
222
247
  redoStack: () => [],
223
248
  isDrawing: () => true,
224
249
  }),
225
- [],
226
- ]),
250
+ })),
227
251
  M.exhaustive,
228
252
  ),
229
253
 
@@ -233,27 +257,30 @@ export const update = (model: Model, message: Message) =>
233
257
  })
234
258
 
235
259
  if (model.isDrawing && model.tool === 'Brush') {
236
- return [evo(withHover, { grid: () => applyBrush(model, x, y) }), []]
260
+ return {
261
+ model: evo(withHover, { grid: () => applyBrush(model, x, y) }),
262
+ }
237
263
  }
238
264
 
239
265
  if (model.isDrawing && model.tool === 'Eraser') {
240
- return [evo(withHover, { grid: () => applyEraser(model, x, y) }), []]
266
+ return {
267
+ model: evo(withHover, { grid: () => applyEraser(model, x, y) }),
268
+ }
241
269
  }
242
270
 
243
- return [withHover, []]
271
+ return { model: withHover }
244
272
  },
245
273
 
246
- LeftCanvas: () => [
247
- evo(model, { maybeHoveredCell: () => Option.none() }),
248
- [],
249
- ],
274
+ LeftCanvas: () => ({
275
+ model: evo(model, { maybeHoveredCell: () => Option.none() }),
276
+ }),
250
277
 
251
278
  ReleasedMouse: () => {
252
279
  if (!model.isDrawing) {
253
- return [model, []]
280
+ return { model }
254
281
  }
255
282
  const nextModel = evo(model, { isDrawing: () => false })
256
- return [nextModel, [saveCanvas(nextModel)]]
283
+ return { model: nextModel, commands: [saveCanvas(nextModel)] }
257
284
  },
258
285
 
259
286
  SelectedColor: ({ colorIndex }) => selectColor(model, colorIndex),
@@ -279,7 +306,7 @@ export const update = (model: Model, message: Message) =>
279
306
  M.when('Both', () => 'Vertical' as const),
280
307
  M.exhaustive,
281
308
  )
282
- return [evo(model, { mirrorMode: () => nextMirrorMode }), []]
309
+ return { model: evo(model, { mirrorMode: () => nextMirrorMode }) }
283
310
  },
284
311
 
285
312
  ToggledMirrorVertical: () => {
@@ -290,39 +317,39 @@ export const update = (model: Model, message: Message) =>
290
317
  M.when('Both', () => 'Horizontal' as const),
291
318
  M.exhaustive,
292
319
  )
293
- return [evo(model, { mirrorMode: () => nextMirrorMode }), []]
320
+ return { model: evo(model, { mirrorMode: () => nextMirrorMode }) }
294
321
  },
295
322
 
296
323
  ClickedUndo: () =>
297
324
  Array.match(model.undoStack, {
298
- onEmpty: () => [model, []],
325
+ onEmpty: () => ({ model }),
299
326
  onNonEmpty: nonEmptyUndoStack => {
300
327
  const nextModel = evo(model, {
301
328
  grid: () => Array.lastNonEmpty(nonEmptyUndoStack),
302
329
  undoStack: () => Array.initNonEmpty(nonEmptyUndoStack),
303
330
  redoStack: () => [...model.redoStack, model.grid],
304
331
  })
305
- return [nextModel, [saveCanvas(nextModel)]]
332
+ return { model: nextModel, commands: [saveCanvas(nextModel)] }
306
333
  },
307
334
  }),
308
335
 
309
336
  ClickedRedo: () =>
310
337
  Array.match(model.redoStack, {
311
- onEmpty: () => [model, []],
338
+ onEmpty: () => ({ model }),
312
339
  onNonEmpty: nonEmptyRedoStack => {
313
340
  const nextModel = evo(model, {
314
341
  grid: () => Array.lastNonEmpty(nonEmptyRedoStack),
315
342
  undoStack: () => [...model.undoStack, model.grid],
316
343
  redoStack: () => Array.initNonEmpty(nonEmptyRedoStack),
317
344
  })
318
- return [nextModel, [saveCanvas(nextModel)]]
345
+ return { model: nextModel, commands: [saveCanvas(nextModel)] }
319
346
  },
320
347
  }),
321
348
 
322
349
  ClickedHistoryStep: ({ stepIndex }) => {
323
350
  const targetGrid = model.undoStack[stepIndex]
324
351
  if (targetGrid === undefined) {
325
- return [model, []]
352
+ return { model }
326
353
  }
327
354
 
328
355
  const statesAfterTarget = Array.drop(model.undoStack, stepIndex + 1)
@@ -337,13 +364,13 @@ export const update = (model: Model, message: Message) =>
337
364
  ],
338
365
  })
339
366
 
340
- return [nextModel, [saveCanvas(nextModel)]]
367
+ return { model: nextModel, commands: [saveCanvas(nextModel)] }
341
368
  },
342
369
 
343
370
  ClickedRedoStep: ({ stepIndex }) => {
344
371
  const targetGrid = model.redoStack[stepIndex]
345
372
  if (targetGrid === undefined) {
346
- return [model, []]
373
+ return { model }
347
374
  }
348
375
 
349
376
  const statesBetweenCurrentAndTarget = Array.drop(
@@ -361,7 +388,7 @@ export const update = (model: Model, message: Message) =>
361
388
  redoStack: () => Array.take(model.redoStack, stepIndex),
362
389
  })
363
390
 
364
- return [nextModel, [saveCanvas(nextModel)]]
391
+ return { model: nextModel, commands: [saveCanvas(nextModel)] }
365
392
  },
366
393
 
367
394
  ClickedClear: () => {
@@ -370,39 +397,33 @@ export const update = (model: Model, message: Message) =>
370
397
  undoStack: () => pushHistory(model.undoStack, model.grid),
371
398
  redoStack: () => [],
372
399
  })
373
- return [nextModel, [saveCanvas(nextModel)]]
400
+ return { model: nextModel, commands: [saveCanvas(nextModel)] }
374
401
  },
375
402
 
376
- ClickedExport: () => [
403
+ ClickedExport: () => ({
377
404
  model,
378
- [
405
+ commands: [
379
406
  ExportPng({
380
407
  grid: model.grid,
381
408
  gridSize: model.gridSize,
382
409
  paletteThemeIndex: model.paletteThemeIndex,
383
410
  }),
384
411
  ],
385
- ],
386
-
387
- SucceededExportPng: () => [model, []],
412
+ }),
388
413
 
389
- CompletedSaveCanvas: () => [model, []],
414
+ SucceededExportPng: () => ({ model }),
390
415
 
391
- FailedExportPng: ({ error }) => {
392
- const [nextErrorDialog, errorDialogCommands] = Dialog.open(
393
- model.errorDialog,
394
- )
416
+ CompletedSaveCanvas: () => ({ model }),
395
417
 
396
- return [
397
- evo(model, {
398
- maybeExportError: () => Option.some(error),
399
- errorDialog: () => nextErrorDialog,
418
+ FailedExportPng: ({ error }) =>
419
+ Update.combine(model, [
420
+ stepModel => ({
421
+ model: evo(stepModel, {
422
+ maybeExportError: () => Option.some(error),
423
+ }),
400
424
  }),
401
- Command.mapMessages(errorDialogCommands, dialogMessage =>
402
- Message.GotErrorDialogMessage({ message: dialogMessage }),
403
- ),
404
- ]
405
- },
425
+ foldErrorDialogOpen,
426
+ ]),
406
427
 
407
428
  GotErrorDialogMessage: ({ message }) => foldErrorDialog(model, message),
408
429
 
@@ -410,33 +431,24 @@ export const update = (model: Model, message: Message) =>
410
431
 
411
432
  ConfirmedGridSizeChange: () =>
412
433
  Option.match(model.maybePendingGridSize, {
413
- onNone: () => [model, []],
414
- onSome: pendingSize => {
415
- const [nextDialog, dialogCommands] = Dialog.close(
416
- model.gridSizeConfirmDialog,
417
- )
418
- const mappedDialogCommands = Command.mapMessages(
419
- dialogCommands,
420
- dialogMessage =>
421
- Message.GotGridSizeConfirmDialogMessage({
422
- message: dialogMessage,
423
- }),
424
- )
425
- const [resizedModel] = applyGridSizeChange(model, pendingSize)
426
- const nextModel = evo(resizedModel, {
427
- gridSizeConfirmDialog: () => nextDialog,
428
- maybePendingGridSize: () => Option.none(),
429
- })
430
- return [nextModel, [...mappedDialogCommands, saveCanvas(nextModel)]]
431
- },
434
+ onNone: () => ({ model }),
435
+ onSome: pendingSize =>
436
+ Update.combine(model, [
437
+ stepModel => applyGridSizeChange(stepModel, pendingSize),
438
+ foldGridSizeConfirmDialogClose,
439
+ stepModel => ({
440
+ model: stepModel,
441
+ commands: [saveCanvas(stepModel)],
442
+ }),
443
+ ]),
432
444
  }),
433
445
 
434
446
  GotGridSizeConfirmDialogMessage: ({ message }) =>
435
447
  foldGridSizeConfirmDialog(model, message),
436
448
  })
437
449
 
438
- const applyGridSizeChange = (model: Model, size: number): UpdateReturn => [
439
- evo(model, {
450
+ const applyGridSizeChange = (model: Model, size: number): UpdateReturn => ({
451
+ model: evo(model, {
440
452
  grid: () => createEmptyGrid(size),
441
453
  gridSize: () => size,
442
454
  undoStack: () => [],
@@ -444,26 +456,23 @@ const applyGridSizeChange = (model: Model, size: number): UpdateReturn => [
444
456
  isDrawing: () => false,
445
457
  maybeHoveredCell: () => Option.none(),
446
458
  }),
447
- [],
448
- ]
459
+ })
449
460
 
450
461
  const requestGridSizeChange = (model: Model, size: number): UpdateReturn => {
451
462
  if (size === model.gridSize) {
452
- return [model, []]
463
+ return { model }
453
464
  }
454
465
 
455
466
  if (isGridEmpty(model.grid)) {
456
467
  return applyGridSizeChange(model, size)
457
468
  }
458
469
 
459
- const [nextDialog, dialogCommands] = Dialog.open(model.gridSizeConfirmDialog)
460
- return [
461
- evo(model, {
462
- maybePendingGridSize: () => Option.some(size),
463
- gridSizeConfirmDialog: () => nextDialog,
470
+ return Update.combine(model, [
471
+ stepModel => ({
472
+ model: evo(stepModel, {
473
+ maybePendingGridSize: () => Option.some(size),
474
+ }),
464
475
  }),
465
- Command.mapMessages(dialogCommands, dialogMessage =>
466
- Message.GotGridSizeConfirmDialogMessage({ message: dialogMessage }),
467
- ),
468
- ]
476
+ foldGridSizeConfirmDialogOpen,
477
+ ])
469
478
  }
@@ -190,14 +190,13 @@ export const init: Runtime.RoutingApplicationInit<Model, Message> = (
190
190
  ) => {
191
191
  const route = urlToAppRoute(url)
192
192
 
193
- return [
194
- {
193
+ return {
194
+ model: {
195
195
  route,
196
196
  dietListbox: Listbox.init({ id: 'diet-filter' }),
197
197
  periodListbox: Listbox.init({ id: 'period-filter' }),
198
198
  },
199
- [],
200
- ]
199
+ }
201
200
  }
202
201
 
203
202
  // UPDATE
@@ -267,7 +266,7 @@ const LoadExternal = Command.define('LoadExternal', {
267
266
  load(href).pipe(Effect.as(Message.CompletedLoadExternal())),
268
267
  })
269
268
 
270
- type UpdateReturn = readonly [Model, ReadonlyArray<Command.Command<Message>>]
269
+ type UpdateReturn = Update.Return<Model, Message>
271
270
  const withUpdateReturn = M.withReturnType<UpdateReturn>()
272
271
 
273
272
  const DietListbox = Listbox.create<string>()
@@ -282,15 +281,15 @@ const foldDietListboxOutMessage: (
282
281
  ({ value }) =>
283
282
  model => {
284
283
  const fields = routeToBrowseFields(model.route)
285
- return [
284
+ return {
286
285
  model,
287
- [
286
+ commands: [
288
287
  ReplaceFilters({
289
288
  ...fields,
290
289
  diet: selectionToParam(Option.some(value), Diet),
291
290
  }),
292
291
  ],
293
- ]
292
+ }
294
293
  },
295
294
  }),
296
295
  )
@@ -313,15 +312,15 @@ const foldPeriodListboxOutMessage: (
313
312
  ({ value }) =>
314
313
  model => {
315
314
  const fields = routeToBrowseFields(model.route)
316
- return [
315
+ return {
317
316
  model,
318
- [
317
+ commands: [
319
318
  ReplaceFilters({
320
319
  ...fields,
321
320
  period: selectionToParam(Option.some(value), Period),
322
321
  }),
323
322
  ],
324
- ]
323
+ }
325
324
  },
326
325
  }),
327
326
  )
@@ -337,54 +336,57 @@ const foldPeriodListbox = Update.foldChild({
337
336
 
338
337
  export const update = (model: Model, message: Message) =>
339
338
  Message.match<UpdateReturn>(message, {
340
- CompletedNavigateInternal: () => [model, []],
341
- CompletedLoadExternal: () => [model, []],
342
- CompletedReplaceFilters: () => [model, []],
339
+ CompletedNavigateInternal: () => ({ model }),
340
+ CompletedLoadExternal: () => ({ model }),
341
+ CompletedReplaceFilters: () => ({ model }),
343
342
 
344
343
  ClickedLink: ({ request }) =>
345
344
  M.value(request).pipe(
346
345
  withUpdateReturn,
347
346
  M.tagsExhaustive({
348
- Internal: ({ url }) => [
347
+ Internal: ({ url }) => ({
349
348
  model,
350
- [NavigateInternal({ url: urlToString(url) })],
351
- ],
352
- External: ({ href }) => [model, [LoadExternal({ href })]],
349
+ commands: [NavigateInternal({ url: urlToString(url) })],
350
+ }),
351
+ External: ({ href }) => ({
352
+ model,
353
+ commands: [LoadExternal({ href })],
354
+ }),
353
355
  }),
354
356
  ),
355
357
 
356
358
  ChangedUrl: ({ url }) => {
357
359
  const nextRoute = urlToAppRoute(url)
358
360
 
359
- return [evo(model, { route: () => nextRoute }), []]
361
+ return { model: evo(model, { route: () => nextRoute }) }
360
362
  },
361
363
 
362
364
  ChangedSearchInput: ({ value }) => {
363
365
  const fields = routeToBrowseFields(model.route)
364
366
 
365
- return [
367
+ return {
366
368
  model,
367
- [
369
+ commands: [
368
370
  ReplaceFilters({
369
371
  ...fields,
370
372
  search: Option.liftPredicate(value, String.isNonEmpty),
371
373
  }),
372
374
  ],
373
- ]
375
+ }
374
376
  },
375
377
 
376
378
  ClickedColumnHeader: ({ column }) => {
377
379
  const fields = routeToBrowseFields(model.route)
378
380
 
379
- return [
381
+ return {
380
382
  model,
381
- [
383
+ commands: [
382
384
  ReplaceFilters({
383
385
  ...fields,
384
386
  sorting: nextSorting(fields.sorting, column),
385
387
  }),
386
388
  ],
387
- ]
389
+ }
388
390
  },
389
391
 
390
392
  GotDietListboxMessage: ({ message }) => foldDietListbox(model, message),