create-foldkit-app 0.32.0 → 0.32.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 (149) hide show
  1. package/dist/commands/create.js +9 -7
  2. package/dist/templates/base/FOLDKIT.md +22 -6
  3. package/dist/templates/examples/api-cache/src/data.ts +14 -14
  4. package/dist/templates/examples/api-cache/src/main.ts +42 -39
  5. package/dist/templates/examples/auth/src/command.ts +3 -3
  6. package/dist/templates/examples/auth/src/domain/session.ts +8 -6
  7. package/dist/templates/examples/auth/src/main.ts +11 -11
  8. package/dist/templates/examples/auth/src/message.ts +3 -3
  9. package/dist/templates/examples/auth/src/model.ts +2 -2
  10. package/dist/templates/examples/auth/src/page/loggedIn/index.ts +1 -1
  11. package/dist/templates/examples/auth/src/page/loggedIn/view.ts +3 -3
  12. package/dist/templates/examples/auth/src/page/loggedOut/index.ts +1 -1
  13. package/dist/templates/examples/auth/src/page/loggedOut/page/login.ts +9 -17
  14. package/dist/templates/examples/auth/src/page/loggedOut/update.ts +4 -6
  15. package/dist/templates/examples/auth/src/page/loggedOut/view.ts +3 -3
  16. package/dist/templates/examples/auth/src/route.ts +2 -2
  17. package/dist/templates/examples/auth/src/update.ts +37 -40
  18. package/dist/templates/examples/auth/src/view.ts +6 -6
  19. package/dist/templates/examples/canvas-art/src/main.ts +22 -30
  20. package/dist/templates/examples/charting/src/command.ts +3 -3
  21. package/dist/templates/examples/charting/src/domain.ts +53 -48
  22. package/dist/templates/examples/charting/src/echarts.ts +6 -6
  23. package/dist/templates/examples/charting/src/githubApi.ts +33 -34
  24. package/dist/templates/examples/charting/src/http.ts +7 -7
  25. package/dist/templates/examples/charting/src/message.ts +6 -6
  26. package/dist/templates/examples/charting/src/model.ts +6 -6
  27. package/dist/templates/examples/charting/src/npmApi.ts +19 -15
  28. package/dist/templates/examples/charting/src/subscription.ts +5 -5
  29. package/dist/templates/examples/charting/src/telemetry.test.ts +18 -12
  30. package/dist/templates/examples/charting/src/telemetry.ts +11 -18
  31. package/dist/templates/examples/charting/src/update.ts +17 -23
  32. package/dist/templates/examples/charting/src/view/chart.ts +2 -2
  33. package/dist/templates/examples/counter/src/main.ts +2 -2
  34. package/dist/templates/examples/counters/src/counter.ts +2 -2
  35. package/dist/templates/examples/counters/src/main.ts +8 -8
  36. package/dist/templates/examples/embedding/src/main.ts +10 -7
  37. package/dist/templates/examples/form/src/main.ts +18 -14
  38. package/dist/templates/examples/generative-art/src/command.ts +7 -2
  39. package/dist/templates/examples/generative-art/src/message.ts +14 -14
  40. package/dist/templates/examples/generative-art/src/model.ts +21 -21
  41. package/dist/templates/examples/generative-art/src/update.ts +15 -17
  42. package/dist/templates/examples/interrupting-commands/src/main.ts +30 -27
  43. package/dist/templates/examples/job-application/src/domain/proficiencyLevel.ts +2 -2
  44. package/dist/templates/examples/job-application/src/domain/pronounOption.ts +2 -2
  45. package/dist/templates/examples/job-application/src/domain/step.ts +11 -11
  46. package/dist/templates/examples/job-application/src/main.ts +5 -5
  47. package/dist/templates/examples/job-application/src/message.ts +2 -2
  48. package/dist/templates/examples/job-application/src/model.ts +5 -5
  49. package/dist/templates/examples/job-application/src/step/attachments.ts +32 -34
  50. package/dist/templates/examples/job-application/src/step/coverLetter.ts +4 -4
  51. package/dist/templates/examples/job-application/src/step/education/education.ts +11 -14
  52. package/dist/templates/examples/job-application/src/step/education/entry.ts +21 -22
  53. package/dist/templates/examples/job-application/src/step/personalInfo.ts +44 -54
  54. package/dist/templates/examples/job-application/src/step/skills/entry.ts +12 -14
  55. package/dist/templates/examples/job-application/src/step/skills/skills.ts +11 -14
  56. package/dist/templates/examples/job-application/src/step/workHistory/entry.ts +43 -45
  57. package/dist/templates/examples/job-application/src/step/workHistory/workHistory.ts +11 -14
  58. package/dist/templates/examples/job-application/src/update.ts +17 -17
  59. package/dist/templates/examples/job-application/src/view/attachments.ts +5 -5
  60. package/dist/templates/examples/job-application/src/view/datePicker.ts +3 -3
  61. package/dist/templates/examples/job-application/src/view/field.ts +5 -5
  62. package/dist/templates/examples/job-application/src/view/index.ts +28 -22
  63. package/dist/templates/examples/kanban/src/command.ts +4 -4
  64. package/dist/templates/examples/kanban/src/domain/card.ts +6 -6
  65. package/dist/templates/examples/kanban/src/domain/column.ts +9 -9
  66. package/dist/templates/examples/kanban/src/main.ts +4 -4
  67. package/dist/templates/examples/kanban/src/message.ts +6 -6
  68. package/dist/templates/examples/kanban/src/model.ts +11 -9
  69. package/dist/templates/examples/kanban/src/update.ts +5 -5
  70. package/dist/templates/examples/managed-resource-layer/src/main.ts +20 -20
  71. package/dist/templates/examples/map/src/locations.ts +7 -7
  72. package/dist/templates/examples/map/src/main.ts +83 -44
  73. package/dist/templates/examples/map/src/mount.test.ts +127 -0
  74. package/dist/templates/examples/pixel-art/src/command.ts +12 -5
  75. package/dist/templates/examples/pixel-art/src/main.ts +4 -4
  76. package/dist/templates/examples/pixel-art/src/message.ts +7 -7
  77. package/dist/templates/examples/pixel-art/src/model.ts +34 -29
  78. package/dist/templates/examples/pixel-art/src/subscription.ts +2 -2
  79. package/dist/templates/examples/pixel-art/src/update.ts +79 -86
  80. package/dist/templates/examples/query-sync/src/main.ts +106 -102
  81. package/dist/templates/examples/route-transitions/src/data.ts +6 -6
  82. package/dist/templates/examples/route-transitions/src/main.ts +23 -29
  83. package/dist/templates/examples/route-transitions/src/route.ts +3 -3
  84. package/dist/templates/examples/routing/src/fileTree.ts +10 -8
  85. package/dist/templates/examples/routing/src/main.ts +23 -21
  86. package/dist/templates/examples/routing/src/page/people.ts +14 -22
  87. package/dist/templates/examples/routing/src/route.ts +7 -7
  88. package/dist/templates/examples/shopping-cart/src/main.ts +30 -31
  89. package/dist/templates/examples/shopping-cart/src/page/products.ts +10 -10
  90. package/dist/templates/examples/shopping-cart/src/route.ts +6 -4
  91. package/dist/templates/examples/slow-warnings/src/main.ts +35 -43
  92. package/dist/templates/examples/snake/src/domain/snake.ts +2 -2
  93. package/dist/templates/examples/snake/src/main.ts +39 -47
  94. package/dist/templates/examples/ssg/src/main.ts +5 -5
  95. package/dist/templates/examples/ssg/src/route.ts +2 -2
  96. package/dist/templates/examples/ssr/src/cookie.ts +3 -3
  97. package/dist/templates/examples/ssr/src/main.ts +10 -10
  98. package/dist/templates/examples/state-machine/src/main.ts +55 -53
  99. package/dist/templates/examples/state-machine/src/view.ts +7 -7
  100. package/dist/templates/examples/stopwatch/src/main.ts +10 -10
  101. package/dist/templates/examples/todo/src/main.ts +41 -34
  102. package/dist/templates/examples/ui-showcase/src/main.ts +54 -42
  103. package/dist/templates/examples/ui-showcase/src/scene.test.ts +1 -1
  104. package/dist/templates/examples/ui-showcase/src/ui/init.ts +1 -2
  105. package/dist/templates/examples/ui-showcase/src/ui/message.ts +17 -18
  106. package/dist/templates/examples/ui-showcase/src/ui/model.ts +47 -44
  107. package/dist/templates/examples/ui-showcase/src/ui/subscriptions.ts +1 -1
  108. package/dist/templates/examples/ui-showcase/src/ui/toast.ts +4 -4
  109. package/dist/templates/examples/ui-showcase/src/ui/update.ts +287 -298
  110. package/dist/templates/examples/ui-showcase/src/ui/view/animation.ts +2 -2
  111. package/dist/templates/examples/ui-showcase/src/ui/view/button.ts +1 -1
  112. package/dist/templates/examples/ui-showcase/src/ui/view/calendar.ts +4 -4
  113. package/dist/templates/examples/ui-showcase/src/ui/view/checkbox.ts +1 -1
  114. package/dist/templates/examples/ui-showcase/src/ui/view/combobox.ts +1 -1
  115. package/dist/templates/examples/ui-showcase/src/ui/view/datePicker.ts +4 -4
  116. package/dist/templates/examples/ui-showcase/src/ui/view/dialog.ts +1 -1
  117. package/dist/templates/examples/ui-showcase/src/ui/view/disclosure.ts +1 -1
  118. package/dist/templates/examples/ui-showcase/src/ui/view/dragAndDrop.ts +1 -1
  119. package/dist/templates/examples/ui-showcase/src/ui/view/fieldset.ts +1 -1
  120. package/dist/templates/examples/ui-showcase/src/ui/view/fileDrop.ts +6 -6
  121. package/dist/templates/examples/ui-showcase/src/ui/view/hoverIntent.ts +9 -20
  122. package/dist/templates/examples/ui-showcase/src/ui/view/input.ts +1 -1
  123. package/dist/templates/examples/ui-showcase/src/ui/view/listbox.ts +1 -1
  124. package/dist/templates/examples/ui-showcase/src/ui/view/menu.ts +15 -15
  125. package/dist/templates/examples/ui-showcase/src/ui/view/popover.ts +1 -1
  126. package/dist/templates/examples/ui-showcase/src/ui/view/radioGroup.ts +1 -1
  127. package/dist/templates/examples/ui-showcase/src/ui/view/select.ts +1 -1
  128. package/dist/templates/examples/ui-showcase/src/ui/view/slider.ts +1 -1
  129. package/dist/templates/examples/ui-showcase/src/ui/view/switch.ts +1 -1
  130. package/dist/templates/examples/ui-showcase/src/ui/view/tabs.ts +7 -7
  131. package/dist/templates/examples/ui-showcase/src/ui/view/textarea.ts +1 -1
  132. package/dist/templates/examples/ui-showcase/src/ui/view/toast.ts +8 -8
  133. package/dist/templates/examples/ui-showcase/src/ui/view/tooltip.ts +1 -1
  134. package/dist/templates/examples/ui-showcase/src/ui/view/virtualList.ts +7 -7
  135. package/dist/templates/examples/view-transitions/src/artwork.ts +7 -7
  136. package/dist/templates/examples/view-transitions/src/main.ts +6 -6
  137. package/dist/templates/examples/view-transitions/src/route.ts +3 -3
  138. package/dist/templates/examples/weather/src/main.ts +42 -42
  139. package/dist/templates/examples/weather/src/story.test.ts +5 -5
  140. package/dist/templates/examples/web-components/src/main.ts +16 -16
  141. package/dist/templates/examples/websocket-chat/src/main.ts +30 -30
  142. package/dist/templates/release.json +13 -13
  143. package/dist/templates/rendering/ssg/src/main.ts +5 -5
  144. package/dist/templates/rendering/ssg/src/route.ts +2 -2
  145. package/dist/templates/rendering/ssr/server/main.ts +15 -15
  146. package/dist/templates/rendering/ssr/src/cookie.ts +3 -3
  147. package/dist/templates/rendering/ssr/src/main.ts +10 -10
  148. package/dist/utils/packages.js +17 -0
  149. package/package.json +1 -1
