create-foldkit-app 0.38.0 → 0.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/templates/base/FOLDKIT.md +3 -1
  2. package/dist/templates/examples/canvas-art/src/main.ts +1 -1
  3. package/dist/templates/examples/charting/src/chartHost.ts +3 -4
  4. package/dist/templates/examples/charting/src/entry.ts +0 -2
  5. package/dist/templates/examples/charting/src/view/chart.ts +101 -36
  6. package/dist/templates/examples/embedding/src/main.ts +3 -3
  7. package/dist/templates/examples/generative-art/src/subscription.ts +1 -1
  8. package/dist/templates/examples/job-application/src/step/education/education.ts +14 -16
  9. package/dist/templates/examples/job-application/src/step/skills/skills.ts +14 -16
  10. package/dist/templates/examples/job-application/src/step/workHistory/workHistory.ts +14 -16
  11. package/dist/templates/examples/map/src/entry.ts +1 -2
  12. package/dist/templates/examples/map/src/main.ts +123 -145
  13. package/dist/templates/examples/map/src/mapHost.ts +10 -12
  14. package/dist/templates/examples/map/src/mount.test.ts +93 -68
  15. package/dist/templates/examples/pixel-art/src/subscription.ts +5 -5
  16. package/dist/templates/examples/routing/src/main.ts +3 -3
  17. package/dist/templates/examples/slow-warnings/src/main.ts +4 -4
  18. package/dist/templates/examples/snake/src/main.ts +4 -3
  19. package/dist/templates/examples/ssg/src/entry.server.ts +2 -0
  20. package/dist/templates/examples/ssg/src/entry.ts +1 -0
  21. package/dist/templates/examples/ssr/package.json +1 -1
  22. package/dist/templates/examples/ssr/src/entry.server.ts +2 -0
  23. package/dist/templates/examples/ssr/src/entry.ts +1 -0
  24. package/dist/templates/examples/stopwatch/src/main.ts +1 -0
  25. package/dist/templates/examples/ui-showcase/src/main.ts +49 -37
  26. package/dist/templates/examples/ui-showcase/src/ui/subscriptions.ts +1 -18
  27. package/dist/templates/examples/ui-showcase/src/ui/update.ts +2 -12
  28. package/dist/templates/examples/ui-showcase/src/ui/view/calendar.ts +9 -7
  29. package/dist/templates/examples/ui-showcase/src/ui/view/checkbox.ts +80 -65
  30. package/dist/templates/examples/ui-showcase/src/ui/view/dialog.ts +102 -123
  31. package/dist/templates/examples/ui-showcase/src/ui/view/disclosure.ts +128 -120
  32. package/dist/templates/examples/ui-showcase/src/ui/view/fieldset.ts +173 -144
  33. package/dist/templates/examples/ui-showcase/src/ui/view/fileDrop.ts +17 -15
  34. package/dist/templates/examples/ui-showcase/src/ui/view/hoverIntent.ts +64 -56
  35. package/dist/templates/examples/ui-showcase/src/ui/view/input.ts +32 -33
  36. package/dist/templates/examples/ui-showcase/src/ui/view/meter.ts +82 -73
  37. package/dist/templates/examples/ui-showcase/src/ui/view/popover.ts +100 -81
  38. package/dist/templates/examples/ui-showcase/src/ui/view/progress.ts +83 -68
  39. package/dist/templates/examples/ui-showcase/src/ui/view/radioGroup.ts +79 -85
  40. package/dist/templates/examples/ui-showcase/src/ui/view/select.ts +63 -67
  41. package/dist/templates/examples/ui-showcase/src/ui/view/slider.ts +72 -72
  42. package/dist/templates/examples/ui-showcase/src/ui/view/switch.ts +25 -26
  43. package/dist/templates/examples/ui-showcase/src/ui/view/tabs.ts +58 -46
  44. package/dist/templates/examples/ui-showcase/src/ui/view/textarea.ts +32 -39
  45. package/dist/templates/examples/ui-showcase/src/ui/view/tooltip.ts +48 -36
  46. package/dist/templates/examples/websocket-chat/src/main.ts +44 -18
  47. package/dist/templates/examples/websocket-chat/src/story.test.ts +33 -6
  48. package/dist/templates/release.json +12 -11
  49. package/dist/templates/rendering/ssg/src/entry.server.ts +2 -0
  50. package/dist/templates/rendering/ssg/src/entry.ts +1 -0
  51. package/dist/templates/rendering/ssg/vite.config.ts +1 -0
  52. package/dist/templates/rendering/ssr/scripts/serve.ts +4 -145
  53. package/dist/templates/rendering/ssr/src/entry.server.ts +2 -0
  54. package/dist/templates/rendering/ssr/src/entry.ts +1 -0
  55. package/dist/templates/rendering/ssr/vite.config.ts +1 -0
  56. package/dist/utils/files.js +2 -0
  57. package/package.json +1 -1
  58. package/dist/templates/examples/charting/src/subscription.ts +0 -70
