foldkit 0.168.0 → 0.169.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 (54) hide show
  1. package/dist/dom/inert.d.ts +7 -3
  2. package/dist/dom/inert.d.ts.map +1 -1
  3. package/dist/dom/inert.js +19 -9
  4. package/dist/dom/streamFromKeyBindings.d.ts +5 -3
  5. package/dist/dom/streamFromKeyBindings.d.ts.map +1 -1
  6. package/dist/dom/streamFromKeyBindings.js +7 -4
  7. package/dist/experimental/server/fragment.d.ts +15 -0
  8. package/dist/experimental/server/fragment.d.ts.map +1 -0
  9. package/dist/experimental/server/fragment.js +14 -0
  10. package/dist/experimental/server/server.d.ts +3 -2
  11. package/dist/experimental/server/server.d.ts.map +1 -1
  12. package/dist/experimental/server/server.js +20 -23
  13. package/dist/experimental/server/template.d.ts.map +1 -1
  14. package/dist/experimental/server/template.js +20 -19
  15. package/dist/html/boundary.d.ts +17 -16
  16. package/dist/html/boundary.d.ts.map +1 -1
  17. package/dist/html/boundary.js +9 -9
  18. package/dist/html/childAttribute.d.ts +5 -5
  19. package/dist/html/index.d.ts.map +1 -1
  20. package/dist/html/index.js +24 -17
  21. package/dist/html/lazy.d.ts +130 -0
  22. package/dist/html/lazy.d.ts.map +1 -1
  23. package/dist/html/lazy.js +54 -6
  24. package/dist/html/runtimeSingleton.d.ts +2 -2
  25. package/dist/html/runtimeSingleton.d.ts.map +1 -1
  26. package/dist/html/runtimeSingleton.js +2 -2
  27. package/dist/html/submodel.d.ts.map +1 -1
  28. package/dist/html/submodel.js +20 -11
  29. package/dist/imeComposition.d.ts +3 -0
  30. package/dist/imeComposition.d.ts.map +1 -0
  31. package/dist/imeComposition.js +6 -0
  32. package/dist/mount/index.d.ts +6 -5
  33. package/dist/mount/index.d.ts.map +1 -1
  34. package/dist/route/transition.d.ts +50 -0
  35. package/dist/route/transition.d.ts.map +1 -1
  36. package/dist/route/transition.js +48 -0
  37. package/dist/runtime/messageQueue.d.ts +1 -0
  38. package/dist/runtime/messageQueue.d.ts.map +1 -1
  39. package/dist/runtime/messageQueue.js +2 -0
  40. package/dist/runtime/renderer.d.ts.map +1 -1
  41. package/dist/runtime/renderer.js +18 -3
  42. package/dist/snabbdom/hooks.d.ts +2 -0
  43. package/dist/snabbdom/hooks.d.ts.map +1 -1
  44. package/dist/snabbdom/init.d.ts.map +1 -1
  45. package/dist/snabbdom/init.js +42 -12
  46. package/dist/test/internal.d.ts.map +1 -1
  47. package/dist/test/internal.js +9 -2
  48. package/dist/test/lazy.d.ts +26 -0
  49. package/dist/test/lazy.d.ts.map +1 -0
  50. package/dist/test/lazy.js +103 -0
  51. package/dist/test/public.d.ts +1 -0
  52. package/dist/test/public.d.ts.map +1 -1
  53. package/dist/test/public.js +1 -0
  54. package/package.json +1 -1
@@ -209,6 +209,34 @@ export function init(modules, domApi, options) {
209
209
  }
210
210
  return vnode.elm;
211
211
  }