@@ -0,0 +1,127 @@
1
+ import { Deferred, Effect, PubSub, Stream } from 'effect'
2
+ import { Mount } from 'foldkit'
3
+ import { beforeEach, describe, expect, test, vi } from 'vitest'
4
+
5
+ import { MountMap } from './main'
6
+
7
+ const maplibre = vi.hoisted(() => {
8
+ let container: HTMLElement | undefined
9
+
10
+ return {
11
+ get container(): HTMLElement | undefined {
12
+ return container
13
+ },
14
+ set container(nextContainer: HTMLElement | undefined) {
15
+ container = nextContainer
16
+ },
17
+ disableKeyboard: vi.fn(),
18
+ enableKeyboard: vi.fn(),
19
+ makeMap: vi.fn(),
20
+ removeMap: vi.fn(),
21
+ }
22
+ })
23
+
24
+ vi.mock('maplibre-gl', () => {
25
+ class Map {
26
+ readonly keyboard = {
27
+ disable: maplibre.disableKeyboard,
28
+ enable: maplibre.enableKeyboard,
29
+ }
30
+
31
+ constructor({ container }: { container: HTMLElement }) {
32
+ maplibre.container = container
33
+ maplibre.makeMap()
34
+ }
35
+
36
+ remove(): void {
37
+ maplibre.removeMap()
38
+ }
39
+ }
40
+
41
+ class Marker {
42
+ readonly element: HTMLButtonElement
43
+
44
+ constructor({ element }: { element: HTMLButtonElement }) {
45
+ this.element = element
46
+ }
47
+
48
+ setLngLat(): this {
49
+ return this
50
+ }
51
+
52
+ addTo(): this {
53
+ maplibre.container?.appendChild(this.element)
54
+ return this
55
+ }
56
+ }
57
+
58
+ return { Map, Marker, setWorkerUrl: vi.fn() }
59
+ })
60
+
61
+ describe('MountMap', () => {
62
+ beforeEach(() => {
63
+ maplibre.container = undefined
64
+ vi.clearAllMocks()
65
+ })
66
+
67
+ test('makes the surviving map read-only while its view is paused', async () => {
68
+ const host = document.createElement('div')
69
+
70
+ await Effect.runPromise(
71
+ Effect.scoped(
72
+ Effect.gen(function* () {
73
+ const observedInitialLive = yield* Deferred.make<void>()
74
+ const observedPaused = yield* Deferred.make<void>()
75
+ const observedResumed = yield* Deferred.make<void>()
76
+ maplibre.enableKeyboard.mockImplementation(() => {
77
+ if (maplibre.enableKeyboard.mock.calls.length === 1) {
78
+ Effect.runSync(Deferred.succeed(observedInitialLive, undefined))
79
+ } else if (maplibre.enableKeyboard.mock.calls.length === 2) {
80
+ Effect.runSync(Deferred.succeed(observedResumed, undefined))
81
+ }
82
+ })
83
+ maplibre.disableKeyboard.mockImplementation(() => {
84
+ Effect.runSync(Deferred.succeed(observedPaused, undefined))
85
+ })
86
+
87
+ const viewStates = yield* PubSub.unbounded<Mount.ViewState>({
88
+ replay: 1,
89
+ })
90
+ yield* PubSub.publish(viewStates, Mount.ViewState.make('Live'))
91
+ yield* MountMap({ hostId: 'test-map-host' })
92
+ .f(host, Stream.fromPubSub(viewStates))
93
+ .pipe(Stream.runDrain, Effect.forkScoped)
94
+
95
+ yield* Deferred.await(observedInitialLive)
96
+ yield* Effect.yieldNow
97
+ expect(maplibre.makeMap).toHaveBeenCalledOnce()
98
+ const markers = host.querySelectorAll('button[data-location-id]')
99
+ expect(markers.length).toBeGreaterThan(0)
100
+ for (const marker of markers) {
101
+ expect(marker).toHaveProperty('disabled', false)
102
+ }
103
+
104
+ yield* PubSub.publish(viewStates, Mount.ViewState.make('Paused'))
105
+ yield* Deferred.await(observedPaused)
106
+ yield* Effect.yieldNow
107
+ expect(maplibre.makeMap).toHaveBeenCalledOnce()
108
+ for (const marker of markers) {
109
+ expect(marker).toHaveProperty('disabled', true)
110
+ }
111
+
112
+ yield* PubSub.publish(viewStates, Mount.ViewState.make('Live'))
113
+ yield* Deferred.await(observedResumed)
114
+ yield* Effect.yieldNow
115
+ expect(maplibre.makeMap).toHaveBeenCalledOnce()
116
+ for (const marker of markers) {
117
+ expect(marker).toHaveProperty('disabled', false)
118
+ }
119
+ }),
120
+ ),
121
+ )
122
+
123
+ expect(maplibre.disableKeyboard).toHaveBeenCalledOnce()
124
+ expect(maplibre.enableKeyboard).toHaveBeenCalledTimes(2)
125
+ expect(maplibre.removeMap).toHaveBeenCalledOnce()
126
+ })
127
+ })
@@ -1,4 +1,4 @@
1
- import { Array, Effect, Predicate, Schema as S } from 'effect'
1
+ import { Array, Effect, Predicate, Schema } from 'effect'
2
2
  import { KeyValueStore } from 'effect/unstable/persistence'
