@continuum-js/dom 0.3.0 → 0.3.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/index.d.ts CHANGED
@@ -8,6 +8,7 @@ export declare function scope<T>(fn: () => T): {
8
8
  };
9
9
  /** Register a cleanup in the current owner (no-op outside any owner). */
10
10
  export declare function onCleanup(fn: () => void): void;
11
+ /** Anything placeable in JSX: nodes, behaviors (live-bound), primitives, arrays. */
11
12
  export type Child = Node | Behavior<unknown> | string | number | boolean | null | undefined | Child[];
12
13
  type Props = Record<string, unknown> | null;
13
14
  /** Fragment marker for `--jsxFragmentFactory Fragment`. */
@@ -21,10 +22,12 @@ export declare function h(tag: string | Component | typeof Fragment, props: Prop
21
22
  export declare function dyn<T>(b: Behavior<T>, render: (v: T) => Child): Node;
22
23
  /** Keyed list: reuses rows by key, reorders with minimal moves (LIS). */
23
24
  export declare function each<T, K>(items: Behavior<T[]>, key: (item: T) => K, render: (item: T) => Child): Node;
25
+ /** A context handle: identity plus the value used when nothing was provided. */
24
26
  export interface Context<T> {
25
27
  readonly id: symbol;
26
28
  readonly defaultValue: T;
27
29
  }
30
+ /** Create a context. Provide with `provide`, read with `use`. */
28
31
  export declare function createContext<T>(defaultValue: T): Context<T>;
29
32
  /** Write a context value into the current owner. */
30
33
  export declare function provide<T>(ctx: Context<T>, value: T): void;
package/dist/index.js CHANGED
@@ -276,12 +276,30 @@ export function dyn(b, render) {
276
276
  frag.appendChild(start);
277
277
  frag.appendChild(end);
278
278
  let current = null;
279
- const update = (v) => {
279
+ // Level-triggered: render the behavior's CURRENT value, not the delivered
280
+ // occurrence. A listener that runs earlier in the post phase may re-enter
281
+ // with a new moment (e.g. a router redirect); the stale queued delivery
282
+ // then must not clobber the newer render. Deduping by Object.is also makes
283
+ // duplicate deliveries free.
284
+ let hasRendered = false;
285
+ let renderedValue;
286
+ const update = () => {
287
+ const v = b.sampleNoTrans();
288
+ if (hasRendered && Object.is(renderedValue, v))
289
+ return;
290
+ hasRendered = true;
291
+ renderedValue = v;
280
292
  if (current) {
281
293
  current.dispose();
282
- for (const n of current.nodes)
283
- if (n.parentNode)
284
- n.parentNode.removeChild(n);
294
+ // Sweep the whole live range between the markers: a nested dynamic
295
+ // region at the root of this one may have swapped nodes since build,
296
+ // so the recorded node list can be stale.
297
+ let n = start.nextSibling;
298
+ while (n && n !== end) {
299
+ const next = n.nextSibling;
300
+ n.parentNode?.removeChild(n);
301
+ n = next;
302
+ }
285
303
  }
286
304
  current = buildScoped(owner, () => render(v));
287
305
  const parent = end.parentNode;
@@ -386,6 +404,7 @@ export function each(items, key, render) {
386
404
  });
387
405
  return frag;
388
406
  }
407
+ /** Create a context. Provide with `provide`, read with `use`. */
389
408
  export function createContext(defaultValue) {
390
409
  return { id: Symbol("context"), defaultValue };
391
410
  }
@@ -480,6 +499,14 @@ export function animationFrames() {
480
499
  }
481
500
  // ---------------------------------------------------------------------------
482
501
  // Control-flow components — JSX wrappers over the rendering helpers.
502
+ //
503
+ // The function/component pairing is a deliberate symmetry, not duplication:
504
+ // when(b, then, else) ↔ <Show when={b}> — conditional region
505
+ // dyn(b, render) ↔ <Dynamic of={b}> — switching subtree
506
+ // each(b, by, render) ↔ <Each of={b} by={..}> — keyed list
507
+ // portal(target, ch) ↔ <Portal mount={..}> — render elsewhere
508
+ // Functions compose in plain code (no JSX required); components read better
509
+ // inside markup. Both call the same implementation.
483
510
  // ---------------------------------------------------------------------------
484
511
  // JSX always delivers children as the rest array; a single render function
485
512
  // arrives as `[fn]`. Normalize to a render callback.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@continuum-js/dom",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Continuum DOM renderer — fine-grained bindings, dynamic regions, ownership, context",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -38,6 +38,6 @@
38
38
  "access": "public"
39
39
  },
40
40
  "dependencies": {
41
- "@continuum-js/frp": "0.3.0"
41
+ "@continuum-js/frp": "0.3.1"
42
42
  }
43
43
  }