212
+ // NOTE: code outside the patch can move a rendered element out of its
213
+ // parent while the vnode keeps its place among its siblings. A Mount that
214
+ // portals an overlay panel does this. Such an element cannot be a reference
215
+ // node for `insertBefore` in that parent, and a reorder of its siblings must
216
+ // not pull it back. A fragment parent is exempt, since its children live in
217
+ // the fragment's own parent.
218
+ function isChildOf(parentElement, node) {
219
+ return (api.parentNode(node) === parentElement ||
220
+ (api.isDocumentFragment?.(parentElement) ?? false));
221
+ }
222
+ function firstChildElmIn(parentElement, vnodes, startIndex, endIndex) {
223
+ for (; startIndex <= endIndex; ++startIndex) {
224
+ const elm = vnodes[startIndex]?.elm;
225
+ if (elm !== undefined && isChildOf(parentElement, elm)) {
226
+ return elm;
227
+ }
228
+ }
229
+ return null;
230
+ }
231
+ function referenceAfter(parentElement, previousEndElm, nextChildren, nextEndIndex) {
232
+ return isChildOf(parentElement, previousEndElm)
233
+ ? api.nextSibling(previousEndElm)
234
+ : firstChildElmIn(parentElement, nextChildren, nextEndIndex + 1, nextChildren.length - 1);
235
+ }
236
+ function referenceBefore(parentElement, previousChildren, previousStartIndex, previousEndIndex, nextChildren, nextEndIndex) {
237
+ return (firstChildElmIn(parentElement, previousChildren, previousStartIndex, previousEndIndex) ??
238
+ firstChildElmIn(parentElement, nextChildren, nextEndIndex + 1, nextChildren.length - 1));
239
+ }
212
240
  function addVnodes(parentElement, before, vnodes, startIndex, endIndex, insertedVnodeQueue) {
213
241
  for (; startIndex <= endIndex; ++startIndex) {
214
242
  const child = vnodes[startIndex];
@@ -242,6 +270,7 @@ export function init(modules, domApi, options) {
242
270
  }
243
271
  }
244
272
  }
273
+ data?.hook?.postdestroy?.(vnode);
245
274
  }
246
275
  }