3
3
  import { Command } from 'foldkit'
4
4
 
@@ -14,8 +14,8 @@ import { PALETTE_THEMES, resolveColor } from './palette'
14
14
  export const SaveCanvas = Command.define('SaveCanvas', {
15
15
  args: {
16
16
  grid: Grid,
17
- gridSize: S.Number,
18
- paletteThemeIndex: S.Number,
17
+ gridSize: Schema.Number,
18
+ paletteThemeIndex: Schema.Number,
19
19
  selectedColorIndex: PaletteIndex,
20
20
  },
21
21
  messages: [Message.CompletedSaveCanvas],
@@ -28,7 +28,10 @@ export const SaveCanvas = Command.define('SaveCanvas', {
28
28
  paletteThemeIndex,
29
29
  selectedColorIndex,
30
30
  }
31
- yield* store.set(STORAGE_KEY, S.encodeSync(SavedCanvasJsonString)(data))
31
+ yield* store.set(
32
+ STORAGE_KEY,
33
+ Schema.encodeSync(SavedCanvasJsonString)(data),
34
+ )
32
35
  return Message.CompletedSaveCanvas()
33
36
  }).pipe(
34
37
  Effect.catch(() => Effect.succeed(Message.CompletedSaveCanvas())),
@@ -45,7 +48,11 @@ export const saveCanvas = (model: Model) =>
45
48
  })
