create-foldkit-app 0.35.1 → 0.35.2
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/FOLDKIT.md +2 -2
- package/dist/templates/examples/api-cache/package.json +2 -2
- package/dist/templates/examples/api-cache/src/main.fixture.ts +4 -4
- package/dist/templates/examples/api-cache/src/main.ts +12 -12
- package/dist/templates/examples/api-cache/src/story.test.ts +6 -6
- package/dist/templates/examples/auth/package.json +2 -2
- package/dist/templates/examples/auth/src/page/loggedOut/page/login.scene.test.ts +2 -2
- package/dist/templates/examples/auth/src/page/loggedOut/page/login.story.test.ts +2 -2
- package/dist/templates/examples/auth/src/page/loggedOut/page/login.ts +5 -5
- package/dist/templates/examples/auth/src/page/loggedOut/update.ts +2 -2
- package/dist/templates/examples/auth/src/scene.test.ts +2 -2
- package/dist/templates/examples/auth/src/update.ts +3 -3
- package/dist/templates/examples/canvas-art/package.json +2 -2
- package/dist/templates/examples/canvas-art/src/main.ts +6 -6
- package/dist/templates/examples/canvas-art/src/scene.test.ts +3 -3
- package/dist/templates/examples/canvas-art/src/story.test.ts +3 -3
- package/dist/templates/examples/charting/package.json +2 -2
- package/dist/templates/examples/charting/src/main.fixture.ts +2 -2
- package/dist/templates/examples/charting/src/scene.test.ts +3 -3
- package/dist/templates/examples/charting/src/story.test.ts +2 -2
- package/dist/templates/examples/charting/src/update.ts +18 -16
- package/dist/templates/examples/counter/package.json +2 -2
- package/dist/templates/examples/counter/src/main.ts +4 -4
- package/dist/templates/examples/counters/package.json +2 -2
- package/dist/templates/examples/counters/src/counter.ts +3 -3
- package/dist/templates/examples/counters/src/main.ts +7 -5
- package/dist/templates/examples/crash-view/package.json +2 -2
- package/dist/templates/examples/embedding/package.json +2 -2
- package/dist/templates/examples/embedding/src/main.ts +5 -3
- package/dist/templates/examples/embedding/src/scene.test.ts +2 -2
- package/dist/templates/examples/embedding/src/story.test.ts +2 -2
- package/dist/templates/examples/form/package.json +2 -2
- package/dist/templates/examples/form/src/main.ts +9 -9
- package/dist/templates/examples/form/src/scene.test.ts +5 -5
- package/dist/templates/examples/form/src/story.test.ts +4 -4
- package/dist/templates/examples/generative-art/package.json +2 -2
- package/dist/templates/examples/generative-art/src/scene.test.ts +2 -2
- package/dist/templates/examples/generative-art/src/story.test.ts +3 -3
- package/dist/templates/examples/generative-art/src/update.ts +11 -11
- package/dist/templates/examples/interrupting-commands/package.json +2 -2
- package/dist/templates/examples/interrupting-commands/src/main.ts +8 -6
- package/dist/templates/examples/job-application/package.json +2 -2
- package/dist/templates/examples/job-application/src/main.fixture.ts +9 -9
- package/dist/templates/examples/job-application/src/scene.test.ts +13 -13
- package/dist/templates/examples/job-application/src/step/attachments/attachments.ts +7 -7
- package/dist/templates/examples/job-application/src/step/coverLetter/coverLetter.ts +2 -2
- package/dist/templates/examples/job-application/src/step/education/education.ts +6 -6
- package/dist/templates/examples/job-application/src/step/education/entry/entry.ts +14 -8
- package/dist/templates/examples/job-application/src/step/personalInfo/personalInfo.ts +20 -15
- package/dist/templates/examples/job-application/src/step/personalInfo/story.test.ts +2 -2
- package/dist/templates/examples/job-application/src/step/skills/entry/entry.ts +7 -5
- package/dist/templates/examples/job-application/src/step/skills/skills.ts +6 -6
- package/dist/templates/examples/job-application/src/step/workHistory/entry/entry.ts +13 -12
- package/dist/templates/examples/job-application/src/step/workHistory/workHistory.ts +6 -6
- package/dist/templates/examples/job-application/src/story.test.ts +10 -10
- package/dist/templates/examples/job-application/src/update.ts +25 -18
- package/dist/templates/examples/kanban/package.json +2 -2
- package/dist/templates/examples/kanban/src/domain/column.ts +9 -6
- package/dist/templates/examples/kanban/src/update.ts +8 -8
- package/dist/templates/examples/managed-resource-layer/package.json +2 -2
- package/dist/templates/examples/managed-resource-layer/src/main.ts +11 -7
- package/dist/templates/examples/managed-resource-layer/src/story.test.ts +3 -3
- package/dist/templates/examples/map/package.json +2 -2
- package/dist/templates/examples/map/src/main.fixture.ts +2 -2
- package/dist/templates/examples/map/src/main.ts +11 -11
- package/dist/templates/examples/map/src/scene.test.ts +4 -4
- package/dist/templates/examples/map/src/story.test.ts +4 -4
- package/dist/templates/examples/pixel-art/package.json +2 -2
- package/dist/templates/examples/pixel-art/src/comparison.bench.test.ts +2 -2
- package/dist/templates/examples/pixel-art/src/main.bench.ts +7 -3
- package/dist/templates/examples/pixel-art/src/scene.test.ts +5 -5
- package/dist/templates/examples/pixel-art/src/story.test.ts +4 -4
- package/dist/templates/examples/pixel-art/src/subscription.ts +2 -2
- package/dist/templates/examples/pixel-art/src/update.ts +49 -33
- package/dist/templates/examples/query-sync/package.json +2 -2
- package/dist/templates/examples/query-sync/src/main.ts +4 -4
- package/dist/templates/examples/query-sync/src/scene.test.ts +4 -4
- package/dist/templates/examples/query-sync/src/story.test.ts +2 -2
- package/dist/templates/examples/route-transitions/package.json +2 -2
- package/dist/templates/examples/route-transitions/src/main.ts +10 -10
- package/dist/templates/examples/route-transitions/src/story.test.ts +10 -6
- package/dist/templates/examples/routing/package.json +2 -2
- package/dist/templates/examples/routing/src/main.ts +13 -17
- package/dist/templates/examples/routing/src/page/people.ts +4 -4
- package/dist/templates/examples/shopping-cart/package.json +2 -2
- package/dist/templates/examples/shopping-cart/src/domain/cart.ts +4 -4
- package/dist/templates/examples/shopping-cart/src/main.ts +12 -12
- package/dist/templates/examples/shopping-cart/src/page/products.ts +2 -2
- package/dist/templates/examples/shopping-cart/src/scene.test.ts +10 -8
- package/dist/templates/examples/shopping-cart/src/story.test.ts +7 -7
- package/dist/templates/examples/slow-warnings/package.json +2 -2
- package/dist/templates/examples/slow-warnings/src/handleSlow.test.ts +2 -2
- package/dist/templates/examples/slow-warnings/src/main.ts +8 -8
- package/dist/templates/examples/slow-warnings/src/scene.test.ts +2 -2
- package/dist/templates/examples/slow-warnings/src/story.test.ts +2 -2
- package/dist/templates/examples/snake/package.json +2 -2
- package/dist/templates/examples/snake/src/main.ts +10 -10
- package/dist/templates/examples/snake/src/scene.test.ts +10 -5
- package/dist/templates/examples/snake/src/story.test.ts +6 -6
- package/dist/templates/examples/ssg/package.json +2 -2
- package/dist/templates/examples/ssg/src/main.ts +3 -3
- package/dist/templates/examples/ssr/package.json +4 -4
- package/dist/templates/examples/ssr/src/main.ts +3 -3
- package/dist/templates/examples/state-machine/package.json +2 -2
- package/dist/templates/examples/state-machine/src/main.ts +14 -10
- package/dist/templates/examples/stopwatch/package.json +2 -2
- package/dist/templates/examples/stopwatch/src/main.ts +5 -5
- package/dist/templates/examples/stopwatch/src/story.test.ts +2 -2
- package/dist/templates/examples/todo/package.json +2 -2
- package/dist/templates/examples/todo/src/main.ts +17 -17
- package/dist/templates/examples/todo/src/scene.test.ts +4 -4
- package/dist/templates/examples/todo/src/story.test.ts +22 -16
- package/dist/templates/examples/ui-showcase/package.json +2 -2
- package/dist/templates/examples/ui-showcase/src/main.ts +8 -5
- package/dist/templates/examples/ui-showcase/src/story.test.ts +3 -3
- package/dist/templates/examples/ui-showcase/src/ui/init.ts +4 -1
- package/dist/templates/examples/ui-showcase/src/ui/subscriptions.ts +10 -0
- package/dist/templates/examples/ui-showcase/src/ui/update.ts +119 -91
- package/dist/templates/examples/ui-showcase/src/ui/view/toast.ts +20 -3
- package/dist/templates/examples/view-transitions/package.json +2 -2
- package/dist/templates/examples/view-transitions/src/main.ts +3 -3
- package/dist/templates/examples/weather/package.json +2 -2
- package/dist/templates/examples/weather/src/main.ts +5 -5
- package/dist/templates/examples/web-components/package.json +2 -2
- package/dist/templates/examples/web-components/src/main.ts +4 -4
- package/dist/templates/examples/websocket-chat/package.json +2 -2
- package/dist/templates/examples/websocket-chat/src/main.ts +8 -8
- package/dist/templates/examples/websocket-chat/src/scene.test.ts +18 -6
- package/dist/templates/examples/websocket-chat/src/story.test.ts +15 -9
- package/dist/templates/release.json +13 -13
- package/dist/templates/rendering/ssg/src/main.ts +3 -3
- package/dist/templates/rendering/ssr/scripts/serve.ts +2 -2
- package/dist/templates/rendering/ssr/src/main.ts +3 -3
- package/package.json +5 -5
|
@@ -16,7 +16,7 @@ import type { Document, Html } from 'foldkit/html'
|
|
|
16
16
|
import { HtmlBuilder } from 'foldkit/html'
|
|
17
17
|
import { defineMessageUnion } from 'foldkit/message'
|
|
18
18
|
import { defineTaggedUnion } from 'foldkit/schema'
|
|
19
|
-
import {
|
|
19
|
+
import { modifyFields } from 'foldkit/struct'
|
|
20
20
|
import type { Map as MapInstance } from 'maplibre-gl'
|
|
21
21
|
import maplibreWorkerUrl from 'maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url'
|
|
22
22
|
|
|
@@ -210,19 +210,19 @@ const findLocation = (
|
|
|
210
210
|
export const update = (model: Model, message: Message) =>
|
|
211
211
|
Message.match<Update.Return<Model, Message>>(message, {
|
|
212
212
|
SucceededMountMap: ({ hostId }) => ({
|
|
213
|
-
model:
|
|
213
|
+
model: modifyFields(model, { maybeMapHostId: () => Option.some(hostId) }),
|
|
214
214
|
}),
|
|
215
215
|
|
|
216
216
|
FailedMountMap: ({ reason }) => ({
|
|
217
|
-
model:
|
|
217
|
+
model: modifyFields(model, { maybeMapError: () => Option.some(reason) }),
|
|
218
218
|
}),
|
|
219
219
|
|
|
220
220
|
MovedMap: ({ bounds }) => ({
|
|
221
|
-
model:
|
|
221
|
+
model: modifyFields(model, { maybeBounds: () => Option.some(bounds) }),
|
|
222
222
|
}),
|
|
223
223
|
|
|
224
224
|
ClickedMarker: ({ locationId }) => ({
|
|
225
|
-
model:
|
|
225
|
+
model: modifyFields(model, {
|
|
226
226
|
maybeSelectedLocationId: () => Option.some(locationId),
|
|
227
227
|
}),
|
|
228
228
|
}),
|
|
@@ -231,7 +231,7 @@ export const update = (model: Model, message: Message) =>
|
|
|
231
231
|
Option.match(findLocation(model, locationId), {
|
|
232
232
|
onNone: () => ({ model }),
|
|
233
233
|
onSome: ({ lng, lat }) => ({
|
|
234
|
-
model:
|
|
234
|
+
model: modifyFields(model, {
|
|
235
235
|
maybeSelectedLocationId: () => Option.some(locationId),
|
|
236
236
|
}),
|
|
237
237
|
commands: [
|
|
@@ -246,25 +246,25 @@ export const update = (model: Model, message: Message) =>
|
|
|
246
246
|
}),
|
|
247
247
|
|
|
248
248
|
UpdatedSearchQuery: ({ value }) => ({
|
|
249
|
-
model:
|
|
249
|
+
model: modifyFields(model, { searchQuery: () => value }),
|
|
250
250
|
}),
|
|
251
251
|
|
|
252
252
|
ClickedFindMe: () => ({
|
|
253
|
-
model:
|
|
253
|
+
model: modifyFields(model, {
|
|
254
254
|
geolocateState: () => GeolocateState.Locating(),
|
|
255
255
|
}),
|
|
256
256
|
commands: [LockBodyScroll(), Geolocate()],
|
|
257
257
|
}),
|
|
258
258
|
|
|
259
259
|
DismissedGeolocate: () => ({
|
|
260
|
-
model:
|
|
260
|
+
model: modifyFields(model, {
|
|
261
261
|
geolocateState: () => GeolocateState.Idle(),
|
|
262
262
|
}),
|
|
263
263
|
commands: [UnlockBodyScroll()],
|
|
264
264
|
}),
|
|
265
265
|
|
|
266
266
|
SucceededGeolocate: ({ lng, lat }) => ({
|
|
267
|
-
model:
|
|
267
|
+
model: modifyFields(model, {
|
|
268
268
|
maybeUserLocation: () => Option.some({ lng, lat }),
|
|
269
269
|
geolocateState: () => GeolocateState.Idle(),
|
|
270
270
|
}),
|
|
@@ -280,7 +280,7 @@ export const update = (model: Model, message: Message) =>
|
|
|
280
280
|
}),
|
|
281
281
|
|
|
282
282
|
FailedGeolocate: ({ reason }) => ({
|
|
283
|
-
model:
|
|
283
|
+
model: modifyFields(model, {
|
|
284
284
|
geolocateState: () => GeolocateState.Failed({ reason }),
|
|
285
285
|
}),
|
|
286
286
|
}),
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
text,
|
|
12
12
|
type,
|
|
13
13
|
} from 'foldkit/scene'
|
|
14
|
-
import {
|
|
14
|
+
import { modifyFields } from 'foldkit/struct'
|
|
15
15
|
import { describe, test } from 'vitest'
|
|
16
16
|
|
|
17
17
|
import {
|
|
@@ -93,7 +93,7 @@ describe('view', () => {
|
|
|
93
93
|
scene(
|
|
94
94
|
{ update, view },
|
|
95
95
|
given(
|
|
96
|
-
|
|
96
|
+
modifyFields(mountedModel, {
|
|
97
97
|
geolocateState: () =>
|
|
98
98
|
GeolocateState.Failed({
|
|
99
99
|
reason: 'Permission denied',
|
|
@@ -112,7 +112,7 @@ describe('view', () => {
|
|
|
112
112
|
scene(
|
|
113
113
|
{ update, view },
|
|
114
114
|
given(
|
|
115
|
-
|
|
115
|
+
modifyFields(initialModel, {
|
|
116
116
|
maybeMapError: () => Option.some('Network timeout'),
|
|
117
117
|
}),
|
|
118
118
|
),
|
|
@@ -126,7 +126,7 @@ describe('view', () => {
|
|
|
126
126
|
scene(
|
|
127
127
|
{ update, view },
|
|
128
128
|
given(
|
|
129
|
-
|
|
129
|
+
modifyFields(mountedModel, {
|
|
130
130
|
maybeBounds: () =>
|
|
131
131
|
Option.some({
|
|
132
132
|
west: -180,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Option } from 'effect'
|
|
2
2
|
import { Command, given, message, model, story } from 'foldkit/story'
|
|
3
|
-
import {
|
|
3
|
+
import { modifyFields } from 'foldkit/struct'
|
|
4
4
|
import { expect, test } from 'vitest'
|
|
5
5
|
|
|
6
6
|
import {
|
|
@@ -141,7 +141,7 @@ test('a successful geolocation result clears the locating state and flies the ma
|
|
|
141
141
|
story(
|
|
142
142
|
update,
|
|
143
143
|
given(
|
|
144
|
-
|
|
144
|
+
modifyFields(mountedModel, {
|
|
145
145
|
geolocateState: () => GeolocateState.Locating(),
|
|
146
146
|
}),
|
|
147
147
|
),
|
|
@@ -162,7 +162,7 @@ test('a failed geolocation result surfaces the reason in the geolocate state', (
|
|
|
162
162
|
story(
|
|
163
163
|
update,
|
|
164
164
|
given(
|
|
165
|
-
|
|
165
|
+
modifyFields(initialModel, {
|
|
166
166
|
geolocateState: () => GeolocateState.Locating(),
|
|
167
167
|
}),
|
|
168
168
|
),
|
|
@@ -180,7 +180,7 @@ test('dismissing the geolocate overlay returns to idle', () => {
|
|
|
180
180
|
story(
|
|
181
181
|
update,
|
|
182
182
|
given(
|
|
183
|
-
|
|
183
|
+
modifyFields(initialModel, {
|
|
184
184
|
geolocateState: () => GeolocateState.Failed({ reason: 'Timed out' }),
|
|
185
185
|
}),
|
|
186
186
|
),
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
"bench": "vitest run --config vitest.bench.config.ts"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@effect/platform-browser": "4.0.0-rc.
|
|
13
|
+
"@effect/platform-browser": "4.0.0-rc.116",
|
|
14
14
|
"@foldkit/ui": "workspace:*",
|
|
15
15
|
"clsx": "^2.1.1",
|
|
16
|
-
"effect": "4.0.0-rc.
|
|
16
|
+
"effect": "4.0.0-rc.116",
|
|
17
17
|
"foldkit": "workspace:*"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Run: pnpm --filter pixel-art-example exec vitest run src/comparison.bench.ts
|
|
5
5
|
*/
|
|
6
6
|
import { Option } from 'effect'
|
|
7
|
-
import {
|
|
7
|
+
import { modifyFields } from 'foldkit/struct'
|
|
8
8
|
import { test } from 'vitest'
|
|
9
9
|
|
|
10
10
|
import { Dialog, Listbox } from '@foldkit/ui'
|
|
@@ -162,7 +162,7 @@ test('benchmark', () => {
|
|
|
162
162
|
{
|
|
163
163
|
name: 'Flood fill (16\u00d716)',
|
|
164
164
|
foldkit: () => {
|
|
165
|
-
const m: Model =
|
|
165
|
+
const m: Model = modifyFields(foldkitModel, { tool: () => 'Fill' })
|
|
166
166
|
update(m, Message.PressedCell({ x: 0, y: 0 }))
|
|
167
167
|
},
|
|
168
168
|
react: () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Option } from 'effect'
|
|
2
|
-
import {
|
|
2
|
+
import { modifyFields } from 'foldkit/struct'
|
|
3
3
|
import { describe, test } from 'vitest'
|
|
4
4
|
|
|
5
5
|
import { Dialog, Listbox, RadioGroup } from '@foldkit/ui'
|
|
@@ -82,7 +82,9 @@ describe('update: single operations', () => {
|
|
|
82
82
|
|
|
83
83
|
test('flood fill (empty grid)', async ({ bench }) => {
|
|
84
84
|
await bench('flood fill (empty grid)', () => {
|
|
85
|
-
const fillModel: Model =
|
|
85
|
+
const fillModel: Model = modifyFields(initialModel, {
|
|
86
|
+
tool: () => 'Fill',
|
|
87
|
+
})
|
|
86
88
|
dispatch(fillModel, Message.PressedCell({ x: 0, y: 0 }))
|
|
87
89
|
}).run()
|
|
88
90
|
})
|
|
@@ -135,7 +137,9 @@ describe('update: paint sequence (16x16 grid)', () => {
|
|
|
135
137
|
|
|
136
138
|
test('paint 50 cells with mirror mode', async ({ bench }) => {
|
|
137
139
|
await bench('paint 50 cells with mirror mode', () => {
|
|
138
|
-
let model: Model =
|
|
140
|
+
let model: Model = modifyFields(initialModel, {
|
|
141
|
+
mirrorMode: () => 'Both',
|
|
142
|
+
})
|
|
139
143
|
for (let i = 0; i < 50; i++) {
|
|
140
144
|
const x = (i * 7 + 3) % GRID_SIZE
|
|
141
145
|
const y = (i * 11 + 5) % GRID_SIZE
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
scene,
|
|
10
10
|
text,
|
|
11
11
|
} from 'foldkit/scene'
|
|
12
|
-
import {
|
|
12
|
+
import { modifyFields } from 'foldkit/struct'
|
|
13
13
|
import { describe, test } from 'vitest'
|
|
14
14
|
|
|
15
15
|
import { Dialog, Listbox, RadioGroup } from '@foldkit/ui'
|
|
@@ -53,7 +53,7 @@ const createTestModel = (): Model => ({
|
|
|
53
53
|
})
|
|
54
54
|
|
|
55
55
|
const createPaintedModel = (): Model =>
|
|
56
|
-
|
|
56
|
+
modifyFields(createTestModel(), {
|
|
57
57
|
grid: () =>
|
|
58
58
|
createEmptyGrid(4).map((row, y) =>
|
|
59
59
|
row.map((cell, x) =>
|
|
@@ -186,7 +186,7 @@ describe('history panel', () => {
|
|
|
186
186
|
})
|
|
187
187
|
|
|
188
188
|
test('undo enables after painting and re-disables after undoing', () => {
|
|
189
|
-
const modelWithHistory: Model =
|
|
189
|
+
const modelWithHistory: Model = modifyFields(createTestModel(), {
|
|
190
190
|
grid: () =>
|
|
191
191
|
createEmptyGrid(4).map((row, y) =>
|
|
192
192
|
row.map((cell, x) =>
|
|
@@ -228,7 +228,7 @@ describe('grid size change', () => {
|
|
|
228
228
|
})
|
|
229
229
|
|
|
230
230
|
test('confirming grid size change closes dialog and saves canvas', () => {
|
|
231
|
-
const modelWithPendingResize: Model =
|
|
231
|
+
const modelWithPendingResize: Model = modifyFields(createTestModel(), {
|
|
232
232
|
maybePendingGridSize: () => Option.some(8),
|
|
233
233
|
gridSizeConfirmDialog: () =>
|
|
234
234
|
Dialog.boot({
|
|
@@ -254,7 +254,7 @@ describe('grid size change', () => {
|
|
|
254
254
|
})
|
|
255
255
|
|
|
256
256
|
test('cancelling grid size change keeps current size', () => {
|
|
257
|
-
const modelWithPendingResize: Model =
|
|
257
|
+
const modelWithPendingResize: Model = modifyFields(createTestModel(), {
|
|
258
258
|
maybePendingGridSize: () => Option.some(8),
|
|
259
259
|
gridSizeConfirmDialog: () =>
|
|
260
260
|
Dialog.boot({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Equal, Option } from 'effect'
|
|
2
2
|
import { Command, given, message, model, story } from 'foldkit/story'
|
|
3
|
-
import {
|
|
3
|
+
import { modifyFields } from 'foldkit/struct'
|
|
4
4
|
import { describe, expect, test } from 'vitest'
|
|
5
5
|
|
|
6
6
|
import { Dialog, Listbox, RadioGroup } from '@foldkit/ui'
|
|
@@ -254,7 +254,7 @@ describe('fill tool', () => {
|
|
|
254
254
|
const gridWithBarrier = createEmptyGrid(4).map(row =>
|
|
255
255
|
row.map((cell, x) => (x === 2 ? Option.some<PaletteIndex>(1) : cell)),
|
|
256
256
|
)
|
|
257
|
-
const modelWithBarrier =
|
|
257
|
+
const modelWithBarrier = modifyFields(emptyModel, {
|
|
258
258
|
grid: () => gridWithBarrier,
|
|
259
259
|
})
|
|
260
260
|
|
|
@@ -290,7 +290,7 @@ describe('grid size', () => {
|
|
|
290
290
|
})
|
|
291
291
|
|
|
292
292
|
test('painted canvas opens confirmation dialog', () => {
|
|
293
|
-
const paintedModel: Model =
|
|
293
|
+
const paintedModel: Model = modifyFields(emptyModel, {
|
|
294
294
|
grid: () =>
|
|
295
295
|
createEmptyGrid(4).map((row, y) =>
|
|
296
296
|
row.map((cell, x) =>
|
|
@@ -313,7 +313,7 @@ describe('grid size', () => {
|
|
|
313
313
|
})
|
|
314
314
|
|
|
315
315
|
test('confirming grid size change resets canvas and history', () => {
|
|
316
|
-
const modelWithPending: Model =
|
|
316
|
+
const modelWithPending: Model = modifyFields(emptyModel, {
|
|
317
317
|
maybePendingGridSize: () => Option.some(8),
|
|
318
318
|
gridSizeConfirmDialog: () =>
|
|
319
319
|
Dialog.boot({
|
|
@@ -43,7 +43,7 @@ export const subscriptions = Subscription.make<Model, Message>()(entry => ({
|
|
|
43
43
|
Subscription.fromEventFilterMapPreventDefault({
|
|
44
44
|
target: document,
|
|
45
45
|
type: 'keydown',
|
|
46
|
-
|
|
46
|
+
filterMapEvent: toUndoRedoMessage,
|
|
47
47
|
}),
|
|
48
48
|
),
|
|
49
49
|
|
|
@@ -51,7 +51,7 @@ export const subscriptions = Subscription.make<Model, Message>()(entry => ({
|
|
|
51
51
|
Subscription.fromEventFilterMap({
|
|
52
52
|
target: document,
|
|
53
53
|
type: 'keydown',
|
|
54
|
-
|
|
54
|
+
filterMapEvent: toToolMessage,
|
|
55
55
|
}),
|
|
56
56
|
),
|
|
57
57
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Array, Match, Option } from 'effect'
|
|
2
2
|
import { Update } from 'foldkit'
|
|
3
|
-
import {
|
|
3
|
+
import { modifyFields } from 'foldkit/struct'
|
|
4
4
|
|
|
5
5
|
import { Dialog, Listbox, RadioGroup } from '@foldkit/ui'
|
|
6
6
|
|
|
@@ -56,7 +56,7 @@ const foldErrorDialogOutMessage = Dialog.OutMessage.match<
|
|
|
56
56
|
>({
|
|
57
57
|
Opened: () => model => ({ model }),
|
|
58
58
|
Closed: () => model => ({
|
|
59
|
-
model:
|
|
59
|
+
model: modifyFields(model, { maybeExportError: () => Option.none() }),
|
|
60
60
|
}),
|
|
61
61
|
})
|
|
62
62
|
|
|
@@ -64,7 +64,7 @@ const foldErrorDialog = Update.foldChild({
|
|
|
64
64
|
update: Dialog.update,
|
|
65
65
|
read: (model: Model) => Option.some(model.errorDialog),
|
|
66
66
|
write: (model, nextErrorDialog) =>
|
|
67
|
-
|
|
67
|
+
modifyFields(model, { errorDialog: () => nextErrorDialog }),
|
|
68
68
|
toParentMessage: message => Message.GotErrorDialogMessage({ message }),
|
|
69
69
|
foldOutMessage: foldErrorDialogOutMessage,
|
|
70
70
|
})
|
|
@@ -73,7 +73,7 @@ const foldErrorDialogOpen = Update.foldChildStep({
|
|
|
73
73
|
update: Dialog.open,
|
|
74
74
|
read: (model: Model) => Option.some(model.errorDialog),
|
|
75
75
|
write: (model, nextErrorDialog) =>
|
|
76
|
-
|
|
76
|
+
modifyFields(model, { errorDialog: () => nextErrorDialog }),
|
|
77
77
|
toParentMessage: message => Message.GotErrorDialogMessage({ message }),
|
|
78
78
|
foldOutMessage: foldErrorDialogOutMessage,
|
|
79
79
|
})
|
|
@@ -89,7 +89,7 @@ const foldThemeListboxOutMessage = Listbox.OutMessage.match<
|
|
|
89
89
|
if (Option.isNone(maybeNextTheme)) {
|
|
90
90
|
return { model }
|
|
91
91
|
}
|
|
92
|
-
const nextModel =
|
|
92
|
+
const nextModel = modifyFields(model, {
|
|
93
93
|
paletteThemeIndex: () => themeIndex,
|
|
94
94
|
selectedColorIndex: () => DEFAULT_COLOR_INDEX,
|
|
95
95
|
})
|
|
@@ -101,7 +101,7 @@ const foldThemeListbox = Update.foldChild({
|
|
|
101
101
|
update: ThemeListbox.update,
|
|
102
102
|
read: (model: Model) => Option.some(model.themeListbox),
|
|
103
103
|
write: (model, nextThemeListbox) =>
|
|
104
|
-
|
|
104
|
+
modifyFields(model, { themeListbox: () => nextThemeListbox }),
|
|
105
105
|
toParentMessage: message => Message.GotThemeListboxMessage({ message }),
|
|
106
106
|
foldOutMessage: foldThemeListboxOutMessage,
|
|
107
107
|
})
|
|
@@ -111,7 +111,7 @@ const foldGridSizeConfirmDialogOutMessage = Dialog.OutMessage.match<
|
|
|
111
111
|
>({
|
|
112
112
|
Opened: () => model => ({ model }),
|
|
113
113
|
Closed: () => model => ({
|
|
114
|
-
model:
|
|
114
|
+
model: modifyFields(model, { maybePendingGridSize: () => Option.none() }),
|
|
115
115
|
}),
|
|
116
116
|
})
|
|
117
117
|
|
|
@@ -119,7 +119,9 @@ const foldGridSizeConfirmDialog = Update.foldChild({
|
|
|
119
119
|
update: Dialog.update,
|
|
120
120
|
read: (model: Model) => Option.some(model.gridSizeConfirmDialog),
|
|
121
121
|
write: (model, nextGridSizeConfirmDialog) =>
|
|
122
|
-
|
|
122
|
+
modifyFields(model, {
|
|
123
|
+
gridSizeConfirmDialog: () => nextGridSizeConfirmDialog,
|
|
124
|
+
}),
|
|
123
125
|
toParentMessage: message =>
|
|
124
126
|
Message.GotGridSizeConfirmDialogMessage({ message }),
|
|
125
127
|
foldOutMessage: foldGridSizeConfirmDialogOutMessage,
|
|
@@ -129,7 +131,9 @@ const foldGridSizeConfirmDialogOpen = Update.foldChildStep({
|
|
|
129
131
|
update: Dialog.open,
|
|
130
132
|
read: (model: Model) => Option.some(model.gridSizeConfirmDialog),
|
|
131
133
|
write: (model, nextGridSizeConfirmDialog) =>
|
|
132
|
-
|
|
134
|
+
modifyFields(model, {
|
|
135
|
+
gridSizeConfirmDialog: () => nextGridSizeConfirmDialog,
|
|
136
|
+
}),
|
|
133
137
|
toParentMessage: message =>
|
|
134
138
|
Message.GotGridSizeConfirmDialogMessage({ message }),
|
|
135
139
|
foldOutMessage: foldGridSizeConfirmDialogOutMessage,
|
|
@@ -139,18 +143,22 @@ const foldGridSizeConfirmDialogClose = Update.foldChildStep({
|
|
|
139
143
|
update: Dialog.close,
|
|
140
144
|
read: (model: Model) => Option.some(model.gridSizeConfirmDialog),
|
|
141
145
|
write: (model, nextGridSizeConfirmDialog) =>
|
|
142
|
-
|
|
146
|
+
modifyFields(model, {
|
|
147
|
+
gridSizeConfirmDialog: () => nextGridSizeConfirmDialog,
|
|
148
|
+
}),
|
|
143
149
|
toParentMessage: message =>
|
|
144
150
|
Message.GotGridSizeConfirmDialogMessage({ message }),
|
|
145
151
|
foldOutMessage: foldGridSizeConfirmDialogOutMessage,
|
|
146
152
|
})
|
|
147
153
|
|
|
148
154
|
const selectTool = (model: Model, tool: Tool): UpdateReturn => ({
|
|
149
|
-
model:
|
|
155
|
+
model: modifyFields(model, { tool: () => tool }),
|
|
150
156
|
})
|
|
151
157
|
|
|
152
158
|
const selectColor = (model: Model, colorIndex: PaletteIndex): UpdateReturn => {
|
|
153
|
-
const nextModel =
|
|
159
|
+
const nextModel = modifyFields(model, {
|
|
160
|
+
selectedColorIndex: () => colorIndex,
|
|
161
|
+
})
|
|
154
162
|
return { model: nextModel, commands: [saveCanvas(nextModel)] }
|
|
155
163
|
}
|
|
156
164
|
|
|
@@ -168,7 +176,7 @@ const foldToolRadioGroup = Update.foldChild({
|
|
|
168
176
|
update: ToolRadioGroup.update,
|
|
169
177
|
read: (model: Model) => Option.some(model.toolRadioGroup),
|
|
170
178
|
write: (model, nextToolRadioGroup) =>
|
|
171
|
-
|
|
179
|
+
modifyFields(model, { toolRadioGroup: () => nextToolRadioGroup }),
|
|
172
180
|
toParentMessage: message => Message.GotToolRadioGroupMessage({ message }),
|
|
173
181
|
foldOutMessage: foldToolRadioGroupOutMessage,
|
|
174
182
|
})
|
|
@@ -186,7 +194,7 @@ const foldGridSizeRadioGroup = Update.foldChild({
|
|
|
186
194
|
update: GridSizeRadioGroup.update,
|
|
187
195
|
read: (model: Model) => Option.some(model.gridSizeRadioGroup),
|
|
188
196
|
write: (model, nextGridSizeRadioGroup) =>
|
|
189
|
-
|
|
197
|
+
modifyFields(model, { gridSizeRadioGroup: () => nextGridSizeRadioGroup }),
|
|
190
198
|
toParentMessage: message => Message.GotGridSizeRadioGroupMessage({ message }),
|
|
191
199
|
foldOutMessage: foldGridSizeRadioGroupOutMessage,
|
|
192
200
|
})
|
|
@@ -207,7 +215,7 @@ const foldPaletteRadioGroup = Update.foldChild({
|
|
|
207
215
|
update: PaletteRadioGroup.update,
|
|
208
216
|
read: (model: Model) => Option.some(model.paletteRadioGroup),
|
|
209
217
|
write: (model, nextPaletteRadioGroup) =>
|
|
210
|
-
|
|
218
|
+
modifyFields(model, { paletteRadioGroup: () => nextPaletteRadioGroup }),
|
|
211
219
|
toParentMessage: message => Message.GotPaletteRadioGroupMessage({ message }),
|
|
212
220
|
foldOutMessage: foldPaletteRadioGroupOutMessage,
|
|
213
221
|
})
|
|
@@ -218,7 +226,7 @@ export const update = (model: Model, message: Message) =>
|
|
|
218
226
|
Match.value(model.tool).pipe(
|
|
219
227
|
withUpdateReturn,
|
|
220
228
|
Match.when('Brush', () => ({
|
|
221
|
-
model:
|
|
229
|
+
model: modifyFields(model, {
|
|
222
230
|
grid: () => applyBrush(model, x, y),
|
|
223
231
|
undoStack: () => pushHistory(model.undoStack, model.grid),
|
|
224
232
|
redoStack: () => [],
|
|
@@ -226,7 +234,7 @@ export const update = (model: Model, message: Message) =>
|
|
|
226
234
|
}),
|
|
227
235
|
})),
|
|
228
236
|
Match.when('Fill', () => {
|
|
229
|
-
const nextModel =
|
|
237
|
+
const nextModel = modifyFields(model, {
|
|
230
238
|
grid: () => applyFill(model, x, y),
|
|
231
239
|
undoStack: () => pushHistory(model.undoStack, model.grid),
|
|
232
240
|
redoStack: () => [],
|
|
@@ -234,7 +242,7 @@ export const update = (model: Model, message: Message) =>
|
|
|
234
242
|
return { model: nextModel, commands: [saveCanvas(nextModel)] }
|
|
235
243
|
}),
|
|
236
244
|
Match.when('Eraser', () => ({
|
|
237
|
-
model:
|
|
245
|
+
model: modifyFields(model, {
|
|
238
246
|
grid: () => applyEraser(model, x, y),
|
|
239
247
|
undoStack: () => pushHistory(model.undoStack, model.grid),
|
|
240
248
|
redoStack: () => [],
|
|
@@ -245,19 +253,23 @@ export const update = (model: Model, message: Message) =>
|
|
|
245
253
|
),
|
|
246
254
|
|
|
247
255
|
EnteredCell: ({ x, y }) => {
|
|
248
|
-
const withHover =
|
|
256
|
+
const withHover = modifyFields(model, {
|
|
249
257
|
maybeHoveredCell: () => Option.some({ x, y }),
|
|
250
258
|
})
|
|
251
259
|
|
|
252
260
|
if (model.isDrawing && model.tool === 'Brush') {
|
|
253
261
|
return {
|
|
254
|
-
model:
|
|
262
|
+
model: modifyFields(withHover, {
|
|
263
|
+
grid: () => applyBrush(model, x, y),
|
|
264
|
+
}),
|
|
255
265
|
}
|
|
256
266
|
}
|
|
257
267
|
|
|
258
268
|
if (model.isDrawing && model.tool === 'Eraser') {
|
|
259
269
|
return {
|
|
260
|
-
model:
|
|
270
|
+
model: modifyFields(withHover, {
|
|
271
|
+
grid: () => applyEraser(model, x, y),
|
|
272
|
+
}),
|
|
261
273
|
}
|
|
262
274
|
}
|
|
263
275
|
|
|
@@ -265,14 +277,14 @@ export const update = (model: Model, message: Message) =>
|
|
|
265
277
|
},
|
|
266
278
|
|
|
267
279
|
LeftCanvas: () => ({
|
|
268
|
-
model:
|
|
280
|
+
model: modifyFields(model, { maybeHoveredCell: () => Option.none() }),
|
|
269
281
|
}),
|
|
270
282
|
|
|
271
283
|
ReleasedMouse: () => {
|
|
272
284
|
if (!model.isDrawing) {
|
|
273
285
|
return { model }
|
|
274
286
|
}
|
|
275
|
-
const nextModel =
|
|
287
|
+
const nextModel = modifyFields(model, { isDrawing: () => false })
|
|
276
288
|
return { model: nextModel, commands: [saveCanvas(nextModel)] }
|
|
277
289
|
},
|
|
278
290
|
|
|
@@ -299,7 +311,9 @@ export const update = (model: Model, message: Message) =>
|
|
|
299
311
|
Match.when('Both', () => 'Vertical' as const),
|
|
300
312
|
Match.exhaustive,
|
|
301
313
|
)
|
|
302
|
-
return {
|
|
314
|
+
return {
|
|
315
|
+
model: modifyFields(model, { mirrorMode: () => nextMirrorMode }),
|
|
316
|
+
}
|
|
303
317
|
},
|
|
304
318
|
|
|
305
319
|
ToggledMirrorVertical: () => {
|
|
@@ -310,14 +324,16 @@ export const update = (model: Model, message: Message) =>
|
|
|
310
324
|
Match.when('Both', () => 'Horizontal' as const),
|
|
311
325
|
Match.exhaustive,
|
|
312
326
|
)
|
|
313
|
-
return {
|
|
327
|
+
return {
|
|
328
|
+
model: modifyFields(model, { mirrorMode: () => nextMirrorMode }),
|
|
329
|
+
}
|
|
314
330
|
},
|
|
315
331
|
|
|
316
332
|
ClickedUndo: () =>
|
|
317
333
|
Array.match(model.undoStack, {
|
|
318
334
|
onEmpty: () => ({ model }),
|
|
319
335
|
onNonEmpty: nonEmptyUndoStack => {
|
|
320
|
-
const nextModel =
|
|
336
|
+
const nextModel = modifyFields(model, {
|
|
321
337
|
grid: () => Array.lastNonEmpty(nonEmptyUndoStack),
|
|
322
338
|
undoStack: () => Array.initNonEmpty(nonEmptyUndoStack),
|
|
323
339
|
redoStack: () => [...model.redoStack, model.grid],
|
|
@@ -330,7 +346,7 @@ export const update = (model: Model, message: Message) =>
|
|
|
330
346
|
Array.match(model.redoStack, {
|
|
331
347
|
onEmpty: () => ({ model }),
|
|
332
348
|
onNonEmpty: nonEmptyRedoStack => {
|
|
333
|
-
const nextModel =
|
|
349
|
+
const nextModel = modifyFields(model, {
|
|
334
350
|
grid: () => Array.lastNonEmpty(nonEmptyRedoStack),
|
|
335
351
|
undoStack: () => [...model.undoStack, model.grid],
|
|
336
352
|
redoStack: () => Array.initNonEmpty(nonEmptyRedoStack),
|
|
@@ -347,7 +363,7 @@ export const update = (model: Model, message: Message) =>
|
|
|
347
363
|
|
|
348
364
|
const statesAfterTarget = Array.drop(model.undoStack, stepIndex + 1)
|
|
349
365
|
|
|
350
|
-
const nextModel =
|
|
366
|
+
const nextModel = modifyFields(model, {
|
|
351
367
|
grid: () => targetGrid,
|
|
352
368
|
undoStack: () => Array.take(model.undoStack, stepIndex),
|
|
353
369
|
redoStack: () => [
|
|
@@ -371,7 +387,7 @@ export const update = (model: Model, message: Message) =>
|
|
|
371
387
|
stepIndex + 1,
|
|
372
388
|
)
|
|
373
389
|
|
|
374
|
-
const nextModel =
|
|
390
|
+
const nextModel = modifyFields(model, {
|
|
375
391
|
grid: () => targetGrid,
|
|
376
392
|
undoStack: () => [
|
|
377
393
|
...model.undoStack,
|
|
@@ -385,7 +401,7 @@ export const update = (model: Model, message: Message) =>
|
|
|
385
401
|
},
|
|
386
402
|
|
|
387
403
|
ClickedClear: () => {
|
|
388
|
-
const nextModel =
|
|
404
|
+
const nextModel = modifyFields(model, {
|
|
389
405
|
grid: () => createEmptyGrid(model.gridSize),
|
|
390
406
|
undoStack: () => pushHistory(model.undoStack, model.grid),
|
|
391
407
|
redoStack: () => [],
|
|
@@ -411,7 +427,7 @@ export const update = (model: Model, message: Message) =>
|
|
|
411
427
|
FailedExportPng: ({ error }) =>
|
|
412
428
|
Update.combine(model, [
|
|
413
429
|
stepModel => ({
|
|
414
|
-
model:
|
|
430
|
+
model: modifyFields(stepModel, {
|
|
415
431
|
maybeExportError: () => Option.some(error),
|
|
416
432
|
}),
|
|
417
433
|
}),
|
|
@@ -441,7 +457,7 @@ export const update = (model: Model, message: Message) =>
|
|
|
441
457
|
})
|
|
442
458
|
|
|
443
459
|
const applyGridSizeChange = (model: Model, size: number): UpdateReturn => ({
|
|
444
|
-
model:
|
|
460
|
+
model: modifyFields(model, {
|
|
445
461
|
grid: () => createEmptyGrid(size),
|
|
446
462
|
gridSize: () => size,
|
|
447
463
|
undoStack: () => [],
|
|
@@ -462,7 +478,7 @@ const requestGridSizeChange = (model: Model, size: number): UpdateReturn => {
|
|
|
462
478
|
|
|
463
479
|
return Update.combine(model, [
|
|
464
480
|
stepModel => ({
|
|
465
|
-
model:
|
|
481
|
+
model: modifyFields(stepModel, {
|
|
466
482
|
maybePendingGridSize: () => Option.some(size),
|
|
467
483
|
}),
|
|
468
484
|
}),
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
"test": "vitest run"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@effect/platform-browser": "4.0.0-rc.
|
|
12
|
+
"@effect/platform-browser": "4.0.0-rc.116",
|
|
13
13
|
"@foldkit/ui": "workspace:*",
|
|
14
14
|
"clsx": "^2.1.1",
|
|
15
|
-
"effect": "4.0.0-rc.
|
|
15
|
+
"effect": "4.0.0-rc.116",
|
|
16
16
|
"foldkit": "workspace:*"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
@@ -17,7 +17,7 @@ import { defineMessageUnion } from 'foldkit/message'
|
|
|
17
17
|
import { UrlRequest, load, pushUrl, replaceUrl } from 'foldkit/navigation'
|
|
18
18
|
import { defineRouteUnion } from 'foldkit/route'
|
|
19
19
|
import { defineTaggedUnion } from 'foldkit/schema'
|
|
20
|
-
import {
|
|
20
|
+
import { modifyFields } from 'foldkit/struct'
|
|
21
21
|
import { Url, toString as urlToString } from 'foldkit/url'
|
|
22
22
|
|
|
23
23
|
import { Button, Input, Listbox } from '@foldkit/ui'
|
|
@@ -302,7 +302,7 @@ const foldDietListbox = Update.foldChild({
|
|
|
302
302
|
update: DietListbox.update,
|
|
303
303
|
read: (model: Model) => Option.some(model.dietListbox),
|
|
304
304
|
write: (model, nextDietListbox) =>
|
|
305
|
-
|
|
305
|
+
modifyFields(model, { dietListbox: () => nextDietListbox }),
|
|
306
306
|
toParentMessage: message => Message.GotDietListboxMessage({ message }),
|
|
307
307
|
foldOutMessage: foldDietListboxOutMessage,
|
|
308
308
|
})
|
|
@@ -330,7 +330,7 @@ const foldPeriodListbox = Update.foldChild({
|
|
|
330
330
|
update: PeriodListbox.update,
|
|
331
331
|
read: (model: Model) => Option.some(model.periodListbox),
|
|
332
332
|
write: (model, nextPeriodListbox) =>
|
|
333
|
-
|
|
333
|
+
modifyFields(model, { periodListbox: () => nextPeriodListbox }),
|
|
334
334
|
toParentMessage: message => Message.GotPeriodListboxMessage({ message }),
|
|
335
335
|
foldOutMessage: foldPeriodListboxOutMessage,
|
|
336
336
|
})
|
|
@@ -356,7 +356,7 @@ export const update = (model: Model, message: Message) =>
|
|
|
356
356
|
ChangedUrl: ({ url }) => {
|
|
357
357
|
const nextRoute = urlToAppRoute(url)
|
|
358
358
|
|
|
359
|
-
return { model:
|
|
359
|
+
return { model: modifyFields(model, { route: () => nextRoute }) }
|
|
360
360
|
},
|
|
361
361
|
|
|
362
362
|
ChangedSearchInput: ({ value }) => {
|