247
276
  function removeVnodes(parentElement, vnodes, startIndex, endIndex) {
@@ -327,7 +356,6 @@ export function init(modules, domApi, options) {
327
356
  let previousKeyToIndex;
328
357
  let indexInPreviousChildren;
329
358
  let vnodeToMove;
330
- let before;
331
359
  while (previousStartIndex <= previousEndIndex &&
332
360
  nextStartIndex <= nextEndIndex) {
333
361
  if (previousStartVnode == null) {
@@ -355,14 +383,18 @@ export function init(modules, domApi, options) {
355
383
  else if (sameVnode(previousStartVnode, nextEndVnode)) {
356
384
  // Vnode moved right
357
385
  patchVnode(previousStartVnode, nextEndVnode, insertedVnodeQueue);
358
- api.insertBefore(parentElement, previousStartVnode.elm, api.nextSibling(previousEndVnode.elm));
386
+ if (isChildOf(parentElement, previousStartVnode.elm)) {
387
+ api.insertBefore(parentElement, previousStartVnode.elm, referenceAfter(parentElement, previousEndVnode.elm, nextChildren, nextEndIndex));
388
+ }
359
389
  previousStartVnode = previousChildren[++previousStartIndex];
360
390
  nextEndVnode = nextChildren[--nextEndIndex];
361
391
  }
362
392
  else if (sameVnode(previousEndVnode, nextStartVnode)) {
363
393
  // Vnode moved left
364
394
  patchVnode(previousEndVnode, nextStartVnode, insertedVnodeQueue);
365
- api.insertBefore(parentElement, previousEndVnode.elm, previousStartVnode.elm);
395
+ if (isChildOf(parentElement, previousEndVnode.elm)) {
396
+ api.insertBefore(parentElement, previousEndVnode.elm, referenceBefore(parentElement, previousChildren, previousStartIndex, previousEndIndex - 1, nextChildren, nextEndIndex));
397
+ }
366
398
  previousEndVnode = previousChildren[--previousEndIndex];
367
399
  nextStartVnode = nextChildren[++nextStartIndex];
368
400
  }
@@ -378,13 +410,13 @@ export function init(modules, domApi, options) {
378
410
  : previousKeyToIndex.get(nextStartKey);
379
411
  if (indexInPreviousChildren === undefined) {
380
412
  // `nextStartVnode` is new, create and insert it in beginning
381
- api.insertBefore(parentElement, createElm(nextStartVnode, insertedVnodeQueue), previousStartVnode.elm);
413
+ api.insertBefore(parentElement, createElm(nextStartVnode, insertedVnodeQueue), referenceBefore(parentElement, previousChildren, previousStartIndex, previousEndIndex, nextChildren, nextEndIndex));
382
414
  nextStartVnode = nextChildren[++nextStartIndex];
383
415
  }
384
416
  else if (nextEndVnode.key === undefined ||
385
417
  previousKeyToIndex.get(nextEndVnode.key) === undefined) {
386
418
  // `nextEndVnode` is new, create and insert it in the end
387
- api.insertBefore(parentElement, createElm(nextEndVnode, insertedVnodeQueue), api.nextSibling(previousEndVnode.elm));
419
+ api.insertBefore(parentElement, createElm(nextEndVnode, insertedVnodeQueue), referenceAfter(parentElement, previousEndVnode.elm, nextChildren, nextEndIndex));
388
420
  nextEndVnode = nextChildren[--nextEndIndex];
389
421
  }
390
422
  else {
@@ -392,23 +424,21 @@ export function init(modules, domApi, options) {
392
424
  // moving `nextStartVnode` into position
393
425
  vnodeToMove = previousChildren[indexInPreviousChildren];
394
426
  if (!sameVnode(vnodeToMove, nextStartVnode)) {
395
- api.insertBefore(parentElement, createElm(nextStartVnode, insertedVnodeQueue), previousStartVnode.elm);
427
+ api.insertBefore(parentElement, createElm(nextStartVnode, insertedVnodeQueue), referenceBefore(parentElement, previousChildren, previousStartIndex, previousEndIndex, nextChildren, nextEndIndex));
396
428
  }
397
429
  else {
398
430
  patchVnode(vnodeToMove, nextStartVnode, insertedVnodeQueue);
399
431
  previousChildren[indexInPreviousChildren] = undefined;
400
- api.insertBefore(parentElement, vnodeToMove.elm, previousStartVnode.elm);
432
+ if (isChildOf(parentElement, vnodeToMove.elm)) {
433
+ api.insertBefore(parentElement, vnodeToMove.elm, referenceBefore(parentElement, previousChildren, previousStartIndex, previousEndIndex, nextChildren, nextEndIndex));
434
+ }
401
435
  }
402
436
  nextStartVnode = nextChildren[++nextStartIndex];
403
437
  }
404
438
  }
405
439
  }
406
440
  if (nextStartIndex <= nextEndIndex) {
407
- before =
408
- nextChildren[nextEndIndex + 1] == null
409
- ? null
410
- : nextChildren[nextEndIndex + 1].elm;
411
- addVnodes(parentElement, before, nextChildren, nextStartIndex, nextEndIndex, insertedVnodeQueue);
441
+ addVnodes(parentElement, firstChildElmIn(parentElement, nextChildren, nextEndIndex + 1, nextChildren.length - 1), nextChildren, nextStartIndex, nextEndIndex, insertedVnodeQueue);
412
442
  }
413
443
  if (previousStartIndex <= previousEndIndex) {
414
444
  removeVnodes(parentElement, previousChildren, previousStartIndex, previousEndIndex);
@@ -1 +1 @@
1
- {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../src/test/internal.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../src/test/internal.ts"],"names":[],"mappings":"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"}
@@ -190,6 +190,11 @@ export const assertZeroCommands = (commands) => {
190
190
  throw new Error(`Expected no Commands but found:\n\n${formatCommandList(commands)}`);
191
191
  }
192
192
  };
193
+ const formatChildCommandHint = (commands) => Array.some(commands, command => Array.isReadonlyArrayNonEmpty(command.messageMappers ?? []))
194
+ ? '\n\nSome Commands came from a child Submodel. If the child is an\n' +
195
+ '@foldkit/ui component, check its test namespace for a helper\n' +
196
+ '(for example, Toast.test.drainEntry).'
197
+ : '';
193
198
  /** Throws when trying to send a message with unresolved Commands. Keyed
194
199
  * Commands (built with an interruptible `Command.define`) and Interrupt
195
200
  * Commands are exempt: they model in-flight async work that legitimately
@@ -204,7 +209,8 @@ export const assertNoUnresolvedCommands = (commands, context) => {
204
209
  throw new Error(`I found unresolved Commands ${context}:\n\n${formatCommandList(unresolvable)}\n\n` +
205
210
  'Resolve all Commands before sending the next Message.\n' +
206
211
  'Use resolve(Definition | instance, ResultMessage) for each one,\n' +
207
- 'or resolveAll(...resolvers) to resolve them all at once.');
212
+ 'or resolveAll(...resolvers) to resolve them all at once.' +
213
+ formatChildCommandHint(unresolvable));
208
214
  }
209
215
  };
210
216
  /** Throws when Commands remain at the end of a test. */
@@ -213,7 +219,8 @@ export const assertAllCommandsResolved = (commands) => {
213
219
  throw new Error(`I found Commands without resolvers:\n\n${formatCommandList(commands)}\n\n` +
214
220
  'Every Command produced by update needs to be resolved.\n' +
215
221
  'Use resolve(Definition | instance, ResultMessage) for each one,\n' +
216
- 'or resolveAll(...resolvers) to resolve them all at once.');
222
+ 'or resolveAll(...resolvers) to resolve them all at once.' +
223
+ formatChildCommandHint(commands));
217
224
  }
218
225
  };
219
226
  const formatPendingMount = ({ name, args, occurrence, }) => {
@@ -0,0 +1,26 @@
1
+ import type { Document, Html, HtmlBuilder } from '../html/index.js';
2
+ /** Checks lazy cache reuse by rendering `view` twice with the same `model`.
3
+ * Throws if a lazy call misses its cache on the second render. The error
4
+ * identifies each slot, includes the key for keyed calls, and explains the
5
+ * miss. `ArgumentsChanged` also lists the changed argument indices. Slot
6
+ * numbers identify lazy instances in the order they are first called on
7
+ * the second render.
8
+ *
9
+ * Throws when the second render makes no lazy calls. Supply a Model that
10
+ * renders the memoized content to test. Check states that render different
11
+ * content separately. When an outer lazy cache hit skips a child view,
12
+ * test the child view directly to check its lazy calls.
13
+ *
14
+ * ```ts
15
+ * import { Lazy } from 'foldkit/test'
16
+ *
17
+ * test('reuses lazy views for an unchanged Model', () => {
18
+ * Lazy.expectAllReused({ view, model: initialModel })
19
+ * })
20
+ * ```
21
+ */
22
+ export declare const expectAllReused: <Model, Message>(config: Readonly<{
23
+ view: (model: Model, h: HtmlBuilder<Message>) => Html | Document;
24
+ model: Model;
25
+ }>) => void;
26
+ //# sourceMappingURL=lazy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lazy.d.ts","sourceRoot":"","sources":["../../src/test/lazy.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAgGnE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,eAAe,GAAI,KAAK,EAAE,OAAO,UACpC,QAAQ,CAAC;IACf,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,KAAK,IAAI,GAAG,QAAQ,CAAA;IAChE,KAAK,EAAE,KAAK,CAAA;CACb,CAAC,KACD,IAiCF,CAAA"}
@@ -0,0 +1,103 @@
1
+ import { Array, Context, Effect, Predicate, pipe } from 'effect';
2
+ import { __beginRender as beginHtmlRender, __clearRuntime as clearHtmlRuntime, __createBoundaryRegistry as createHtmlBoundaryRegistry, __htmlBuilder as htmlBuilderFor, __setRuntime as setHtmlRuntime, } from '../html/index.js';
3
+ import { LazyMissReason, observeLazyResolutions, } from '../html/lazy.js';
4
+ import { MountTracker } from '../mount/index.js';
5
+ import { Dispatch } from '../runtime/dispatch.js';
6
+ const noOpDispatch = Dispatch.of({
7
+ dispatchAsync: () => Effect.void,
8
+ dispatchSync: () => { },
9
+ });
10
+ const lazyContext = Context.make(Dispatch, noOpDispatch).pipe(Context.add(MountTracker, {
11
+ started: () => { },
12
+ ended: () => { },
13
+ }));
14
+ const REASON_HINTS = {
15
+ NoCachedEntry: 'Create the slot at module scope. Use a stable key for each rendered item or position.',
16
+ FunctionChanged: 'Pass the same view function for each slot or key. Define it outside view.',
17
+ FrameChanged: 'Use separate slots or keys for different Submodel boundaries.',
18
+ ArgumentCountChanged: 'Pass the same number of arguments to each slot or key.',
19
+ ArgumentsChanged: 'Reuse the same objects, arrays, and functions when their values have not changed.',
20
+ };
21
+ const formatKey = (key) => Predicate.isString(key) ? JSON.stringify(key) : String(key);
22
+ const formatReason = LazyMissReason.$match({
23
+ NoCachedEntry: () => 'NoCachedEntry',
24
+ FunctionChanged: () => 'FunctionChanged',
25
+ FrameChanged: () => 'FrameChanged',
26
+ ArgumentCountChanged: ({ previousCount, currentCount }) => `ArgumentCountChanged from ${previousCount} to ${currentCount}`,
27
+ ArgumentsChanged: ({ indices }) => `ArgumentsChanged at ${indices.length === 1 ? 'index' : 'indices'} ${indices.join(', ')}`,
28
+ });
29
+ const formatMiss = ({ slotId, key, reason }) => key === undefined
30
+ ? ` slot ${slotId}: ${formatReason(reason)}`
31
+ : ` slot ${slotId}, key ${formatKey(key)}: ${formatReason(reason)}`;
32
+ const formatFailure = (misses) => {
33
+ const missCount = misses.length === 1
34
+ ? '1 lazy cache miss'
35
+ : `${misses.length} lazy cache misses`;
36
+ const hints = pipe(misses, Array.map(({ reason }) => reason._tag), Array.dedupe, Array.map(tag => ` ${tag}: ${REASON_HINTS[tag]}`));
37
+ return [
38
+ `${missCount} on the second render with the same Model:`,
39
+ '',
40
+ ...Array.map(misses, formatMiss),
41
+ '',
42
+ ...hints,
43
+ ].join('\n');
44
+ };
45
+ const toMisses = (resolutions) => {
46
+ const slotIds = new Map();
47
+ const misses = [];
48
+ for (const { slot, key, missReason } of resolutions) {
49
+ const slotId = slotIds.get(slot) ?? slotIds.size + 1;
50
+ slotIds.set(slot, slotId);
51
+ if (missReason !== undefined) {
52
+ misses.push({ slotId, key, reason: missReason });
53
+ }
54
+ }
55
+ return misses;
56
+ };
57
+ /** Checks lazy cache reuse by rendering `view` twice with the same `model`.
58
+ * Throws if a lazy call misses its cache on the second render. The error
59
+ * identifies each slot, includes the key for keyed calls, and explains the
60
+ * miss. `ArgumentsChanged` also lists the changed argument indices. Slot
61
+ * numbers identify lazy instances in the order they are first called on
62
+ * the second render.
63
+ *
64
+ * Throws when the second render makes no lazy calls. Supply a Model that
65
+ * renders the memoized content to test. Check states that render different
66
+ * content separately. When an outer lazy cache hit skips a child view,
67
+ * test the child view directly to check its lazy calls.
68
+ *
69
+ * ```ts
70
+ * import { Lazy } from 'foldkit/test'
71
+ *
72
+ * test('reuses lazy views for an unchanged Model', () => {
73
+ * Lazy.expectAllReused({ view, model: initialModel })
74
+ * })
75
+ * ```
76
+ */
77
+ export const expectAllReused = (config) => {
78
+ const { view, model } = config;
79
+ const registry = createHtmlBoundaryRegistry();
80
+ const render = () => {
81
+ beginHtmlRender(registry);
82
+ setHtmlRuntime(noOpDispatch.dispatchSync, lazyContext, registry);
83
+ try {
84
+ view(model, htmlBuilderFor());
85
+ }
86
+ finally {
87
+ clearHtmlRuntime();
88
+ }
89
+ };
90
+ render();
91
+ const resolutions = [];
92
+ observeLazyResolutions(resolution => {
93
+ resolutions.push(resolution);
94
+ }, render);
95
+ if (Array.isArrayEmpty(resolutions)) {
96
+ throw new Error('The second render made no lazy calls. Choose a Model that renders ' +
97
+ 'the memoized content you want to test.');
98
+ }
99
+ const misses = toMisses(resolutions);
100
+ if (Array.isReadonlyArrayNonEmpty(misses)) {
101
+ throw new Error(formatFailure(misses));
102
+ }
103
+ };
@@ -1,3 +1,4 @@
1
1
  export * as Story from './story.js';
2
2
  export * as Scene from './scene.js';
3
+ export * as Lazy from './lazy.js';
3
4
  //# sourceMappingURL=public.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/test/public.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/test/public.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA"}
@@ -1,2 +1,3 @@
1
1
  export * as Story from './story.js';
2
2
  export * as Scene from './scene.js';
3
+ export * as Lazy from './lazy.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foldkit",
3
- "version": "0.168.0",
3
+ "version": "0.169.0",
4
4
  "description": "A TypeScript frontend framework, built on Effect and architected like Elm",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",