@@ -187,84 +187,101 @@ const deleteProjectContent = (
187
187
 
188
188
  // DEMOS
189
189
 
190
+ const dialogWithPanel = (
191
+ { dialog, backdrop, panel, isVisible }: Dialog.RenderInfo,
192
+ backdropClassName: string,
193
+ panelClassNameValue: string,
194
+ content: () => ReadonlyArray<Html>,
195
+ h: HtmlBuilder<UiMessage>,
196
+ ): Html =>
197
+ h.dialog(
198
+ [...dialog, h.Class(dialogClassName)],
199
+ isVisible
200
+ ? [
201
+ h.div([...backdrop, h.Class(backdropClassName)]),
202
+ h.div([...panel, h.Class(panelClassNameValue)], content()),
203
+ ]
204
+ : [],
205
+ )
206
+
190
207
  const basicDemo = (
191
208
  dialogModel: Dialog.Model,
192
209
  h: HtmlBuilder<UiMessage>,
193
- ): Html =>
194
- h.submodel({
210
+ ): Html => {
211
+ const basicDialogView = (render: Dialog.RenderInfo): Html =>
212
+ dialogWithPanel(
213
+ render,
214
+ backdropClassName,
215
+ panelClassName,
216
+ () => [
217
+ confirmContent(render.closeButton, render.title, render.description, h),
218
+ ],
219
+ h,
220
+ )
221
+
222
+ return h.submodel({
195
223
  slotId: dialogModel.id,
196
224
  model: dialogModel,
197
225
  view: Dialog.view,
198
226
  viewInputs: {
199
227
  hasDescription: true,
200
- toView: ({
201
- dialog,
202
- backdrop,
203
- panel,
204
- closeButton,
205
- title,
206
- description,
207
- isVisible,
208
- }) =>
209
- h.dialog(
210
- [...dialog, h.Class(dialogClassName)],
211
- isVisible
212
- ? [
213
- h.div([...backdrop, h.Class(backdropClassName)]),
214
- h.div(
215
- [...panel, h.Class(panelClassName)],
216
- [confirmContent(closeButton, title, description, h)],
217
- ),
218
- ]
219
- : [],
220
- ),
228
+ toView: basicDialogView,
221
229
  },
222
230
  toParentMessage: message => UiMessage.GotDialogDemoMessage({ message }),
223
231
  })
232
+ }
224
233
 
225
234
  const animatedDemo = (
226
235
  dialogModel: Dialog.Model,
227
236
  h: HtmlBuilder<UiMessage>,
228
- ): Html =>
229
- h.submodel({
237
+ ): Html => {
238
+ const animatedDialogView = (render: Dialog.RenderInfo): Html =>
239
+ dialogWithPanel(
240
+ render,
241
+ animatedBackdropClassName,
242
+ animatedPanelClassName,
243
+ () => [
244
+ confirmContent(render.closeButton, render.title, render.description, h),
245
+ ],
246
+ h,
247
+ )
248
+
249
+ return h.submodel({
230
250
  slotId: dialogModel.id,
231
251
  model: dialogModel,
232
252
  view: Dialog.view,
233
253
  viewInputs: {
234
254
  hasDescription: true,
235
- toView: ({
236
- dialog,
237
- backdrop,
238
- panel,
239
- closeButton,
240
- title,
241
- description,
242
- isVisible,
243
- }) =>
244
- h.dialog(
245
- [...dialog, h.Class(dialogClassName)],
246
- isVisible
247
- ? [
248
- h.div([...backdrop, h.Class(animatedBackdropClassName)]),
249
- h.div(
250
- [...panel, h.Class(animatedPanelClassName)],
251
- [confirmContent(closeButton, title, description, h)],
252
- ),
253
- ]
254
- : [],
255
- ),
255
+ toView: animatedDialogView,
256
256
  },
257
257
  toParentMessage: message =>
258
258
  UiMessage.GotDialogAnimatedDemoMessage({ message }),
259
259
  })
260
+ }
260
261
 
261
262
  const overlayDemo = (
262
263
  dialogModel: Dialog.Model,
263
264
  comboboxModel: Combobox.Model,
264
265
  maybeSelectedCity: Option.Option<City>,
265
266
  h: HtmlBuilder<UiMessage>,
266
- ): Html =>
267
- h.div(
267
+ ): Html => {
268
+ const overlayDialogView = (render: Dialog.RenderInfo): Html =>
269
+ dialogWithPanel(
270
+ render,
271
+ backdropClassName,
272
+ panelClassName,
273
+ () =>
274
+ editFiltersContent(
275
+ render.title,
276
+ render.description,
277
+ comboboxModel,
278
+ maybeSelectedCity,
279
+ h,
280
+ ),
281
+ h,
282
+ )
283
+
284
+ return h.div(
268
285
  [],
269
286
  [
270
287
  trigger('Edit filters', UiMessage.ClickedEditFilters(), h),
@@ -274,45 +291,51 @@ const overlayDemo = (
274
291
  view: Dialog.view,
275
292
  viewInputs: {
276
293
  hasDescription: true,
277
- toView: ({
278
- dialog,
279
- backdrop,
280
- panel,
281
- title,
282
- description,
283
- isVisible,
284
- }) =>
285
- h.dialog(
286
- [...dialog, h.Class(dialogClassName)],
287
- isVisible
288
- ? [
289
- h.div([...backdrop, h.Class(backdropClassName)]),
290
- h.div(
291
- [...panel, h.Class(panelClassName)],
292
- editFiltersContent(
293
- title,
294
- description,
295
- comboboxModel,
296
- maybeSelectedCity,
297
- h,
298
- ),
299
- ),
300
- ]
301
- : [],
302
- ),
294
+ toView: overlayDialogView,
303
295
  },
304
296
  toParentMessage: message =>
305
297
  UiMessage.GotOverlayDialogDemoMessage({ message }),
306
298
  }),
307
299
  ],
308
300
  )
301
+ }
309
302
 
310
303
  const nestedDemo = (
311
304
  parentDialogModel: Dialog.Model,
312
305
  childDialogModel: Dialog.Model,
313
306
  h: HtmlBuilder<UiMessage>,
314
- ): Html =>
315
- h.div(
307
+ ): Html => {
308
+ const settingsDialogView = (render: Dialog.RenderInfo): Html =>
309
+ dialogWithPanel(
310
+ render,
311
+ backdropClassName,
312
+ settingsPanelClassName,
313
+ () =>
314
+ projectSettingsContent(
315
+ render.closeButton,
316
+ render.title,
317
+ render.description,
318
+ h,
319
+ ),
320
+ h,
321
+ )
322
+
323
+ const deleteProjectDialogView = (render: Dialog.RenderInfo): Html =>
324
+ dialogWithPanel(
325
+ render,
326
+ backdropClassName,
327
+ confirmPanelClassName,
328
+ () =>
329
+ deleteProjectContent(
330
+ render.closeButton,
331
+ render.title,
332
+ render.description,
333
+ h,
334
+ ),
335
+ h,
336
+ )
337
+
338
+ return h.div(
316
339
  [],
317
340
  [
318
341
  trigger(
@@ -326,32 +349,7 @@ const nestedDemo = (
326
349
  view: Dialog.view,
327
350
  viewInputs: {
328
351
  hasDescription: true,
329
- toView: ({
330
- dialog,
331
- backdrop,
332
- panel,
333
- closeButton,
334
- title,
335
- description,
336
- isVisible,
337
- }) =>
338
- h.dialog(
339
- [...dialog, h.Class(dialogClassName)],
340
- isVisible
341
- ? [
342
- h.div([...backdrop, h.Class(backdropClassName)]),
343
- h.div(
344
- [...panel, h.Class(settingsPanelClassName)],
345
- projectSettingsContent(
346
- closeButton,
347
- title,
348
- description,
349
- h,
350
- ),
351
- ),
352
- ]
353
- : [],
354
- ),
352
+ toView: settingsDialogView,
355
353
  },
356
354
  toParentMessage: message =>
357
355
  UiMessage.GotNestedDialogParentDemoMessage({ message }),
@@ -362,33 +360,14 @@ const nestedDemo = (
362
360
  view: Dialog.view,
363
361
  viewInputs: {
364
362
  hasDescription: true,
365
- toView: ({
366
- dialog,
367
- backdrop,
368
- panel,
369
- closeButton,
370
- title,
371
- description,
372
- isVisible,
373
- }) =>
374
- h.dialog(
375
- [...dialog, h.Class(dialogClassName)],
376
- isVisible
377
- ? [
378
- h.div([...backdrop, h.Class(backdropClassName)]),
379
- h.div(
380
- [...panel, h.Class(confirmPanelClassName)],
381
- deleteProjectContent(closeButton, title, description, h),
382
- ),
383
- ]
384
- : [],
385
- ),
363
+ toView: deleteProjectDialogView,
386
364
  },
387
365
  toParentMessage: message =>
388
366
  UiMessage.GotNestedDialogChildDemoMessage({ message }),
389
367
  }),
390
368
  ],
391
369
  )
370
+ }
392
371
 
393
372
  // VIEW
394
373
 
@@ -68,6 +68,131 @@ const subheading = (text: string, h: HtmlBuilder<UiMessage>): Html => {
68
68
 
69
69
  export const view = Submodel.defineView<UiModel, UiMessage>(
70
70
  (model, h): Html => {
71
+ const basicDisclosureView = (
72
+ attributes: Disclosure.DisclosureAttributes<UiMessage>,
73
+ ): Html =>
74
+ h.div(
75
+ [],
76
+ [
77
+ h.button(
78
+ [
79
+ ...attributes.button,
80
+ h.Class(
81
+ 'w-full flex items-center justify-between px-4 py-3 text-left text-base font-normal cursor-pointer transition border border-gray-300 text-gray-900 hover:bg-gray-200/50 rounded-lg data-[open]:rounded-b-none data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 select-none',
82
+ ),
83
+ ],
84
+ [buttonContent(model.isDisclosureBasicDemoOpen, h)],
85
+ ),
86
+ model.isDisclosureBasicDemoOpen
87
+ ? h.div(
88
+ [
89
+ ...attributes.panel,
90
+ h.Class(
91
+ 'px-4 py-3 border-x border-b border-gray-300 rounded-b-lg text-gray-800',
92
+ ),
93
+ ],
94
+ [panelText(h)],
95
+ )
96
+ : h.empty,
97
+ ],
98
+ )
99
+
100
+ const animatedDisclosureView = (
101
+ attributes: Disclosure.DisclosureAttributes<UiMessage>,
102
+ ): Html =>
103
+ h.div(
104
+ [h.Class('border border-gray-300 rounded-lg overflow-hidden')],
105
+ [
106
+ h.button(
107
+ [
108
+ ...attributes.button,
109
+ h.Class(
110
+ 'w-full flex items-center justify-between px-4 py-3 text-left text-base font-normal cursor-pointer transition text-gray-900 hover:bg-gray-200/50 focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-accent-600 data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 select-none',
111
+ ),
112
+ ],
113
+ [buttonContent(model.isDisclosureAnimatedDemoOpen, h)],
114
+ ),
115
+ attributes.animatePanel(
116
+ h.div(
117
+ [
118
+ ...attributes.panel,
119
+ h.Class('px-4 py-3 border-t border-gray-300 text-gray-800'),
120
+ ],
121
+ [panelText(h)],
122
+ ),
123
+ ),
124
+ ],
125
+ )
126
+
127
+ const collapsedPreviewView = ({
128
+ button,
129
+ panel,
130
+ animatePanel,
131
+ }: Disclosure.DisclosureAttributes<UiMessage>): Html =>
132
+ h.article(
133
+ [
134
+ h.Class(
135
+ 'relative overflow-hidden rounded-lg border border-gray-300 bg-white',
136
+ ),
137
+ ],
138
+ [
139
+ h.h4(
140
+ [h.Class('px-4 py-3 text-base font-normal text-gray-900')],
141
+ ['Why the Elm Architecture scales'],
142
+ ),
143
+ h.div(
144
+ [h.Class('relative')],
145
+ [
146
+ animatePanel(
147
+ h.div(
148
+ [
149
+ ...panel,
150
+ h.Class(
151
+ clsx(
152
+ 'border-t border-gray-300 px-4 pt-3',
153
+ model.isDisclosureCollapsedPreviewDemoOpen
154
+ ? 'pb-20'
155
+ : 'pb-3',
156
+ ),
157
+ ),
158
+ ],
159
+ [collapsedPreviewPanel(h)],
160
+ ),
161
+ { peek: COLLAPSED_PREVIEW_HEIGHT },
162
+ ),
163
+ ...(model.isDisclosureCollapsedPreviewDemoOpen
164
+ ? []
165
+ : [
166
+ h.div([
167
+ h.AriaHidden(true),
168
+ h.Class(
169
+ 'pointer-events-none absolute inset-x-0 bottom-0 h-16 bg-gradient-to-t from-white to-transparent',
170
+ ),
171
+ ]),
172
+ ]),
173
+ ],
174
+ ),
175
+ h.div(
176
+ [h.Class('absolute inset-x-0 bottom-2.5 flex justify-center px-4')],
177
+ [
178
+ h.button(
179
+ [
180
+ ...button,
181
+ h.Class(
182
+ 'cursor-pointer whitespace-nowrap rounded-full border border-gray-300 bg-white px-5 py-2 text-sm font-medium text-gray-900 shadow-sm transition hover:bg-gray-100 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent-600 select-none',
183
+ ),
184
+ ],
185
+ [
186
+ model.isDisclosureCollapsedPreviewDemoOpen
187
+ ? 'Show less'
188
+ : 'Read more',
189
+ ],
190
+ ),
191
+ ],
192
+ ),
193
+ ],
194
+ )
195
+
71
196
  return h.div(
72
197
  [],
73
198
  [
@@ -90,32 +215,7 @@ export const view = Submodel.defineView<UiModel, UiMessage>(
90
215
  isOpen: model.isDisclosureBasicDemoOpen,
91
216
  onToggle: isOpen =>
92
217
  UiMessage.ToggledDisclosureBasicDemo({ isOpen }),
93
- toView: attributes =>
94
- h.div(
95
- [],
96
- [
97
- h.button(
98
- [
99
- ...attributes.button,
100
- h.Class(
101
- 'w-full flex items-center justify-between px-4 py-3 text-left text-base font-normal cursor-pointer transition border border-gray-300 text-gray-900 hover:bg-gray-200/50 rounded-lg data-[open]:rounded-b-none data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 select-none',
102
- ),
103
- ],
104
- [buttonContent(model.isDisclosureBasicDemoOpen, h)],
105
- ),
106
- model.isDisclosureBasicDemoOpen
107
- ? h.div(
108
- [
109
- ...attributes.panel,
110
- h.Class(
111
- 'px-4 py-3 border-x border-b border-gray-300 rounded-b-lg text-gray-800',
112
- ),
113
- ],
114
- [panelText(h)],
115
- )
116
- : h.empty,
117
- ],
118
- ),
218
+ toView: basicDisclosureView,
119
219
  },
120
220
  h,
121
221
  ),
@@ -134,32 +234,7 @@ export const view = Submodel.defineView<UiModel, UiMessage>(
134
234
  isOpen: model.isDisclosureAnimatedDemoOpen,
135
235
  onToggle: isOpen =>
136
236
  UiMessage.ToggledDisclosureAnimatedDemo({ isOpen }),
137
- toView: attributes =>
138
- h.div(
139
- [h.Class('border border-gray-300 rounded-lg overflow-hidden')],
140
- [
141
- h.button(
142
- [
143
- ...attributes.button,
144
- h.Class(
145
- 'w-full flex items-center justify-between px-4 py-3 text-left text-base font-normal cursor-pointer transition text-gray-900 hover:bg-gray-200/50 focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-accent-600 data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 select-none',
146
- ),
147
- ],
148
- [buttonContent(model.isDisclosureAnimatedDemoOpen, h)],
149
- ),
150
- attributes.animatePanel(
151
- h.div(
152
- [
153
- ...attributes.panel,
154
- h.Class(
155
- 'px-4 py-3 border-t border-gray-300 text-gray-800',
156
- ),
157
- ],
158
- [panelText(h)],
159
- ),
160
- ),
161
- ],
162
- ),
237
+ toView: animatedDisclosureView,
163
238
  },
164
239
  h,
165
240
  ),
@@ -175,74 +250,7 @@ export const view = Submodel.defineView<UiModel, UiMessage>(
175
250
  isOpen: model.isDisclosureCollapsedPreviewDemoOpen,
176
251
  onToggle: isOpen =>
177
252
  UiMessage.ToggledDisclosureCollapsedPreviewDemo({ isOpen }),
178
- toView: ({ button, panel, animatePanel }) =>
179
- h.article(
180
- [
181
- h.Class(
182
- 'relative overflow-hidden rounded-lg border border-gray-300 bg-white',
183
- ),
184
- ],
185
- [
186
- h.h4(
187
- [h.Class('px-4 py-3 text-base font-normal text-gray-900')],
188
- ['Why the Elm Architecture scales'],
189
- ),
190
- h.div(
191
- [h.Class('relative')],
192
- [
193
- animatePanel(
194
- h.div(
195
- [
196
- ...panel,
197
- h.Class(
198
- clsx(
199
- 'border-t border-gray-300 px-4 pt-3',
200
- model.isDisclosureCollapsedPreviewDemoOpen
201
- ? 'pb-20'
202
- : 'pb-3',
203
- ),
204
- ),
205
- ],
206
- [collapsedPreviewPanel(h)],
207
- ),
208
- { peek: COLLAPSED_PREVIEW_HEIGHT },
209
- ),
210
- ...(model.isDisclosureCollapsedPreviewDemoOpen
211
- ? []
212
- : [
213
- h.div([
214
- h.AriaHidden(true),
215
- h.Class(
216
- 'pointer-events-none absolute inset-x-0 bottom-0 h-16 bg-gradient-to-t from-white to-transparent',
217
- ),
218
- ]),
219
- ]),
220
- ],
221
- ),
222
- h.div(
223
- [
224
- h.Class(
225
- 'absolute inset-x-0 bottom-2.5 flex justify-center px-4',
226
- ),
227
- ],
228
- [
229
- h.button(
230
- [
231
- ...button,
232
- h.Class(
233
- 'cursor-pointer whitespace-nowrap rounded-full border border-gray-300 bg-white px-5 py-2 text-sm font-medium text-gray-900 shadow-sm transition hover:bg-gray-100 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent-600 select-none',
234
- ),
235
- ],
236
- [
237
- model.isDisclosureCollapsedPreviewDemoOpen
238
- ? 'Show less'
239
- : 'Read more',
240
- ],
241
- ),
242
- ],
243
- ),
244
- ],
245
- ),
253
+ toView: collapsedPreviewView,
246
254
  },
247
255
  h,
248
256
  ),