create-foldkit-app 0.29.0 → 0.29.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/templates/base/AGENTS.md +5 -112
- package/dist/templates/base/FOLDKIT.md +144 -0
- package/dist/templates/examples/api-cache/src/main.ts +36 -40
- package/dist/templates/examples/auth/src/main.ts +16 -15
- package/dist/templates/examples/auth/src/page/loggedIn/update.ts +10 -11
- package/dist/templates/examples/auth/src/page/loggedOut/page/login.ts +44 -55
- package/dist/templates/examples/auth/src/page/loggedOut/update.ts +8 -12
- package/dist/templates/examples/auth/src/update.ts +67 -73
- package/dist/templates/examples/canvas-art/src/main.ts +32 -31
- package/dist/templates/examples/charting/src/init.test.ts +6 -3
- package/dist/templates/examples/charting/src/init.ts +4 -4
- package/dist/templates/examples/charting/src/update.ts +34 -38
- package/dist/templates/examples/counter/src/main.ts +13 -13
- package/dist/templates/examples/counters/src/counter.ts +9 -8
- package/dist/templates/examples/counters/src/main.ts +20 -26
- package/dist/templates/examples/crash-view/src/main.ts +5 -3
- package/dist/templates/examples/embedding/src/main.ts +11 -9
- package/dist/templates/examples/form/src/main.ts +79 -89
- package/dist/templates/examples/generative-art/src/main.ts +6 -4
- package/dist/templates/examples/generative-art/src/update.ts +26 -23
- package/dist/templates/examples/interrupting-commands/src/main.ts +68 -66
- package/dist/templates/examples/job-application/src/main.ts +3 -4
- package/dist/templates/examples/job-application/src/step/attachments.ts +16 -19
- package/dist/templates/examples/job-application/src/step/coverLetter.ts +5 -5
- package/dist/templates/examples/job-application/src/step/education/education.ts +12 -17
- package/dist/templates/examples/job-application/src/step/education/entry.ts +29 -42
- package/dist/templates/examples/job-application/src/step/personalInfo.ts +35 -44
- package/dist/templates/examples/job-application/src/step/skills/entry.ts +15 -21
- package/dist/templates/examples/job-application/src/step/skills/skills.ts +12 -17
- package/dist/templates/examples/job-application/src/step/workHistory/entry.ts +41 -58
- package/dist/templates/examples/job-application/src/step/workHistory/workHistory.ts +12 -17
- package/dist/templates/examples/job-application/src/update.ts +26 -29
- package/dist/templates/examples/kanban/src/main.ts +3 -4
- package/dist/templates/examples/kanban/src/update.ts +31 -31
- package/dist/templates/examples/managed-resource-layer/src/main.ts +30 -34
- package/dist/templates/examples/map/src/main.ts +48 -56
- package/dist/templates/examples/pixel-art/src/comparison.bench.test.ts +34 -13
- package/dist/templates/examples/pixel-art/src/main.bench.ts +3 -3
- package/dist/templates/examples/pixel-art/src/main.ts +3 -4
- package/dist/templates/examples/pixel-art/src/update.ts +109 -100
- package/dist/templates/examples/query-sync/src/main.ts +27 -25
- package/dist/templates/examples/route-transitions/src/main.ts +46 -43
- package/dist/templates/examples/route-transitions/src/story.test.ts +11 -11
- package/dist/templates/examples/routing/src/main.ts +16 -14
- package/dist/templates/examples/routing/src/page/people.ts +23 -28
- package/dist/templates/examples/shopping-cart/src/main.ts +41 -42
- package/dist/templates/examples/shopping-cart/src/page/products.ts +28 -35
- package/dist/templates/examples/slow-warnings/src/main.ts +23 -32
- package/dist/templates/examples/snake/src/main.ts +135 -143
- package/dist/templates/examples/ssg/src/main.ts +20 -17
- package/dist/templates/examples/ssr/src/main.ts +20 -24
- package/dist/templates/examples/state-machine/src/main.ts +24 -11
- package/dist/templates/examples/state-machine/src/story.test.ts +2 -2
- package/dist/templates/examples/stopwatch/src/main.ts +42 -50
- package/dist/templates/examples/todo/src/main.ts +152 -160
- package/dist/templates/examples/ui-showcase/src/main.ts +53 -54
- package/dist/templates/examples/ui-showcase/src/scene.test.ts +2 -2
- package/dist/templates/examples/ui-showcase/src/story.test.ts +2 -2
- package/dist/templates/examples/ui-showcase/src/ui/init.ts +6 -7
- package/dist/templates/examples/ui-showcase/src/ui/update.ts +265 -336
- package/dist/templates/examples/view-transitions/src/main.ts +18 -17
- package/dist/templates/examples/weather/src/main.ts +33 -40
- package/dist/templates/examples/web-components/src/main.ts +14 -17
- package/dist/templates/examples/websocket-chat/src/main.ts +44 -50
- package/dist/templates/release.json +8 -8
- package/dist/templates/rendering/ssg/src/main.ts +20 -17
- package/dist/templates/rendering/ssr/src/main.ts +20 -24
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Array, Match as M, Option, pipe } from 'effect'
|
|
2
|
-
import {
|
|
2
|
+
import { Update } from 'foldkit'
|
|
3
3
|
import { evo } from 'foldkit/struct'
|
|
4
4
|
|
|
5
5
|
import { Menu, Tabs } from '@foldkit/ui'
|
|
@@ -26,8 +26,6 @@ const isApplicationComplete = (model: Model): boolean =>
|
|
|
26
26
|
Education.isComplete(model.education) &&
|
|
27
27
|
Skills.isComplete(model.skills)
|
|
28
28
|
|
|
29
|
-
type UpdateReturn = readonly [Model, ReadonlyArray<Command.Command<Message>>]
|
|
30
|
-
|
|
31
29
|
const toNextStep = (current: Step.Step): Step.Step =>
|
|
32
30
|
pipe(
|
|
33
31
|
Step.all,
|
|
@@ -94,7 +92,7 @@ const foldStepMenuOutMessage = M.type<Menu.OutMessage<Step.Step>>().pipe(
|
|
|
94
92
|
M.tagsExhaustive({
|
|
95
93
|
Selected:
|
|
96
94
|
({ value }) =>
|
|
97
|
-
model =>
|
|
95
|
+
model => ({ model: evo(model, { currentStep: () => value }) }),
|
|
98
96
|
}),
|
|
99
97
|
)
|
|
100
98
|
|
|
@@ -111,7 +109,7 @@ const foldStepTabsOutMessage = M.type<Tabs.OutMessage<Step.Step>>().pipe(
|
|
|
111
109
|
M.tagsExhaustive({
|
|
112
110
|
Selected:
|
|
113
111
|
({ value }) =>
|
|
114
|
-
model =>
|
|
112
|
+
model => ({ model: evo(model, { currentStep: () => value }) }),
|
|
115
113
|
}),
|
|
116
114
|
)
|
|
117
115
|
|
|
@@ -124,7 +122,7 @@ const foldStepTabs = Update.foldChild({
|
|
|
124
122
|
})
|
|
125
123
|
|
|
126
124
|
export const update = (model: Model, message: Message) =>
|
|
127
|
-
Message.match<
|
|
125
|
+
Message.match<Update.Return<Model, Message>>(message, {
|
|
128
126
|
GotPersonalInfoMessage: ({ message }) => foldPersonalInfo(model, message),
|
|
129
127
|
|
|
130
128
|
GotWorkHistoryMessage: ({ message }) => foldWorkHistory(model, message),
|
|
@@ -141,18 +139,19 @@ export const update = (model: Model, message: Message) =>
|
|
|
141
139
|
|
|
142
140
|
GotStepTabsMessage: ({ message }) => foldStepTabs(model, message),
|
|
143
141
|
|
|
144
|
-
NavigatedToStep: ({ step }) =>
|
|
145
|
-
evo(model, { currentStep: () => step }),
|
|
146
|
-
|
|
147
|
-
|
|
142
|
+
NavigatedToStep: ({ step }) => ({
|
|
143
|
+
model: evo(model, { currentStep: () => step }),
|
|
144
|
+
}),
|
|
145
|
+
|
|
146
|
+
ClickedNext: () => ({ model: evo(model, { currentStep: toNextStep }) }),
|
|
148
147
|
|
|
149
|
-
|
|
148
|
+
ClickedPrevious: () => ({
|
|
149
|
+
model: evo(model, { currentStep: toPreviousStep }),
|
|
150
|
+
}),
|
|
150
151
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
[],
|
|
155
|
-
],
|
|
152
|
+
ToggledPreview: () => ({
|
|
153
|
+
model: evo(model, { isPreviewVisible: isVisible => !isVisible }),
|
|
154
|
+
}),
|
|
156
155
|
|
|
157
156
|
ClickedSubmit: () => {
|
|
158
157
|
const revealedModel = evo(model, {
|
|
@@ -163,21 +162,19 @@ export const update = (model: Model, message: Message) =>
|
|
|
163
162
|
isSubmitAttempted: () => true,
|
|
164
163
|
})
|
|
165
164
|
if (isApplicationComplete(revealedModel)) {
|
|
166
|
-
return
|
|
167
|
-
evo(revealedModel, { submission: () => Submitting() }),
|
|
168
|
-
[SubmitApplication()],
|
|
169
|
-
|
|
165
|
+
return {
|
|
166
|
+
model: evo(revealedModel, { submission: () => Submitting() }),
|
|
167
|
+
commands: [SubmitApplication()],
|
|
168
|
+
}
|
|
170
169
|
}
|
|
171
|
-
return
|
|
170
|
+
return { model: revealedModel }
|
|
172
171
|
},
|
|
173
172
|
|
|
174
|
-
SucceededSubmitApplication: () =>
|
|
175
|
-
evo(model, { submission: () => SubmitSuccess() }),
|
|
176
|
-
|
|
177
|
-
],
|
|
173
|
+
SucceededSubmitApplication: () => ({
|
|
174
|
+
model: evo(model, { submission: () => SubmitSuccess() }),
|
|
175
|
+
}),
|
|
178
176
|
|
|
179
|
-
FailedSubmitApplication: ({ error }) =>
|
|
180
|
-
evo(model, { submission: () => SubmitError({ error }) }),
|
|
181
|
-
|
|
182
|
-
],
|
|
177
|
+
FailedSubmitApplication: ({ error }) => ({
|
|
178
|
+
model: evo(model, { submission: () => SubmitError({ error }) }),
|
|
179
|
+
}),
|
|
183
180
|
})
|
|
@@ -41,16 +41,15 @@ export const init: Runtime.ApplicationInit<Model, Message, Flags> = flags => {
|
|
|
41
41
|
onSome: ({ columns }) => columns,
|
|
42
42
|
})
|
|
43
43
|
|
|
44
|
-
return
|
|
45
|
-
{
|
|
44
|
+
return {
|
|
45
|
+
model: {
|
|
46
46
|
columns,
|
|
47
47
|
dragAndDrop: DragAndDrop.init({ id: 'kanban' }),
|
|
48
48
|
maybeNewCardColumnId: Option.none(),
|
|
49
49
|
newCardTitle: '',
|
|
50
50
|
announcement: '',
|
|
51
51
|
},
|
|
52
|
-
|
|
53
|
-
]
|
|
52
|
+
}
|
|
54
53
|
}
|
|
55
54
|
|
|
56
55
|
export { Message, Model, subscriptions, update, view }
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Array, Match as M, Option, String, pipe } from 'effect'
|
|
2
|
-
import {
|
|
2
|
+
import { Update } from 'foldkit'
|
|
3
3
|
import { evo } from 'foldkit/struct'
|
|
4
4
|
|
|
5
5
|
import { DragAndDrop } from '@foldkit/ui'
|
|
@@ -9,7 +9,7 @@ import { Column } from './domain'
|
|
|
9
9
|
import { Message } from './message'
|
|
10
10
|
import type { Model } from './model'
|
|
11
11
|
|
|
12
|
-
type UpdateReturn =
|
|
12
|
+
type UpdateReturn = Update.Return<Model, Message>
|
|
13
13
|
|
|
14
14
|
const findCardTitle = (
|
|
15
15
|
columns: ReadonlyArray<Column.Column>,
|
|
@@ -106,22 +106,21 @@ const foldDragAndDropOutMessage: (
|
|
|
106
106
|
toContainerId,
|
|
107
107
|
toIndex,
|
|
108
108
|
)
|
|
109
|
-
return
|
|
110
|
-
evo(model, {
|
|
109
|
+
return {
|
|
110
|
+
model: evo(model, {
|
|
111
111
|
columns: () => nextColumns,
|
|
112
112
|
announcement: () =>
|
|
113
113
|
screenReaderTextForDrop(previousModel, outMessage),
|
|
114
114
|
}),
|
|
115
|
-
[SaveBoard({ columns: nextColumns })],
|
|
116
|
-
|
|
115
|
+
commands: [SaveBoard({ columns: nextColumns })],
|
|
116
|
+
}
|
|
117
117
|
},
|
|
118
|
-
Cancelled: () =>
|
|
119
|
-
evo(model, {
|
|
118
|
+
Cancelled: () => ({
|
|
119
|
+
model: evo(model, {
|
|
120
120
|
announcement: () =>
|
|
121
121
|
screenReaderTextForDrop(previousModel, outMessage),
|
|
122
122
|
}),
|
|
123
|
-
|
|
124
|
-
],
|
|
123
|
+
}),
|
|
125
124
|
})
|
|
126
125
|
|
|
127
126
|
const foldDragAndDrop = (previousModel: Model) =>
|
|
@@ -142,29 +141,31 @@ export const update = (model: Model, message: Message) =>
|
|
|
142
141
|
GotDragAndDropMessage: ({ message }) =>
|
|
143
142
|
foldDragAndDrop(model)(model, message),
|
|
144
143
|
|
|
145
|
-
ClickedAddCard: ({ columnId }) =>
|
|
146
|
-
evo(model, {
|
|
144
|
+
ClickedAddCard: ({ columnId }) => ({
|
|
145
|
+
model: evo(model, {
|
|
147
146
|
maybeNewCardColumnId: () => Option.some(columnId),
|
|
148
147
|
newCardTitle: () => '',
|
|
149
148
|
}),
|
|
150
|
-
[FocusAddCardInput()],
|
|
151
|
-
|
|
149
|
+
commands: [FocusAddCardInput()],
|
|
150
|
+
}),
|
|
152
151
|
|
|
153
|
-
ChangedNewCardTitle: ({ value }) =>
|
|
154
|
-
evo(model, { newCardTitle: () => value }),
|
|
155
|
-
|
|
156
|
-
],
|
|
152
|
+
ChangedNewCardTitle: ({ value }) => ({
|
|
153
|
+
model: evo(model, { newCardTitle: () => value }),
|
|
154
|
+
}),
|
|
157
155
|
|
|
158
156
|
SubmittedNewCard: () =>
|
|
159
157
|
Option.match(model.maybeNewCardColumnId, {
|
|
160
|
-
onNone: () =>
|
|
158
|
+
onNone: () => ({ model }),
|
|
161
159
|
onSome: columnId => {
|
|
162
160
|
const title = String.trim(model.newCardTitle)
|
|
163
161
|
if (String.isEmpty(title)) {
|
|
164
|
-
return
|
|
162
|
+
return { model }
|
|
165
163
|
}
|
|
166
164
|
|
|
167
|
-
return
|
|
165
|
+
return {
|
|
166
|
+
model,
|
|
167
|
+
commands: [GenerateCardId({ columnId, title })],
|
|
168
|
+
}
|
|
168
169
|
},
|
|
169
170
|
}),
|
|
170
171
|
|
|
@@ -181,25 +182,24 @@ export const update = (model: Model, message: Message) =>
|
|
|
181
182
|
})
|
|
182
183
|
})
|
|
183
184
|
|
|
184
|
-
return
|
|
185
|
-
evo(model, {
|
|
185
|
+
return {
|
|
186
|
+
model: evo(model, {
|
|
186
187
|
columns: () => nextColumns,
|
|
187
188
|
maybeNewCardColumnId: () => Option.none(),
|
|
188
189
|
newCardTitle: () => '',
|
|
189
190
|
}),
|
|
190
|
-
[SaveBoard({ columns: nextColumns })],
|
|
191
|
-
|
|
191
|
+
commands: [SaveBoard({ columns: nextColumns })],
|
|
192
|
+
}
|
|
192
193
|
},
|
|
193
194
|
|
|
194
|
-
CancelledNewCard: () =>
|
|
195
|
-
evo(model, {
|
|
195
|
+
CancelledNewCard: () => ({
|
|
196
|
+
model: evo(model, {
|
|
196
197
|
maybeNewCardColumnId: () => Option.none(),
|
|
197
198
|
newCardTitle: () => '',
|
|
198
199
|
}),
|
|
199
|
-
|
|
200
|
-
],
|
|
200
|
+
}),
|
|
201
201
|
|
|
202
|
-
CompletedSaveBoard: () =>
|
|
202
|
+
CompletedSaveBoard: () => ({ model }),
|
|
203
203
|
|
|
204
|
-
CompletedFocusAddCardInput: () =>
|
|
204
|
+
CompletedFocusAddCardInput: () => ({ model }),
|
|
205
205
|
})
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
Option,
|
|
9
9
|
Schema as S,
|
|
10
10
|
} from 'effect'
|
|
11
|
-
import { Command, ManagedResource, Runtime } from 'foldkit'
|
|
11
|
+
import { Command, ManagedResource, Runtime, type Update } from 'foldkit'
|
|
12
12
|
import { Document, Html, HtmlBuilder } from 'foldkit/html'
|
|
13
13
|
import { defineMessageUnion } from 'foldkit/message'
|
|
14
14
|
import { ts } from 'foldkit/schema'
|
|
@@ -100,54 +100,50 @@ export const Compute = Command.define('Compute', {
|
|
|
100
100
|
|
|
101
101
|
// UPDATE
|
|
102
102
|
|
|
103
|
-
type UpdateReturn = readonly [
|
|
104
|
-
Model,
|
|
105
|
-
ReadonlyArray<Command.Command<Message, never, EngineService>>,
|
|
106
|
-
]
|
|
107
|
-
|
|
108
103
|
export const update = (model: Model, message: Message) =>
|
|
109
|
-
Message.match<
|
|
110
|
-
ClickedStartEngine: () =>
|
|
111
|
-
evo(model, { engine: () => EngineBooting() }),
|
|
112
|
-
|
|
113
|
-
],
|
|
104
|
+
Message.match<Update.Return<Model, Message, EngineService>>(message, {
|
|
105
|
+
ClickedStartEngine: () => ({
|
|
106
|
+
model: evo(model, { engine: () => EngineBooting() }),
|
|
107
|
+
}),
|
|
114
108
|
|
|
115
|
-
ClickedStopEngine: () =>
|
|
109
|
+
ClickedStopEngine: () => ({
|
|
110
|
+
model: evo(model, { engine: () => EngineOff() }),
|
|
111
|
+
}),
|
|
116
112
|
|
|
117
|
-
StartedEngine: ({ engineId }) =>
|
|
118
|
-
evo(model, { engine: () => EngineReady({ engineId }) }),
|
|
119
|
-
|
|
120
|
-
],
|
|
113
|
+
StartedEngine: ({ engineId }) => ({
|
|
114
|
+
model: evo(model, { engine: () => EngineReady({ engineId }) }),
|
|
115
|
+
}),
|
|
121
116
|
|
|
122
|
-
StoppedEngine: () =>
|
|
117
|
+
StoppedEngine: () => ({ model }),
|
|
123
118
|
|
|
124
|
-
FailedStartEngine: ({ reason }) =>
|
|
125
|
-
evo(model, { engine: () => EngineFailed({ reason }) }),
|
|
126
|
-
|
|
127
|
-
],
|
|
119
|
+
FailedStartEngine: ({ reason }) => ({
|
|
120
|
+
model: evo(model, { engine: () => EngineFailed({ reason }) }),
|
|
121
|
+
}),
|
|
128
122
|
|
|
129
123
|
ClickedCompute: () => {
|
|
130
124
|
const nextComputeCount = Number.increment(model.computeCount)
|
|
131
|
-
return
|
|
132
|
-
evo(model, { computeCount: () => nextComputeCount }),
|
|
133
|
-
[Compute({ value: nextComputeCount })],
|
|
134
|
-
|
|
125
|
+
return {
|
|
126
|
+
model: evo(model, { computeCount: () => nextComputeCount }),
|
|
127
|
+
commands: [Compute({ value: nextComputeCount })],
|
|
128
|
+
}
|
|
135
129
|
},
|
|
136
130
|
|
|
137
|
-
CompletedCompute: ({ result }) =>
|
|
138
|
-
evo(model, { maybeSquareResult: () => Option.some(result) }),
|
|
139
|
-
|
|
140
|
-
],
|
|
131
|
+
CompletedCompute: ({ result }) => ({
|
|
132
|
+
model: evo(model, { maybeSquareResult: () => Option.some(result) }),
|
|
133
|
+
}),
|
|
141
134
|
|
|
142
|
-
SkippedCompute: () =>
|
|
135
|
+
SkippedCompute: () => ({ model }),
|
|
143
136
|
})
|
|
144
137
|
|
|
145
138
|
// INIT
|
|
146
139
|
|
|
147
|
-
export const init: Runtime.ApplicationInit<Model, Message> = () =>
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
140
|
+
export const init: Runtime.ApplicationInit<Model, Message> = () => ({
|
|
141
|
+
model: {
|
|
142
|
+
engine: EngineOff(),
|
|
143
|
+
computeCount: 0,
|
|
144
|
+
maybeSquareResult: Option.none(),
|
|
145
|
+
},
|
|
146
|
+
})
|
|
151
147
|
|
|
152
148
|
// MANAGED RESOURCE
|
|
153
149
|
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
Stream,
|
|
12
12
|
String,
|
|
13
13
|
} from 'effect'
|
|
14
|
-
import { Command, Mount, Runtime, Subscription } from 'foldkit'
|
|
14
|
+
import { Command, Mount, Runtime, Subscription, type Update } from 'foldkit'
|
|
15
15
|
import * as Dom from 'foldkit/dom'
|
|
16
16
|
import type { Document, Html } from 'foldkit/html'
|
|
17
17
|
import { HtmlBuilder } from 'foldkit/html'
|
|
@@ -205,8 +205,6 @@ export const UnlockBodyScroll = Command.define('UnlockBodyScroll', {
|
|
|
205
205
|
|
|
206
206
|
// UPDATE
|
|
207
207
|
|
|
208
|
-
type UpdateReturn = readonly [Model, ReadonlyArray<Command.Command<Message>>]
|
|
209
|
-
|
|
210
208
|
const findLocation = (
|
|
211
209
|
model: Model,
|
|
212
210
|
locationId: string,
|
|
@@ -214,68 +212,63 @@ const findLocation = (
|
|
|
214
212
|
Array.findFirst(model.locations, ({ id }) => Equal.equals(id, locationId))
|
|
215
213
|
|
|
216
214
|
export const update = (model: Model, message: Message) =>
|
|
217
|
-
Message.match<
|
|
218
|
-
SucceededMountMap: ({ hostId }) =>
|
|
219
|
-
evo(model, { maybeMapHostId: () => Option.some(hostId) }),
|
|
220
|
-
|
|
221
|
-
],
|
|
215
|
+
Message.match<Update.Return<Model, Message>>(message, {
|
|
216
|
+
SucceededMountMap: ({ hostId }) => ({
|
|
217
|
+
model: evo(model, { maybeMapHostId: () => Option.some(hostId) }),
|
|
218
|
+
}),
|
|
222
219
|
|
|
223
|
-
FailedMountMap: ({ reason }) =>
|
|
224
|
-
evo(model, { maybeMapError: () => Option.some(reason) }),
|
|
225
|
-
|
|
226
|
-
],
|
|
220
|
+
FailedMountMap: ({ reason }) => ({
|
|
221
|
+
model: evo(model, { maybeMapError: () => Option.some(reason) }),
|
|
222
|
+
}),
|
|
227
223
|
|
|
228
|
-
MovedMap: ({ bounds }) =>
|
|
229
|
-
evo(model, { maybeBounds: () => Option.some(bounds) }),
|
|
230
|
-
|
|
231
|
-
],
|
|
224
|
+
MovedMap: ({ bounds }) => ({
|
|
225
|
+
model: evo(model, { maybeBounds: () => Option.some(bounds) }),
|
|
226
|
+
}),
|
|
232
227
|
|
|
233
|
-
ClickedMarker: ({ locationId }) =>
|
|
234
|
-
evo(model, {
|
|
228
|
+
ClickedMarker: ({ locationId }) => ({
|
|
229
|
+
model: evo(model, {
|
|
235
230
|
maybeSelectedLocationId: () => Option.some(locationId),
|
|
236
231
|
}),
|
|
237
|
-
|
|
238
|
-
],
|
|
232
|
+
}),
|
|
239
233
|
|
|
240
234
|
ClickedLocation: ({ locationId }) =>
|
|
241
235
|
Option.match(findLocation(model, locationId), {
|
|
242
|
-
onNone: () =>
|
|
243
|
-
onSome: ({ lng, lat }) =>
|
|
244
|
-
evo(model, {
|
|
236
|
+
onNone: () => ({ model }),
|
|
237
|
+
onSome: ({ lng, lat }) => ({
|
|
238
|
+
model: evo(model, {
|
|
245
239
|
maybeSelectedLocationId: () => Option.some(locationId),
|
|
246
240
|
}),
|
|
247
|
-
[
|
|
241
|
+
commands: [
|
|
248
242
|
FlyTo({
|
|
249
243
|
maybeHostId: model.maybeMapHostId,
|
|
250
|
-
lng
|
|
251
|
-
lat
|
|
244
|
+
lng,
|
|
245
|
+
lat,
|
|
252
246
|
zoom: SELECTED_LOCATION_ZOOM,
|
|
253
247
|
}),
|
|
254
248
|
],
|
|
255
|
-
|
|
249
|
+
}),
|
|
256
250
|
}),
|
|
257
251
|
|
|
258
|
-
UpdatedSearchQuery: ({ value }) =>
|
|
259
|
-
evo(model, { searchQuery: () => value }),
|
|
260
|
-
|
|
261
|
-
],
|
|
252
|
+
UpdatedSearchQuery: ({ value }) => ({
|
|
253
|
+
model: evo(model, { searchQuery: () => value }),
|
|
254
|
+
}),
|
|
262
255
|
|
|
263
|
-
ClickedFindMe: () =>
|
|
264
|
-
evo(model, { geolocateState: () => GeolocateLocating() }),
|
|
265
|
-
[LockBodyScroll(), Geolocate()],
|
|
266
|
-
|
|
256
|
+
ClickedFindMe: () => ({
|
|
257
|
+
model: evo(model, { geolocateState: () => GeolocateLocating() }),
|
|
258
|
+
commands: [LockBodyScroll(), Geolocate()],
|
|
259
|
+
}),
|
|
267
260
|
|
|
268
|
-
DismissedGeolocate: () =>
|
|
269
|
-
evo(model, { geolocateState: () => GeolocateIdle() }),
|
|
270
|
-
[UnlockBodyScroll()],
|
|
271
|
-
|
|
261
|
+
DismissedGeolocate: () => ({
|
|
262
|
+
model: evo(model, { geolocateState: () => GeolocateIdle() }),
|
|
263
|
+
commands: [UnlockBodyScroll()],
|
|
264
|
+
}),
|
|
272
265
|
|
|
273
|
-
SucceededGeolocate: ({ lng, lat }) =>
|
|
274
|
-
evo(model, {
|
|
266
|
+
SucceededGeolocate: ({ lng, lat }) => ({
|
|
267
|
+
model: evo(model, {
|
|
275
268
|
maybeUserLocation: () => Option.some({ lng, lat }),
|
|
276
269
|
geolocateState: () => GeolocateIdle(),
|
|
277
270
|
}),
|
|
278
|
-
[
|
|
271
|
+
commands: [
|
|
279
272
|
UnlockBodyScroll(),
|
|
280
273
|
FlyTo({
|
|
281
274
|
maybeHostId: model.maybeMapHostId,
|
|
@@ -284,24 +277,23 @@ export const update = (model: Model, message: Message) =>
|
|
|
284
277
|
zoom: USER_LOCATION_ZOOM,
|
|
285
278
|
}),
|
|
286
279
|
],
|
|
287
|
-
|
|
280
|
+
}),
|
|
288
281
|
|
|
289
|
-
FailedGeolocate: ({ reason }) =>
|
|
290
|
-
evo(model, { geolocateState: () => GeolocateFailed({ reason }) }),
|
|
291
|
-
|
|
292
|
-
],
|
|
282
|
+
FailedGeolocate: ({ reason }) => ({
|
|
283
|
+
model: evo(model, { geolocateState: () => GeolocateFailed({ reason }) }),
|
|
284
|
+
}),
|
|
293
285
|
|
|
294
|
-
SucceededFlyTo: () =>
|
|
295
|
-
FailedFlyTo: () =>
|
|
296
|
-
CompletedFocusSearchInput: () =>
|
|
297
|
-
CompletedLockBodyScroll: () =>
|
|
298
|
-
CompletedUnlockBodyScroll: () =>
|
|
286
|
+
SucceededFlyTo: () => ({ model }),
|
|
287
|
+
FailedFlyTo: () => ({ model }),
|
|
288
|
+
CompletedFocusSearchInput: () => ({ model }),
|
|
289
|
+
CompletedLockBodyScroll: () => ({ model }),
|
|
290
|
+
CompletedUnlockBodyScroll: () => ({ model }),
|
|
299
291
|
})
|
|
300
292
|
|
|
301
293
|
// INIT
|
|
302
294
|
|
|
303
|
-
export const init: Runtime.ApplicationInit<Model, Message> = () =>
|
|
304
|
-
{
|
|
295
|
+
export const init: Runtime.ApplicationInit<Model, Message> = () => ({
|
|
296
|
+
model: {
|
|
305
297
|
locations: featuredLocations,
|
|
306
298
|
searchQuery: '',
|
|
307
299
|
maybeMapHostId: Option.none(),
|
|
@@ -311,8 +303,8 @@ export const init: Runtime.ApplicationInit<Model, Message> = () => [
|
|
|
311
303
|
maybeUserLocation: Option.none(),
|
|
312
304
|
geolocateState: GeolocateIdle(),
|
|
313
305
|
},
|
|
314
|
-
[FocusSearchInput()],
|
|
315
|
-
|
|
306
|
+
commands: [FocusSearchInput()],
|
|
307
|
+
})
|
|
316
308
|
|
|
317
309
|
// MAP MOUNT
|
|
318
310
|
|
|
@@ -60,8 +60,9 @@ const buildFoldkitHistory = (steps: number): Model => {
|
|
|
60
60
|
for (let i = 0; i < steps; i++) {
|
|
61
61
|
const x = i % GRID_SIZE
|
|
62
62
|
const y = Math.floor(i / GRID_SIZE) % GRID_SIZE
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
const pressedCell = update(model, Message.PressedCell({ x, y }))
|
|
64
|
+
const releasedMouse = update(pressedCell.model, Message.ReleasedMouse())
|
|
65
|
+
model = releasedMouse.model
|
|
65
66
|
}
|
|
66
67
|
return model
|
|
67
68
|
}
|
|
@@ -112,8 +113,11 @@ test('benchmark', () => {
|
|
|
112
113
|
{
|
|
113
114
|
name: 'Brush stroke',
|
|
114
115
|
foldkit: () => {
|
|
115
|
-
const
|
|
116
|
-
|
|
116
|
+
const pressedCell = update(
|
|
117
|
+
foldkitModel,
|
|
118
|
+
Message.PressedCell({ x: 5, y: 5 }),
|
|
119
|
+
)
|
|
120
|
+
update(pressedCell.model, Message.ReleasedMouse())
|
|
117
121
|
},
|
|
118
122
|
react: () => {
|
|
119
123
|
const s = reducer(reactState, { type: 'PressedCell', x: 5, y: 5 })
|
|
@@ -123,12 +127,27 @@ test('benchmark', () => {
|
|
|
123
127
|
{
|
|
124
128
|
name: 'Brush drag (5 cells)',
|
|
125
129
|
foldkit: () => {
|
|
126
|
-
let
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
let brushUpdate = update(
|
|
131
|
+
foldkitModel,
|
|
132
|
+
Message.PressedCell({ x: 0, y: 0 }),
|
|
133
|
+
)
|
|
134
|
+
brushUpdate = update(
|
|
135
|
+
brushUpdate.model,
|
|
136
|
+
Message.EnteredCell({ x: 1, y: 0 }),
|
|
137
|
+
)
|
|
138
|
+
brushUpdate = update(
|
|
139
|
+
brushUpdate.model,
|
|
140
|
+
Message.EnteredCell({ x: 2, y: 0 }),
|
|
141
|
+
)
|
|
142
|
+
brushUpdate = update(
|
|
143
|
+
brushUpdate.model,
|
|
144
|
+
Message.EnteredCell({ x: 3, y: 0 }),
|
|
145
|
+
)
|
|
146
|
+
brushUpdate = update(
|
|
147
|
+
brushUpdate.model,
|
|
148
|
+
Message.EnteredCell({ x: 4, y: 0 }),
|
|
149
|
+
)
|
|
150
|
+
update(brushUpdate.model, Message.ReleasedMouse())
|
|
132
151
|
},
|
|
133
152
|
react: () => {
|
|
134
153
|
let s = reducer(reactState, { type: 'PressedCell', x: 0, y: 0 })
|
|
@@ -162,12 +181,14 @@ test('benchmark', () => {
|
|
|
162
181
|
{
|
|
163
182
|
name: '5\u00d7 undo + 5\u00d7 redo',
|
|
164
183
|
foldkit: () => {
|
|
165
|
-
let
|
|
184
|
+
let model = foldkitWith20
|
|
166
185
|
for (let i = 0; i < 5; i++) {
|
|
167
|
-
|
|
186
|
+
const undo = update(model, Message.ClickedUndo())
|
|
187
|
+
model = undo.model
|
|
168
188
|
}
|
|
169
189
|
for (let i = 0; i < 5; i++) {
|
|
170
|
-
|
|
190
|
+
const redo = update(model, Message.ClickedRedo())
|
|
191
|
+
model = redo.model
|
|
171
192
|
}
|
|
172
193
|
},
|
|
173
194
|
react: () => {
|
|
@@ -36,7 +36,7 @@ const dispatch = (
|
|
|
36
36
|
...messages: ReadonlyArray<Parameters<typeof update>[1]>
|
|
37
37
|
): Model =>
|
|
38
38
|
messages.reduce<Model>(
|
|
39
|
-
(currentModel, message) => update(currentModel, message)
|
|
39
|
+
(currentModel, message) => update(currentModel, message).model,
|
|
40
40
|
model,
|
|
41
41
|
)
|
|
42
42
|
|
|
@@ -96,10 +96,10 @@ describe('update: undo/redo with history', () => {
|
|
|
96
96
|
bench('5x undo then 5x redo', () => {
|
|
97
97
|
let model = modelWith10Steps
|
|
98
98
|
for (let i = 0; i < 5; i++) {
|
|
99
|
-
model = update(model, Message.ClickedUndo())
|
|
99
|
+
model = update(model, Message.ClickedUndo()).model
|
|
100
100
|
}
|
|
101
101
|
for (let i = 0; i < 5; i++) {
|
|
102
|
-
model = update(model, Message.ClickedRedo())
|
|
102
|
+
model = update(model, Message.ClickedRedo()).model
|
|
103
103
|
}
|
|
104
104
|
})
|
|
105
105
|
})
|
|
@@ -46,8 +46,8 @@ export const flags: Effect.Effect<Flags> = Effect.gen(function* () {
|
|
|
46
46
|
|
|
47
47
|
// INIT
|
|
48
48
|
|
|
49
|
-
export const init: Runtime.ApplicationInit<Model, Message, Flags> = flags =>
|
|
50
|
-
{
|
|
49
|
+
export const init: Runtime.ApplicationInit<Model, Message, Flags> = flags => ({
|
|
50
|
+
model: {
|
|
51
51
|
grid: Option.match(flags.maybeSavedCanvas, {
|
|
52
52
|
onNone: () => createEmptyGrid(DEFAULT_GRID_SIZE),
|
|
53
53
|
onSome: ({ grid }) => grid,
|
|
@@ -79,7 +79,6 @@ export const init: Runtime.ApplicationInit<Model, Message, Flags> = flags => [
|
|
|
79
79
|
gridSizeRadioGroup: RadioGroup.init({ id: GRID_SIZE_RADIO_GROUP_ID }),
|
|
80
80
|
paletteRadioGroup: RadioGroup.init({ id: PALETTE_RADIO_GROUP_ID }),
|
|
81
81
|
},
|
|
82
|
-
|
|
83
|
-
]
|
|
82
|
+
})
|
|
84
83
|
|
|
85
84
|
export { Message, Model, subscriptions, update, view }
|