46
49
 
47
50
  export const ExportPng = Command.define('ExportPng', {
48
- args: { grid: Grid, gridSize: S.Number, paletteThemeIndex: S.Number },
51
+ args: {
52
+ grid: Grid,
53
+ gridSize: Schema.Number,
54
+ paletteThemeIndex: Schema.Number,
55
+ },
49
56
  messages: [Message.SucceededExportPng, Message.FailedExportPng],
50
57
  execute: ({ grid, gridSize, paletteThemeIndex }) =>
51
58
  Effect.gen(function* () {
@@ -1,4 +1,4 @@
1
- import { Effect, Option, Schema as S } from 'effect'
1
+ import { Effect, Option, Schema } from 'effect'
2
2
  import { KeyValueStore } from 'effect/unstable/persistence'
3
3
  import { Runtime } from 'foldkit'
4
4
 
@@ -25,8 +25,8 @@ import {
25
25
 
26
26
  // FLAGS
27
27
 
28
- export const Flags = S.Struct({
29
- maybeSavedCanvas: S.Option(SavedCanvas),
28
+ export const Flags = Schema.Struct({
29
+ maybeSavedCanvas: Schema.Option(SavedCanvas),
30
30
  })
31
31
  export type Flags = typeof Flags.Type
32
32
 
@@ -35,7 +35,7 @@ export const flags: Effect.Effect<Flags> = Effect.gen(function* () {
35
35
  const json = yield* Effect.fromOption(
36
36
  Option.fromNullishOr(yield* store.get(STORAGE_KEY)),
37
37
  )
38
- const decoded = yield* S.decodeEffect(SavedCanvasJsonString)(json)
38
+ const decoded = yield* Schema.decodeEffect(SavedCanvasJsonString)(json)
39
39
  return Flags.make({ maybeSavedCanvas: Option.some(decoded) })
40
40
  }).pipe(
41
41
  Effect.catch(() =>
@@ -1,4 +1,4 @@
1
- import { Schema as S } from 'effect'
1
+ import { Schema } from 'effect'
2
2
  import { defineMessageUnion } from 'foldkit/message'
3
3
 
4
4
  import { Dialog, Listbox, RadioGroup } from '@foldkit/ui'
@@ -6,23 +6,23 @@ import { Dialog, Listbox, RadioGroup } from '@foldkit/ui'
6
6
  import { PaletteIndex, Tool } from './model'
7
7
 
8
8
  export const Message = defineMessageUnion({
9
- PressedCell: { x: S.Number, y: S.Number },
10
- EnteredCell: { x: S.Number, y: S.Number },
9
+ PressedCell: { x: Schema.Number, y: Schema.Number },
10
+ EnteredCell: { x: Schema.Number, y: Schema.Number },
11
11
  LeftCanvas: {},
12
12
  ReleasedMouse: {},
13
13
  SelectedColor: { colorIndex: PaletteIndex },
14
14
  SelectedTool: { tool: Tool },
15
- SelectedGridSize: { size: S.Number },
15
+ SelectedGridSize: { size: Schema.Number },
16
16
  ToggledMirrorHorizontal: {},
17
17
  ToggledMirrorVertical: {},
18
18
  ClickedUndo: {},
19
19
  ClickedRedo: {},
20
- ClickedHistoryStep: { stepIndex: S.Number },
21
- ClickedRedoStep: { stepIndex: S.Number },
20
+ ClickedHistoryStep: { stepIndex: Schema.Number },
21
+ ClickedRedoStep: { stepIndex: Schema.Number },
22
22
  ClickedClear: {},
23
23
  ClickedExport: {},
24
24
  SucceededExportPng: {},
25
- FailedExportPng: { error: S.String },
25
+ FailedExportPng: { error: Schema.String },
26
26
  GotErrorDialogMessage: { message: Dialog.Message },
27
27
  GotThemeListboxMessage: { message: Listbox.Message },
28
28
  GotToolRadioGroupMessage: { message: RadioGroup.Message },
@@ -1,67 +1,72 @@
1
- import { Option, Schema as S } from 'effect'
1
+ import { Option, Schema } from 'effect'
2
2
 
3
3
  import { Dialog, Listbox, RadioGroup } from '@foldkit/ui'
4
4
 
5
5
  // CONSTANT
6
6
 
7
- export const PaletteIndex = S.Literals([
7
+ export const PaletteIndex = Schema.Literals([
8
8
  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
9
9
  ])
10
10
  export type PaletteIndex = typeof PaletteIndex.Type
11
11
 
12
- export const HexColor = S.String.check(S.isPattern(/^#[0-9a-f]{6}$/)).pipe(
13
- S.brand('HexColor'),
14
- )
12
+ export const HexColor = Schema.String.check(
13
+ Schema.isPattern(/^#[0-9a-f]{6}$/),
14
+ ).pipe(Schema.brand('HexColor'))
15
15
  export type HexColor = typeof HexColor.Type
16
16
 
17
- export const Tool = S.Literals(['Brush', 'Fill', 'Eraser'])
17
+ export const Tool = Schema.Literals(['Brush', 'Fill', 'Eraser'])
18
18
  export type Tool = typeof Tool.Type
19
19
 
20
- export const MirrorMode = S.Literals(['None', 'Horizontal', 'Vertical', 'Both'])
20
+ export const MirrorMode = Schema.Literals([
21
+ 'None',
22
+ 'Horizontal',
23
+ 'Vertical',
24
+ 'Both',
25
+ ])
21
26
  export type MirrorMode = typeof MirrorMode.Type
22
27
 
23
- export const Cell = S.Option(PaletteIndex)
28
+ export const Cell = Schema.Option(PaletteIndex)
24
29
  export type Cell = typeof Cell.Type
25
30
 
26
- const Row = S.Array(Cell)
27
- export const Grid = S.Array(Row)
31
+ const Row = Schema.Array(Cell)
32
+ export const Grid = Schema.Array(Row)
28
33
  export type Grid = typeof Grid.Type
29
34
 
30
- export const Position = S.Struct({ x: S.Number, y: S.Number })
35
+ export const Position = Schema.Struct({ x: Schema.Number, y: Schema.Number })
31
36
 
32
- const SavedCell = S.Option(PaletteIndex)
33
- const SavedRow = S.Array(SavedCell)
34
- const SavedGrid = S.Array(SavedRow)
37
+ const SavedCell = Schema.Option(PaletteIndex)
38
+ const SavedRow = Schema.Array(SavedCell)
39
+ const SavedGrid = Schema.Array(SavedRow)
35
40
 
36
- export const SavedCanvas = S.Struct({
41
+ export const SavedCanvas = Schema.Struct({
37
42
  grid: SavedGrid,
38
- gridSize: S.Number,
39
- paletteThemeIndex: S.Number,
43
+ gridSize: Schema.Number,
44
+ paletteThemeIndex: Schema.Number,
40
45
  selectedColorIndex: PaletteIndex,
41
46
  })
42
47
  export type SavedCanvas = typeof SavedCanvas.Type
43
48
 
44
- export const SavedCanvasJsonString = S.fromJsonString(
45
- S.toCodecJson(SavedCanvas),
49
+ export const SavedCanvasJsonString = Schema.fromJsonString(
50
+ Schema.toCodecJson(SavedCanvas),
46
51
  )
47
52
 
48
53
  // MODEL
49
54
 
50
- export const Model = S.Struct({
55
+ export const Model = Schema.Struct({
51
56
  grid: Grid,
52
- undoStack: S.Array(Grid),
53
- redoStack: S.Array(Grid),
57
+ undoStack: Schema.Array(Grid),
58
+ redoStack: Schema.Array(Grid),
54
59
  selectedColorIndex: PaletteIndex,
55
- gridSize: S.Number,
60
+ gridSize: Schema.Number,
56
61
  tool: Tool,
57
62
  mirrorMode: MirrorMode,
58
- isDrawing: S.Boolean,
59
- maybeHoveredCell: S.Option(Position),
63
+ isDrawing: Schema.Boolean,
64
+ maybeHoveredCell: Schema.Option(Position),
60
65
  errorDialog: Dialog.Model,
61
- maybeExportError: S.Option(S.String),
62
- paletteThemeIndex: S.Number,
66
+ maybeExportError: Schema.Option(Schema.String),
67
+ paletteThemeIndex: Schema.Number,
63
68
  gridSizeConfirmDialog: Dialog.Model,
64
- maybePendingGridSize: S.Option(S.Number),
69
+ maybePendingGridSize: Schema.Option(Schema.Number),
65
70
  themeListbox: Listbox.Model,
66
71
  toolRadioGroup: RadioGroup.Model,
67
72
  gridSizeRadioGroup: RadioGroup.Model,
@@ -74,6 +79,6 @@ export const paletteIndexFromValue = (
74
79
  fallback: PaletteIndex,
75
80
  ): PaletteIndex =>
76
81
  Option.getOrElse(
77
- S.decodeUnknownOption(PaletteIndex)(Number(value)),
82
+ Schema.decodeUnknownOption(PaletteIndex)(Number(value)),
78
83
  () => fallback,
79
84
  )
@@ -1,4 +1,4 @@
1
- import { Effect, Option, Schema as S, Stream } from 'effect'
1
+ import { Effect, Option, Schema, Stream } from 'effect'
2
2
  import { Subscription } from 'foldkit'
3
3
 
4
4
  import { Message } from './message'
@@ -46,7 +46,7 @@ export const subscriptions = Subscription.make<Model, Message>()(entry => ({
46
46
  ),
47
47
 
48
48
  mouseRelease: entry(
49
- { isDrawing: S.Boolean },
49
+ { isDrawing: Schema.Boolean },
50
50
  {
51
51
  modelToDependencies: model => ({ isDrawing: model.isDrawing }),
52
52
  dependenciesToStream: ({ isDrawing }) =>
@@ -1,4 +1,4 @@
1
- import { Array, Match as M, Option } from 'effect'
1
+ import { Array, Match, Option } from 'effect'
2
2
  import { Update } from 'foldkit'
3
3
  import { evo } from 'foldkit/struct'
4
4
 
@@ -32,7 +32,7 @@ import {
32
32
 
33
33
  type UpdateReturn = Update.Return<Model, Message>
34
34
 
35
- const withUpdateReturn = M.withReturnType<UpdateReturn>()
35
+ const withUpdateReturn = Match.withReturnType<UpdateReturn>()
36
36
 
37
37
  const applyEraser = (model: Model, x: number, y: number) => {
38
38
  const positions = getMirroredPositions(x, y, model.gridSize, model.mirrorMode)
@@ -51,15 +51,14 @@ const applyFill = (model: Model, x: number, y: number) => {
51
51
  )
52
52
  }
53
53
 
54
- const foldErrorDialogOutMessage = M.type<Dialog.OutMessage>().pipe(
55
- M.withReturnType<Update.Step<Model, Message>>(),
56
- M.tagsExhaustive({
57
- Opened: () => model => ({ model }),
58
- Closed: () => model => ({
59
- model: evo(model, { maybeExportError: () => Option.none() }),
60
- }),
54
+ const foldErrorDialogOutMessage = Dialog.OutMessage.match<
55
+ Update.Step<Model, Message>
56
+ >({
57
+ Opened: () => model => ({ model }),
58
+ Closed: () => model => ({
59
+ model: evo(model, { maybeExportError: () => Option.none() }),
61
60
  }),
62
- )
61
+ })
63
62
 
64
63
  const foldErrorDialog = Update.foldChild({
65
64
  update: Dialog.update,
@@ -79,27 +78,24 @@ const foldErrorDialogOpen = Update.foldChildStep({
79
78
  foldOutMessage: foldErrorDialogOutMessage,
80
79
  })
81
80
 
82
- const foldThemeListboxOutMessage: (
83
- outMessage: Listbox.OutMessage,
84
- ) => Update.Step<Model, Message> = M.type<Listbox.OutMessage>().pipe(
85
- M.withReturnType<Update.Step<Model, Message>>(),
86
- M.tagsExhaustive({
87
- Selected:
88
- ({ value }) =>
89
- model => {
90
- const themeIndex = Number(value)
91
- const maybeNextTheme = Array.get(PALETTE_THEMES, themeIndex)
92
- if (Option.isNone(maybeNextTheme)) {
93
- return { model }
94
- }
95
- const nextModel = evo(model, {
96
- paletteThemeIndex: () => themeIndex,
97
- selectedColorIndex: () => DEFAULT_COLOR_INDEX,
98
- })
99
- return { model: nextModel, commands: [saveCanvas(nextModel)] }
100
- },
101
- }),
102
- )
81
+ const foldThemeListboxOutMessage = Listbox.OutMessage.match<
82
+ Update.Step<Model, Message>
83
+ >({
84
+ Selected:
85
+ ({ value }) =>
86
+ model => {
87
+ const themeIndex = Number(value)
88
+ const maybeNextTheme = Array.get(PALETTE_THEMES, themeIndex)
89
+ if (Option.isNone(maybeNextTheme)) {
90
+ return { model }
91
+ }
92
+ const nextModel = evo(model, {
93
+ paletteThemeIndex: () => themeIndex,
94
+ selectedColorIndex: () => DEFAULT_COLOR_INDEX,
95
+ })
96
+ return { model: nextModel, commands: [saveCanvas(nextModel)] }
97
+ },
98
+ })
103
99
 
104
100
  const foldThemeListbox = Update.foldChild({
105
101
  update: ThemeListbox.update,
@@ -110,15 +106,14 @@ const foldThemeListbox = Update.foldChild({
110
106
  foldOutMessage: foldThemeListboxOutMessage,
111
107
  })
112
108
 
113
- const foldGridSizeConfirmDialogOutMessage = M.type<Dialog.OutMessage>().pipe(
114
- M.withReturnType<Update.Step<Model, Message>>(),
115
- M.tagsExhaustive({
116
- Opened: () => model => ({ model }),
117
- Closed: () => model => ({
118
- model: evo(model, { maybePendingGridSize: () => Option.none() }),
119
- }),
109
+ const foldGridSizeConfirmDialogOutMessage = Dialog.OutMessage.match<
110
+ Update.Step<Model, Message>
111
+ >({
112
+ Opened: () => model => ({ model }),
113
+ Closed: () => model => ({
114
+ model: evo(model, { maybePendingGridSize: () => Option.none() }),
120
115
  }),
121
- )
116
+ })
122
117
 
123
118
  const foldGridSizeConfirmDialog = Update.foldChild({
124
119
  update: Dialog.update,
@@ -159,15 +154,15 @@ const selectColor = (model: Model, colorIndex: PaletteIndex): UpdateReturn => {
159
154
  return { model: nextModel, commands: [saveCanvas(nextModel)] }
160
155
  }
161
156
 
162
- const foldToolRadioGroupOutMessage = M.type<RadioGroup.OutMessage<Tool>>().pipe(
163
- M.withReturnType<Update.Step<Model, Message>>(),
164
- M.tagsExhaustive({
165
- Selected:
166
- ({ value }) =>
167
- model =>
168
- selectTool(model, value),
169
- }),
170
- )
157
+ const foldToolRadioGroupOutMessage = RadioGroup.OutMessage.match<
158
+ Update.Step<Model, Message>,
159
+ RadioGroup.OutMessage<Tool>
160
+ >({
161
+ Selected:
162
+ ({ value }) =>
163
+ model =>
164
+ selectTool(model, value),
165
+ })
171
166
 
172
167
  const foldToolRadioGroup = Update.foldChild({
173
168
  update: ToolRadioGroup.update,
@@ -178,15 +173,14 @@ const foldToolRadioGroup = Update.foldChild({
178
173
  foldOutMessage: foldToolRadioGroupOutMessage,
179
174
  })
180
175
 
181
- const foldGridSizeRadioGroupOutMessage = M.type<RadioGroup.OutMessage>().pipe(
182
- M.withReturnType<Update.Step<Model, Message>>(),
183
- M.tagsExhaustive({
184
- Selected:
185
- ({ value }) =>
186
- model =>
187
- requestGridSizeChange(model, Number(value)),
188
- }),
189
- )
176
+ const foldGridSizeRadioGroupOutMessage = RadioGroup.OutMessage.match<
177
+ Update.Step<Model, Message>
178
+ >({
179
+ Selected:
180
+ ({ value }) =>
181
+ model =>
182
+ requestGridSizeChange(model, Number(value)),
183
+ })
190
184
 
191
185
  const foldGridSizeRadioGroup = Update.foldChild({
192
186
  update: GridSizeRadioGroup.update,
@@ -197,18 +191,17 @@ const foldGridSizeRadioGroup = Update.foldChild({
197
191
  foldOutMessage: foldGridSizeRadioGroupOutMessage,
198
192
  })
199
193
 
200
- const foldPaletteRadioGroupOutMessage = M.type<RadioGroup.OutMessage>().pipe(
201
- M.withReturnType<Update.Step<Model, Message>>(),
202
- M.tagsExhaustive({
203
- Selected:
204
- ({ value }) =>
205
- model =>
206
- selectColor(
207
- model,
208
- paletteIndexFromValue(value, model.selectedColorIndex),
209
- ),
210
- }),
211
- )
194
+ const foldPaletteRadioGroupOutMessage = RadioGroup.OutMessage.match<
195
+ Update.Step<Model, Message>
196
+ >({
197
+ Selected:
198
+ ({ value }) =>
199
+ model =>
200
+ selectColor(
201
+ model,
202
+ paletteIndexFromValue(value, model.selectedColorIndex),
203
+ ),
204
+ })
212
205
 
213
206
  const foldPaletteRadioGroup = Update.foldChild({
214
207
  update: PaletteRadioGroup.update,
@@ -222,9 +215,9 @@ const foldPaletteRadioGroup = Update.foldChild({
222
215
  export const update = (model: Model, message: Message) =>
223
216
  Message.match<UpdateReturn>(message, {
224
217
  PressedCell: ({ x, y }) =>
225
- M.value(model.tool).pipe(
218
+ Match.value(model.tool).pipe(
226
219
  withUpdateReturn,
227
- M.when('Brush', () => ({
220
+ Match.when('Brush', () => ({
228
221
  model: evo(model, {
229
222
  grid: () => applyBrush(model, x, y),
230
223
  undoStack: () => pushHistory(model.undoStack, model.grid),
@@ -232,7 +225,7 @@ export const update = (model: Model, message: Message) =>
232
225
  isDrawing: () => true,
233
226
  }),
234
227
  })),
235
- M.when('Fill', () => {
228
+ Match.when('Fill', () => {
236
229
  const nextModel = evo(model, {
237
230
  grid: () => applyFill(model, x, y),
238
231
  undoStack: () => pushHistory(model.undoStack, model.grid),
@@ -240,7 +233,7 @@ export const update = (model: Model, message: Message) =>
240
233
  })
241
234
  return { model: nextModel, commands: [saveCanvas(nextModel)] }
242
235
  }),
243
- M.when('Eraser', () => ({
236
+ Match.when('Eraser', () => ({
244
237
  model: evo(model, {
245
238
  grid: () => applyEraser(model, x, y),
246
239
  undoStack: () => pushHistory(model.undoStack, model.grid),
@@ -248,7 +241,7 @@ export const update = (model: Model, message: Message) =>
248
241
  isDrawing: () => true,
249
242
  }),
250
243
  })),
251
- M.exhaustive,
244
+ Match.exhaustive,
252
245
  ),
253
246
 
254
247
  EnteredCell: ({ x, y }) => {
@@ -299,23 +292,23 @@ export const update = (model: Model, message: Message) =>
299
292
  foldPaletteRadioGroup(model, message),
300
293
 
301
294
  ToggledMirrorHorizontal: () => {
302
- const nextMirrorMode = M.value(model.mirrorMode).pipe(
303
- M.when('None', () => 'Horizontal' as const),
304
- M.when('Horizontal', () => 'None' as const),
305
- M.when('Vertical', () => 'Both' as const),
306
- M.when('Both', () => 'Vertical' as const),
307
- M.exhaustive,
295
+ const nextMirrorMode = Match.value(model.mirrorMode).pipe(
296
+ Match.when('None', () => 'Horizontal' as const),
297
+ Match.when('Horizontal', () => 'None' as const),
298
+ Match.when('Vertical', () => 'Both' as const),
299
+ Match.when('Both', () => 'Vertical' as const),
300
+ Match.exhaustive,
308
301
  )
309
302
  return { model: evo(model, { mirrorMode: () => nextMirrorMode }) }
310
303
  },
311
304
 
312
305
  ToggledMirrorVertical: () => {
313
- const nextMirrorMode = M.value(model.mirrorMode).pipe(
314
- M.when('None', () => 'Vertical' as const),
315
- M.when('Vertical', () => 'None' as const),
316
- M.when('Horizontal', () => 'Both' as const),
317
- M.when('Both', () => 'Horizontal' as const),
318
- M.exhaustive,
306
+ const nextMirrorMode = Match.value(model.mirrorMode).pipe(
307
+ Match.when('None', () => 'Vertical' as const),
308
+ Match.when('Vertical', () => 'None' as const),
309
+ Match.when('Horizontal', () => 'Both' as const),
310
+ Match.when('Both', () => 'Horizontal' as const),
311
+ Match.exhaustive,
319
312
  )
320
313
  return { model: evo(model, { mirrorMode: () => nextMirrorMode }) }
321
314
  },