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
|
@@ -61,7 +61,7 @@ Then replace this file whole. Foldkit's conventions change with its APIs, and a
|
|
|
61
61
|
const update = (model: Model, message: Message) =>
|
|
62
62
|
Message.match<Update.Return<Model, Message>>(message, {
|
|
63
63
|
ClickedIncrement: () => ({
|
|
64
|
-
model:
|
|
64
|
+
model: modifyFields(model, { count: count => count + 1 }),
|
|
65
65
|
}),
|
|
66
66
|
})
|
|
67
67
|
```
|
|
@@ -86,7 +86,7 @@ Add `toParentOutMessage` only when at least one child OutMessage should continue
|
|
|
86
86
|
|
|
87
87
|
When a `foldChildInits` entry can derive or forward an OutMessage, add `resolveOutMessage` to construct one parent OutMessage from the named OutMessages after every local fold completes. Combine their information when both results matter; choosing one discards the other. The callback also receives the final Model. If that Model alone contains everything needed, use local folds and attach a parent OutMessage afterward with `Update.withOutMessage`.
|
|
88
88
|
|
|
89
|
-
Use `
|
|
89
|
+
Use `modifyFields()` from `foldkit/struct` for immutable model updates. Never spread or `Object.assign`.
|
|
90
90
|
|
|
91
91
|
### View
|
|
92
92
|
|
|
@@ -9,9 +9,9 @@
|
|
|
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
|
-
"effect": "4.0.0-rc.
|
|
14
|
+
"effect": "4.0.0-rc.116",
|
|
15
15
|
"foldkit": "workspace:*"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HashMap, Option } from 'effect'
|
|
2
|
-
import {
|
|
2
|
+
import { modifyFields } from 'foldkit/struct'
|
|
3
3
|
|
|
4
4
|
import { Tabs } from '@foldkit/ui'
|
|
5
5
|
|
|
@@ -44,14 +44,14 @@ export const loadingPostsModel: Model = {
|
|
|
44
44
|
stats: StatsData.Idle(),
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
export const loadedPostsModel: Model =
|
|
47
|
+
export const loadedPostsModel: Model = modifyFields(loadingPostsModel, {
|
|
48
48
|
posts: () =>
|
|
49
49
|
PostsData.Success({
|
|
50
50
|
data: { posts: fixturePosts, fetchedAt: FETCHED_AT },
|
|
51
51
|
}),
|
|
52
52
|
})
|
|
53
53
|
|
|
54
|
-
export const cachedFirstPostModel: Model =
|
|
54
|
+
export const cachedFirstPostModel: Model = modifyFields(loadedPostsModel, {
|
|
55
55
|
postDetailById: () =>
|
|
56
56
|
HashMap.set(
|
|
57
57
|
HashMap.empty(),
|
|
@@ -62,7 +62,7 @@ export const cachedFirstPostModel: Model = evo(loadedPostsModel, {
|
|
|
62
62
|
),
|
|
63
63
|
})
|
|
64
64
|
|
|
65
|
-
export const loadedStatsModel: Model =
|
|
65
|
+
export const loadedStatsModel: Model = modifyFields(loadedPostsModel, {
|
|
66
66
|
activeTab: () => 'Stats',
|
|
67
67
|
stats: () =>
|
|
68
68
|
StatsData.Success({
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import { AsyncData, Command, Runtime, Subscription, Update } from 'foldkit'
|
|
14
14
|
import { Document, Html, HtmlBuilder } from 'foldkit/html'
|
|
15
15
|
import { defineMessageUnion } from 'foldkit/message'
|
|
16
|
-
import {
|
|
16
|
+
import { modifyFields } from 'foldkit/struct'
|
|
17
17
|
|
|
18
18
|
import { Button, Tabs } from '@foldkit/ui'
|
|
19
19
|
|
|
@@ -102,7 +102,7 @@ const applyPostsTransition = (
|
|
|
102
102
|
Option.match(maybeNextPosts, {
|
|
103
103
|
onNone: () => ({ model }),
|
|
104
104
|
onSome: nextPosts => ({
|
|
105
|
-
model:
|
|
105
|
+
model: modifyFields(model, { posts: () => nextPosts }),
|
|
106
106
|
commands: [FetchPosts()],
|
|
107
107
|
}),
|
|
108
108
|
})
|
|
@@ -114,7 +114,7 @@ const applyStatsTransition = (
|
|
|
114
114
|
Option.match(maybeNextStats, {
|
|
115
115
|
onNone: () => ({ model }),
|
|
116
116
|
onSome: nextStats => ({
|
|
117
|
-
model:
|
|
117
|
+
model: modifyFields(model, { stats: () => nextStats }),
|
|
118
118
|
commands: [FetchStats()],
|
|
119
119
|
}),
|
|
120
120
|
})
|
|
@@ -123,7 +123,7 @@ const setPostDetail = (postId: string, postDetail: PostDetailData) =>
|
|
|
123
123
|
HashMap.set(postId, postDetail)
|
|
124
124
|
|
|
125
125
|
const activateTab = (model: Model, tab: Tab): UpdateReturn => {
|
|
126
|
-
const modelWithActiveTab =
|
|
126
|
+
const modelWithActiveTab = modifyFields(model, { activeTab: () => tab })
|
|
127
127
|
|
|
128
128
|
return Match.value(tab).pipe(
|
|
129
129
|
Match.withReturnType<UpdateReturn>(),
|
|
@@ -156,7 +156,7 @@ const foldTabsOutMessage = Tabs.OutMessage.match<
|
|
|
156
156
|
const foldTabs = Update.foldChild({
|
|
157
157
|
update: AppTabs.update,
|
|
158
158
|
read: (model: Model) => Option.some(model.tabs),
|
|
159
|
-
write: (model, nextTabs) =>
|
|
159
|
+
write: (model, nextTabs) => modifyFields(model, { tabs: () => nextTabs }),
|
|
160
160
|
toParentMessage: message => Message.GotTabsMessage({ message }),
|
|
161
161
|
foldOutMessage: foldTabsOutMessage,
|
|
162
162
|
})
|
|
@@ -166,13 +166,13 @@ export const update = (model: Model, message: Message) =>
|
|
|
166
166
|
GotTabsMessage: ({ message }) => foldTabs(model, message),
|
|
167
167
|
|
|
168
168
|
ClickedPost: ({ postId }) => {
|
|
169
|
-
const selectedModel =
|
|
169
|
+
const selectedModel = modifyFields(model, {
|
|
170
170
|
maybeSelectedPostId: () => Option.some(postId),
|
|
171
171
|
})
|
|
172
172
|
|
|
173
173
|
return Option.match(HashMap.get(model.postDetailById, postId), {
|
|
174
174
|
onNone: () => ({
|
|
175
|
-
model:
|
|
175
|
+
model: modifyFields(selectedModel, {
|
|
176
176
|
postDetailById: setPostDetail(postId, PostDetailData.Loading()),
|
|
177
177
|
}),
|
|
178
178
|
commands: [FetchPostDetail({ postId })],
|
|
@@ -182,7 +182,7 @@ export const update = (model: Model, message: Message) =>
|
|
|
182
182
|
},
|
|
183
183
|
|
|
184
184
|
ClickedBackToPosts: () => ({
|
|
185
|
-
model:
|
|
185
|
+
model: modifyFields(model, { maybeSelectedPostId: () => Option.none() }),
|
|
186
186
|
}),
|
|
187
187
|
|
|
188
188
|
ClickedInvalidatePosts: () =>
|
|
@@ -192,7 +192,7 @@ export const update = (model: Model, message: Message) =>
|
|
|
192
192
|
applyPostsTransition(model, AsyncData.revalidateOrLoad(model.posts)),
|
|
193
193
|
|
|
194
194
|
ClickedRetryPostDetail: ({ postId }) => ({
|
|
195
|
-
model:
|
|
195
|
+
model: modifyFields(model, {
|
|
196
196
|
postDetailById: setPostDetail(postId, PostDetailData.Loading()),
|
|
197
197
|
}),
|
|
198
198
|
commands: [FetchPostDetail({ postId })],
|
|
@@ -208,17 +208,17 @@ export const update = (model: Model, message: Message) =>
|
|
|
208
208
|
applyStatsTransition(model, AsyncData.revalidate(model.stats)),
|
|
209
209
|
|
|
210
210
|
SettledFetchPosts: ({ result }) => ({
|
|
211
|
-
model:
|
|
211
|
+
model: modifyFields(model, { posts: AsyncData.settle(result) }),
|
|
212
212
|
}),
|
|
213
213
|
|
|
214
214
|
SettledFetchPostDetail: ({ postId, result }) => ({
|
|
215
|
-
model:
|
|
215
|
+
model: modifyFields(model, {
|
|
216
216
|
postDetailById: HashMap.modify(postId, AsyncData.settle(result)),
|
|
217
217
|
}),
|
|
218
218
|
}),
|
|
219
219
|
|
|
220
220
|
SettledFetchStats: ({ result }) => ({
|
|
221
|
-
model:
|
|
221
|
+
model: modifyFields(model, { stats: AsyncData.settle(result) }),
|
|
222
222
|
}),
|
|
223
223
|
})
|
|
224
224
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HashMap, Option, Result } 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 { Tabs } from '@foldkit/ui'
|
|
@@ -97,7 +97,7 @@ test('a revalidation tick keeps stale stats on screen while refetching', () => {
|
|
|
97
97
|
FetchStats,
|
|
98
98
|
Message.SettledFetchStats({
|
|
99
99
|
result: Result.succeed({
|
|
100
|
-
stats:
|
|
100
|
+
stats: modifyFields(fixtureStats, { activeUsers: () => 99 }),
|
|
101
101
|
fetchedAt: FETCHED_AT + 5000,
|
|
102
102
|
}),
|
|
103
103
|
}),
|
|
@@ -135,7 +135,7 @@ test('a failed refresh keeps the stale stats on screen with the error', () => {
|
|
|
135
135
|
test('refresh clicks during an in-flight fetch are deduplicated', () => {
|
|
136
136
|
story(
|
|
137
137
|
update,
|
|
138
|
-
given(
|
|
138
|
+
given(modifyFields(loadedStatsModel, { stats: () => StatsData.Loading() })),
|
|
139
139
|
message(Message.ClickedRefreshStats()),
|
|
140
140
|
Command.expectNone(),
|
|
141
141
|
)
|
|
@@ -145,7 +145,7 @@ test('a revalidation tick during a refresh is deduplicated', () => {
|
|
|
145
145
|
story(
|
|
146
146
|
update,
|
|
147
147
|
given(
|
|
148
|
-
|
|
148
|
+
modifyFields(loadedStatsModel, {
|
|
149
149
|
stats: () =>
|
|
150
150
|
StatsData.Refreshing({
|
|
151
151
|
data: { stats: fixtureStats, fetchedAt: FETCHED_AT },
|
|
@@ -187,7 +187,7 @@ test('retrying failed posts shows the loading state and refetches', () => {
|
|
|
187
187
|
story(
|
|
188
188
|
update,
|
|
189
189
|
given(
|
|
190
|
-
|
|
190
|
+
modifyFields(loadedPostsModel, {
|
|
191
191
|
posts: () => PostsData.Failure({ error: 'The server is down.' }),
|
|
192
192
|
}),
|
|
193
193
|
),
|
|
@@ -274,7 +274,7 @@ test('revisiting a post with a cached failure shows it without refetching', () =
|
|
|
274
274
|
story(
|
|
275
275
|
update,
|
|
276
276
|
given(
|
|
277
|
-
|
|
277
|
+
modifyFields(loadedPostsModel, {
|
|
278
278
|
postDetailById: () =>
|
|
279
279
|
HashMap.set(
|
|
280
280
|
HashMap.empty(),
|
|
@@ -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": {
|
|
@@ -11,12 +11,12 @@ import {
|
|
|
11
11
|
type,
|
|
12
12
|
within,
|
|
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 { Message, SimulateAuthRequest, initModel, update, view } from './login'
|
|
18
18
|
|
|
19
|
-
const validModel =
|
|
19
|
+
const validModel = modifyFields(initModel(), {
|
|
20
20
|
email: () => Valid({ value: 'alice@example.com' }),
|
|
21
21
|
password: () => Valid({ value: 'password' }),
|
|
22
22
|
})
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
model,
|
|
9
9
|
story,
|
|
10
10
|
} from 'foldkit/story'
|
|
11
|
-
import {
|
|
11
|
+
import { modifyFields } from 'foldkit/struct'
|
|
12
12
|
import { describe, expect, test } from 'vitest'
|
|
13
13
|
|
|
14
14
|
import {
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
update,
|
|
20
20
|
} from './login'
|
|
21
21
|
|
|
22
|
-
const validModel =
|
|
22
|
+
const validModel = modifyFields(initModel(), {
|
|
23
23
|
email: () => Valid({ value: 'alice@example.com' }),
|
|
24
24
|
password: () => Valid({ value: 'password' }),
|
|
25
25
|
})
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from 'foldkit/fieldValidation'
|
|
13
13
|
import { Html, HtmlBuilder } from 'foldkit/html'
|
|
14
14
|
import { defineMessageUnion } from 'foldkit/message'
|
|
15
|
-
import {
|
|
15
|
+
import { modifyFields } from 'foldkit/struct'
|
|
16
16
|
|
|
17
17
|
import { Button, Input } from '@foldkit/ui'
|
|
18
18
|
|
|
@@ -111,11 +111,11 @@ export const update = (model: Model, message: Message) =>
|
|
|
111
111
|
message,
|
|
112
112
|
{
|
|
113
113
|
ChangedEmail: ({ value }) => ({
|
|
114
|
-
model:
|
|
114
|
+
model: modifyFields(model, { email: () => validateEmail(value) }),
|
|
115
115
|
}),
|
|
116
116
|
|
|
117
117
|
ChangedPassword: ({ value }) => ({
|
|
118
|
-
model:
|
|
118
|
+
model: modifyFields(model, { password: () => validatePassword(value) }),
|
|
119
119
|
}),
|
|
120
120
|
|
|
121
121
|
SubmittedForm: () => {
|
|
@@ -128,7 +128,7 @@ export const update = (model: Model, message: Message) =>
|
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
return {
|
|
131
|
-
model:
|
|
131
|
+
model: modifyFields(model, { isSubmitting: () => true }),
|
|
132
132
|
commands: [
|
|
133
133
|
SimulateAuthRequest({
|
|
134
134
|
email: model.email.value,
|
|
@@ -144,7 +144,7 @@ export const update = (model: Model, message: Message) =>
|
|
|
144
144
|
}),
|
|
145
145
|
|
|
146
146
|
FailedSimulateAuthRequest: ({ error }) => ({
|
|
147
|
-
model:
|
|
147
|
+
model: modifyFields(model, {
|
|
148
148
|
password: () =>
|
|
149
149
|
Invalid({
|
|
150
150
|
value: model.password.value,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Option } from 'effect'
|
|
2
2
|
import { Update } from 'foldkit'
|
|
3
|
-
import {
|
|
3
|
+
import { modifyFields } from 'foldkit/struct'
|
|
4
4
|
|
|
5
5
|
import { Message, OutMessage } from './message'
|
|
6
6
|
import { Model } from './model'
|
|
@@ -10,7 +10,7 @@ const foldLogin = Update.foldChild({
|
|
|
10
10
|
update: Login.update,
|
|
11
11
|
read: (model: Model) => Option.some(model.loginModel),
|
|
12
12
|
write: (model, nextLoginModel) =>
|
|
13
|
-
|
|
13
|
+
modifyFields(model, { loginModel: () => nextLoginModel }),
|
|
14
14
|
toParentMessage: message => Message.GotLoginMessage({ message }),
|
|
15
15
|
toParentOutMessage: Login.OutMessage.match<OutMessage>({
|
|
16
16
|
SucceededLogin: ({ session }) => OutMessage.SucceededLogin({ session }),
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
submit,
|
|
9
9
|
text,
|
|
10
10
|
} from 'foldkit/scene'
|
|
11
|
-
import {
|
|
11
|
+
import { modifyFields } from 'foldkit/struct'
|
|
12
12
|
import { describe, test } from 'vitest'
|
|
13
13
|
|
|
14
14
|
import { SaveSession } from './command'
|
|
@@ -26,7 +26,7 @@ import { view } from './view'
|
|
|
26
26
|
|
|
27
27
|
const validModel = LoggedOut.Model({
|
|
28
28
|
route: AppRoute.Login(),
|
|
29
|
-
loginModel:
|
|
29
|
+
loginModel: modifyFields(initLoginModel(), {
|
|
30
30
|
email: () => Valid({ value: 'alice@example.com' }),
|
|
31
31
|
password: () => Valid({ value: 'password' }),
|
|
32
32
|
}),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Effect, Match, Option, Schema } from 'effect'
|
|
2
2
|
import { Command, Update } from 'foldkit'
|
|
3
3
|
import { UrlRequest, load, pushUrl, replaceUrl } from 'foldkit/navigation'
|
|
4
|
-
import {
|
|
4
|
+
import { modifyFields } from 'foldkit/struct'
|
|
5
5
|
import { toString as urlToString } from 'foldkit/url'
|
|
6
6
|
|
|
7
7
|
import { ClearSession, LogError, SaveSession } from './command'
|
|
@@ -125,7 +125,7 @@ export const update = (model: Model, message: Message) =>
|
|
|
125
125
|
Match.value(route).pipe(
|
|
126
126
|
withUpdateReturn,
|
|
127
127
|
Match.tag('Home', 'Login', 'NotFound', route => ({
|
|
128
|
-
model:
|
|
128
|
+
model: modifyFields(loggedOutModel, { route: () => route }),
|
|
129
129
|
})),
|
|
130
130
|
Match.orElse(() => ({ model, commands: [RedirectToLogin()] })),
|
|
131
131
|
),
|
|
@@ -134,7 +134,7 @@ export const update = (model: Model, message: Message) =>
|
|
|
134
134
|
Match.value(route).pipe(
|
|
135
135
|
withUpdateReturn,
|
|
136
136
|
Match.tag('Dashboard', 'Settings', 'NotFound', route => ({
|
|
137
|
-
model:
|
|
137
|
+
model: modifyFields(loggedInModel, { route: () => route }),
|
|
138
138
|
})),
|
|
139
139
|
Match.orElse(() => ({
|
|
140
140
|
model,
|
|
@@ -9,9 +9,9 @@
|
|
|
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
|
-
"effect": "4.0.0-rc.
|
|
14
|
+
"effect": "4.0.0-rc.116",
|
|
15
15
|
"foldkit": "workspace:*"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
@@ -2,7 +2,7 @@ import { Array, Effect, Number, Option, Random, Schema, pipe } from 'effect'
|
|
|
2
2
|
import { Canvas, Command, Runtime, Subscription, type Update } from 'foldkit'
|
|
3
3
|
import { Document, Html, HtmlBuilder } from 'foldkit/html'
|
|
4
4
|
import { defineMessageUnion } from 'foldkit/message'
|
|
5
|
-
import {
|
|
5
|
+
import { modifyFields } from 'foldkit/struct'
|
|
6
6
|
|
|
7
7
|
import { Button } from '@foldkit/ui'
|
|
8
8
|
|
|
@@ -113,7 +113,7 @@ const advanceBall =
|
|
|
113
113
|
const maxY = CANVAS_HEIGHT - ball.radius
|
|
114
114
|
const bouncedX = nextX < minX || nextX > maxX
|
|
115
115
|
const bouncedY = nextY < minY || nextY > maxY
|
|
116
|
-
return
|
|
116
|
+
return modifyFields(ball, {
|
|
117
117
|
x: () => Math.max(minX, Math.min(maxX, nextX)),
|
|
118
118
|
y: () => Math.max(minY, Math.min(maxY, nextY)),
|
|
119
119
|
vx: vx => (bouncedX ? -vx : vx),
|
|
@@ -124,7 +124,7 @@ const advanceBall =
|
|
|
124
124
|
export const update = (model: Model, message: Message) =>
|
|
125
125
|
Message.match<Update.Return<Model, Message>>(message, {
|
|
126
126
|
TickedFrame: ({ deltaTime }) => ({
|
|
127
|
-
model:
|
|
127
|
+
model: modifyFields(model, {
|
|
128
128
|
balls: Array.map(advanceBall(deltaTime / MS_PER_SECOND)),
|
|
129
129
|
}),
|
|
130
130
|
}),
|
|
@@ -135,7 +135,7 @@ export const update = (model: Model, message: Message) =>
|
|
|
135
135
|
}),
|
|
136
136
|
|
|
137
137
|
CompletedGenerateBall: ({ x, y, vx, vy, radius, color }) => ({
|
|
138
|
-
model:
|
|
138
|
+
model: modifyFields(model, {
|
|
139
139
|
balls: Array.append({
|
|
140
140
|
id: model.nextId,
|
|
141
141
|
x,
|
|
@@ -149,10 +149,10 @@ export const update = (model: Model, message: Message) =>
|
|
|
149
149
|
}),
|
|
150
150
|
}),
|
|
151
151
|
|
|
152
|
-
ClickedClear: () => ({ model:
|
|
152
|
+
ClickedClear: () => ({ model: modifyFields(model, { balls: () => [] }) }),
|
|
153
153
|
|
|
154
154
|
ClickedTogglePlay: () => ({
|
|
155
|
-
model:
|
|
155
|
+
model: modifyFields(model, { isRunning: running => !running }),
|
|
156
156
|
}),
|
|
157
157
|
})
|
|
158
158
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { click, expect, given, role, scene, text } from 'foldkit/scene'
|
|
2
|
-
import {
|
|
2
|
+
import { modifyFields } from 'foldkit/struct'
|
|
3
3
|
import { describe, test } from 'vitest'
|
|
4
4
|
|
|
5
5
|
import { type Model, update, view } from './main'
|
|
@@ -34,7 +34,7 @@ describe('view', () => {
|
|
|
34
34
|
})
|
|
35
35
|
|
|
36
36
|
test('the ball count reflects spawned balls in the Model', () => {
|
|
37
|
-
const populatedModel: Model =
|
|
37
|
+
const populatedModel: Model = modifyFields(emptyModel, {
|
|
38
38
|
balls: () => [
|
|
39
39
|
{ id: 0, x: 10, y: 20, vx: 1, vy: 1, radius: 8, color: '#ff2d55' },
|
|
40
40
|
{ id: 1, x: 30, y: 40, vx: -1, vy: 1, radius: 12, color: '#5ac8fa' },
|
|
@@ -51,7 +51,7 @@ describe('view', () => {
|
|
|
51
51
|
})
|
|
52
52
|
|
|
53
53
|
test('Clear empties the rendered ball count', () => {
|
|
54
|
-
const populatedModel: Model =
|
|
54
|
+
const populatedModel: Model = modifyFields(emptyModel, {
|
|
55
55
|
balls: () => [
|
|
56
56
|
{ id: 0, x: 10, y: 20, vx: 1, vy: 1, radius: 8, color: '#ff2d55' },
|
|
57
57
|
],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command, given, message, model, story } from 'foldkit/story'
|
|
2
|
-
import {
|
|
2
|
+
import { modifyFields } from 'foldkit/struct'
|
|
3
3
|
import { describe, expect, test } from 'vitest'
|
|
4
4
|
|
|
5
5
|
import { GenerateBall, Message, type Model, update } from './main'
|
|
@@ -10,7 +10,7 @@ const emptyModel: Model = {
|
|
|
10
10
|
isRunning: true,
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
const populatedModel: Model =
|
|
13
|
+
const populatedModel: Model = modifyFields(emptyModel, {
|
|
14
14
|
balls: () => [
|
|
15
15
|
{ id: 0, x: 100, y: 100, vx: 50, vy: 50, radius: 10, color: '#ff2d55' },
|
|
16
16
|
{ id: 1, x: 200, y: 200, vx: -50, vy: -50, radius: 15, color: '#5ac8fa' },
|
|
@@ -97,7 +97,7 @@ describe('update', () => {
|
|
|
97
97
|
})
|
|
98
98
|
|
|
99
99
|
test('bounces a ball off the canvas edges, flipping its velocity', () => {
|
|
100
|
-
const movingRightModel: Model =
|
|
100
|
+
const movingRightModel: Model = modifyFields(emptyModel, {
|
|
101
101
|
balls: () => [
|
|
102
102
|
{
|
|
103
103
|
id: 0,
|
|
@@ -9,11 +9,11 @@
|
|
|
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
15
|
"echarts": "^6.1.0",
|
|
16
|
-
"effect": "4.0.0-rc.
|
|
16
|
+
"effect": "4.0.0-rc.116",
|
|
17
17
|
"foldkit": "workspace:*"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Option } from 'effect'
|
|
2
|
-
import {
|
|
2
|
+
import { modifyFields } from 'foldkit/struct'
|
|
3
3
|
|
|
4
4
|
import { RadioGroup } from '@foldkit/ui'
|
|
5
5
|
|
|
@@ -120,7 +120,7 @@ export const loadingModel = Model.make({
|
|
|
120
120
|
maybeSelectedDatumId: Option.none(),
|
|
121
121
|
})
|
|
122
122
|
|
|
123
|
-
export const readyModel =
|
|
123
|
+
export const readyModel = modifyFields(loadingModel, {
|
|
124
124
|
telemetry: () => TelemetryAsyncData.Success({ data: sampleTelemetry }),
|
|
125
125
|
maybeChartHostId: () => Option.some('test-chart-host'),
|
|
126
126
|
})
|
|
@@ -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 { RadioGroup } from '@foldkit/ui'
|
|
@@ -79,7 +79,7 @@ describe('view', () => {
|
|
|
79
79
|
scene(
|
|
80
80
|
{ update, view },
|
|
81
81
|
given(
|
|
82
|
-
|
|
82
|
+
modifyFields(readyModel, {
|
|
83
83
|
telemetry: () =>
|
|
84
84
|
TelemetryAsyncData.Refreshing({ data: sampleTelemetry }),
|
|
85
85
|
}),
|
|
@@ -95,7 +95,7 @@ describe('view', () => {
|
|
|
95
95
|
scene(
|
|
96
96
|
{ update, view },
|
|
97
97
|
given(
|
|
98
|
-
|
|
98
|
+
modifyFields(loadingModel, {
|
|
99
99
|
telemetry: () => TelemetryAsyncData.Failure({ error: 'offline' }),
|
|
100
100
|
}),
|
|
101
101
|
),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command, given, message, model, story } from 'foldkit/story'
|
|
2
|
-
import {
|
|
2
|
+
import { modifyFields } from 'foldkit/struct'
|
|
3
3
|
import { expect, test } from 'vitest'
|
|
4
4
|
|
|
5
5
|
import { RadioGroup } from '@foldkit/ui'
|
|
@@ -103,7 +103,7 @@ test('a failed refresh preserves stale data in the stale state', () => {
|
|
|
103
103
|
story(
|
|
104
104
|
update,
|
|
105
105
|
given(
|
|
106
|
-
|
|
106
|
+
modifyFields(readyModel, {
|
|
107
107
|
telemetry: () =>
|
|
108
108
|
TelemetryAsyncData.Refreshing({ data: sampleTelemetry }),
|
|
109
109
|
}),
|