@xmachines/play-dom 2.0.0 → 2.1.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.
@@ -1,12 +1,14 @@
1
1
  /**
2
- * PlayRenderer.ts — XMachines wrapper around @xmachines/json-render-dom.
2
+ * PlayRenderer.ts — the XMachines wrapper of @xmachines/json-render-dom.
3
3
  *
4
- * Bridges actor.currentView (TC39 Signal) to the inner DOM renderer using watchSignal.
5
- * Exposes connect() / disconnect() methods following the same pattern as
6
- * play-react, play-vue, and play-solid PlayRenderer classes.
4
+ * It connects actor.currentView, a TC39 Signal, to the DOM renderer below it, with
5
+ * watchSignal. It gives you the connect() method and the disconnect() method, in
6
+ * the same pattern as the PlayRenderer class of play-react, of play-vue, and of
7
+ * play-solid.
7
8
  *
8
- * State store: uses external `store` option if provided (controlled mode); otherwise
9
- * creates a fresh @xstate/store atom per view transition seeded from spec.state.
9
+ * The state store: the renderer uses the external `store` option when the caller
10
+ * gives one, and this is the controlled mode. Without that option, it makes a new
11
+ * @xstate/store atom for each view transition, with the values of spec.state.
10
12
  */
11
13
  import { watchSignal } from "@xmachines/play-signals";
12
14
  import { createAtom } from "@xstate/store";
@@ -14,26 +16,27 @@ import { xstateStoreStateStore } from "@xmachines/json-render-xstate";
14
16
  import { createViewStoreLifecycle, refreshContextSubtree } from "@xmachines/play-actor";
15
17
  import { createIncrementalRenderer } from "@xmachines/json-render-dom";
16
18
  /**
17
- * PlayRenderer connects an actor's `currentView` signal to the DOM renderer.
19
+ * PlayRenderer connects the `currentView` signal of an actor to the DOM renderer.
18
20
  *
19
- * Watches `actor.currentView` via TC39 Signals and renders `DomComponentRenderer`
20
- * functions into `container` on every view transition. Cleared on `disconnect()`.
21
+ * It watches `actor.currentView` through the TC39 Signals. It renders each
22
+ * `DomComponentRenderer` function into `container` on every view transition.
23
+ * `disconnect()` clears the container.
21
24
  *
22
- * Options from `PlayDomOptions` (which extends `UIProviderOptions`) are all forwarded
23
- * into `DomRenderContext` on every render pass:
24
- * - `functions` — named compute functions for `{ $computed: "name" }` prop expressions
25
- * - `directives` — custom `$`-prefixed dynamic values (from `defineDirective`), resolved during prop resolution
26
- * - `validationFunctions` — custom validation functions, available at `ctx.ctx.validationFunctions`
27
- * - `navigate` — navigation callback, invoked on `onSuccess: { navigate: "..." }` action bindings
28
- * - `onRenderError` — called with `(error, name)` for component render errors and action handler rejections
25
+ * Every option of `PlayDomOptions`, which extends `UIProviderOptions`, goes into
26
+ * `DomRenderContext` on each render pass:
27
+ * - `functions` — the named compute functions of a `{ $computed: "name" }` prop expression
28
+ * - `directives` — your own dynamic values with a `$` prefix, from `defineDirective`. The renderer resolves them with the props
29
+ * - `validationFunctions` — your own check functions. They are available at `ctx.ctx.validationFunctions`
30
+ * - `navigate` — the navigation callback. The renderer calls it for an `onSuccess: { navigate: "..." }` action binding
31
+ * - `onRenderError` — the renderer calls it with `(error, name)` for a component render error and for an action handler rejection
29
32
  *
30
- * **Preferred usage via `registryResult`:**
33
+ * **The preferred use, with `registryResult`:**
31
34
  * ```typescript
32
35
  * import { PlayRenderer, defineRegistry } from "@xmachines/play-dom";
33
36
  *
34
37
  * const registryResult = defineRegistry(catalog, { components, actions });
35
38
  * const renderer = new PlayRenderer(container, actor, registryResult.registry, {
36
- * registryResult, // wires setState/getState from xstate store automatically
39
+ * registryResult, // it connects setState and getState of the xstate store for you
37
40
  * navigate: (path) => myRouter.push(path),
38
41
  * functions: { fullName: (args) => `${args.first} ${args.last}` },
39
42
  * });
@@ -42,7 +45,7 @@ import { createIncrementalRenderer } from "@xmachines/json-render-dom";
42
45
  * renderer.disconnect();
43
46
  * ```
44
47
  *
45
- * **Controlled store mode** — bring your own `StateStore`:
48
+ * **The controlled store mode** — you give your own `StateStore`:
46
49
  * ```typescript
47
50
  * import { createAtom } from "@xstate/store";
48
51
  * import { xstateStoreStateStore } from "@xmachines/json-render-xstate";
@@ -53,8 +56,9 @@ import { createIncrementalRenderer } from "@xmachines/json-render-dom";
53
56
  * renderer.connect();
54
57
  * ```
55
58
  *
56
- * Double `connect()` is safe calling `connect()` while already connected
57
- * automatically disconnects first, preventing double-render subscriptions.
59
+ * A second `connect()` is safe. A `connect()` call on a connected renderer
60
+ * disconnects it first. Therefore the renderer holds no second render
61
+ * subscription.
58
62
  */
59
63
  export class PlayRenderer {
60
64
  container;
@@ -64,56 +68,56 @@ export class PlayRenderer {
64
68
  unwatch = null;
65
69
  storeUnsubscribe = null;
66
70
  /**
67
- * Live watch-subscription cleanups. A `Set` (not an array) so that each
68
- * registered cleanup can delete ITSELF on invocation: the incremental
69
- * renderer releases a watcher when its element unmounts, and the registered
70
- * wrapper is what it invokes so the Set shrinks in lock-step with live
71
- * subscriptions instead of accumulating one spent closure per historical
72
- * mount over a long-lived view.
71
+ * The cleanup functions of the live watch subscriptions. This field is a `Set`,
72
+ * and not an array, so that each registered cleanup function can delete ITSELF on
73
+ * its call: the incremental renderer releases a watcher when its element unmounts,
74
+ * and it calls the registered wrapper. The Set therefore shrinks with the live
75
+ * subscriptions. It does not collect one spent closure for each historical mount of
76
+ * a view with a long life.
73
77
  */
74
78
  watchCleanups = new Set();
75
79
  /**
76
- * viewKey of the currently rendered view and the (unguarded) store backing
77
- * it. A same-key emission means only the /context projection moved: the
78
- * slice-only fast path in render() refreshes the store in place instead of
79
- * tearing the tree down, so ephemeral view state (drafts, toggles) survives.
80
- * A null emission (a state with no meta.view) is a GAP, not a new view:
81
- * the DOM tears down but the identity and store are kept, so returning to
82
- * the same view rebuilds around the surviving ephemeral state matching
83
- * the framework providers. Reset in disconnect() a kept-alive store must
84
- * not outlive the connection.
80
+ * The viewKey of the view on the screen now, and the store behind it, without the
81
+ * guard. An emission with the same key means that only the /context projection
82
+ * moved: the fast path for a slice in render() refreshes the store in place, and it
83
+ * does not remove the tree. The ephemeral view state, such as a draft or a toggle,
84
+ * therefore stays. A null emission, from a state with no meta.view, is a GAP, and
85
+ * not a new view: the DOM goes away, but the identity and the store stay. A return
86
+ * to the same view therefore builds again around the ephemeral state that survived,
87
+ * in the same way as the framework providers. `disconnect()` resets both fields,
88
+ * because a store that stays alive must not outlive the connection.
85
89
  */
86
90
  lastViewKey = undefined;
87
91
  currentStore = null;
88
92
  /**
89
- * Store lifecycle (reseed on viewKey change, refresh /context in place
90
- * otherwise, guard identity cache) the shared coordinator from
91
- * @xmachines/play-actor. lastViewKey/currentStore above remain DOM-side
92
- * bookkeeping for the slice-only fast path, which is about the live TREE
93
- * (spec + subscription), not the store.
93
+ * The shared coordinator of the store lifecycle, from @xmachines/play-actor. It
94
+ * seeds the store again on a change of the viewKey, it refreshes /context in place
95
+ * in every other case, and it guards the identity cache. The two fields above,
96
+ * lastViewKey and currentStore, stay as the DOM-side record for the fast path of a
97
+ * slice. That path is about the live TREE, which is the spec and the subscription,
98
+ * and not about the store.
94
99
  */
95
100
  storeLifecycle = createViewStoreLifecycle((seed) => xstateStoreStateStore({ atom: createAtom(seed) }));
96
101
  /**
97
- * Set to `false` in `disconnect()` before calling `storeUnsub()`.
98
- * The `rerender` closure checks this flag at entry so that any synchronous
99
- * callback fired by the `StateStore` implementation within its own
100
- * `unsubscribe()` call (an edge-case but valid contract) does not mutate a
101
- * detached DOM tree.
102
+ * `disconnect()` sets this field to `false` before it calls `storeUnsub()`.
103
+ * The `rerender` closure reads the flag at its start. Therefore a synchronous
104
+ * callback from the `StateStore` implementation inside its own `unsubscribe()`
105
+ * call, which is rare but correct, changes no detached DOM tree.
102
106
  */
103
107
  alive = true;
104
108
  /**
105
- * @param container - `HTMLElement` to render into. Cleared and repopulated on every view transition.
106
- * @param actor - Actor providing the `currentView` signal (must implement `Viewable`).
107
- * @param registry - Component renderer map typically `registryResult.registry` from `defineRegistry`.
108
- * @param options - Configuration (see {@link PlayDomOptions}):
109
- * - `registryResult` — auto-wires `setState`/`state` from the xstate store.
110
- * - `store` — external `StateStore` (controlled mode; overrides `spec.state` seeding).
111
- * - `loading` — streaming mode flag; suppresses missing-child warnings.
112
- * - `functions` — named compute functions for `$computed` prop expressions.
113
- * - `directives` — custom `$`-prefixed dynamic values resolved during prop resolution.
114
- * - `validationFunctions` — custom validation functions; available at `ctx.ctx.validationFunctions`.
115
- * - `navigate` — navigation callback; invoked on `onSuccess: { navigate: "..." }`.
116
- * - `onRenderError` — `(error, name)` handler for component render errors and action handler rejections; suppresses `console.error` fallback.
109
+ * @param container - The `HTMLElement` to render into. Each view transition clears it and fills it again.
110
+ * @param actor - The actor with the `currentView` signal. It must implement `Viewable`.
111
+ * @param registry - The map of the component renderers, usually `registryResult.registry` from `defineRegistry`.
112
+ * @param options - The configuration. See {@link PlayDomOptions}:
113
+ * - `registryResult` — it connects `setState` and `state` of the xstate store for you.
114
+ * - `store` — an external `StateStore`, which is the controlled mode. It replaces the values of `spec.state`.
115
+ * - `loading` — the flag of the streaming mode. It stops each warning about an absent child.
116
+ * - `functions` — the named compute functions of a `$computed` prop expression.
117
+ * - `directives` — your own dynamic values with a `$` prefix. The renderer resolves them with the props.
118
+ * - `validationFunctions` — your own check functions. They are available at `ctx.ctx.validationFunctions`.
119
+ * - `navigate` — the navigation callback. The renderer calls it for `onSuccess: { navigate: "..." }`.
120
+ * - `onRenderError` — the `(error, name)` handler of a component render error and of an action handler rejection. It stops the `console.error` fallback.
117
121
  */
118
122
  constructor(container, actor, registry, options = {}) {
119
123
  this.container = container;
@@ -122,13 +126,13 @@ export class PlayRenderer {
122
126
  this.options = options;
123
127
  }
124
128
  /**
125
- * Start watching actor.currentView and render to container.
126
- * Renders the initial view synchronously, then subscribes to signal changes.
129
+ * Starts the watch of actor.currentView, and renders into the container.
130
+ * It renders the first view synchronously, then it subscribes to the signal changes.
127
131
  *
128
- * Calling `connect()` on an already-connected renderer (where a previous
129
- * `connect()` was never followed by `disconnect()`) would silently install a
130
- * second `watchSignal` subscription, causing double-renders on every view
131
- * change. Guard against this by auto-disconnecting first.
132
+ * A `connect()` call on a connected renderer, where a `disconnect()` call did not
133
+ * follow the previous `connect()`, installs a second `watchSignal` subscription.
134
+ * Each view change then renders two times. Therefore this method disconnects the
135
+ * renderer first.
132
136
  */
133
137
  connect() {
134
138
  if (this.unwatch !== null)
@@ -137,53 +141,55 @@ export class PlayRenderer {
137
141
  this.unwatch = watchSignal(this.actor.currentView, (view) => this.render(view));
138
142
  }
139
143
  /**
140
- * Stop watching and clear the container.
144
+ * Stops the watch and clears the container.
141
145
  */
142
146
  disconnect() {
143
147
  this.unwatch?.();
144
148
  this.unwatch = null;
145
- // Null the refs first so any in-flight rerender callback sees null and skips.
146
- // Capture the arrays/functions before clearing so we call the correct cleanups
147
- // even if unsubscribing the store triggers a synchronous rerender that would
148
- // otherwise overwrite watchCleanups before we iterate them.
149
+ // Set the refs to null first. A rerender callback that is still in flight therefore
150
+ // sees null, and it stops.
151
+ // Capture each array and each function before the code clears them. Therefore the
152
+ // code calls the correct cleanup functions, also when the cancellation of the store
153
+ // subscription starts a synchronous rerender. Without the capture, that rerender
154
+ // overwrites watchCleanups before the loop over them.
149
155
  const storeUnsub = this.storeUnsubscribe;
150
156
  const watchCleanups = [...this.watchCleanups];
151
157
  this.storeUnsubscribe = null;
152
158
  this.watchCleanups = new Set();
153
- // Set alive = false before calling storeUnsub() so that any synchronous
154
- // rerender callback triggered within unsubscribe() exits immediately.
159
+ // Set alive = false before the storeUnsub() call. A synchronous rerender callback
160
+ // from inside unsubscribe() therefore returns at once.
155
161
  this.alive = false;
156
162
  storeUnsub?.();
157
163
  for (const cleanup of watchCleanups)
158
164
  cleanup();
159
165
  this.container.replaceChildren();
160
- // Lifetime rule: the kept-alive store dies with the connection.
166
+ // The rule of the lifetime: the store that stays alive dies with the connection.
161
167
  this.lastViewKey = undefined;
162
168
  this.currentStore = null;
163
169
  this.storeLifecycle.reset();
164
170
  }
165
171
  /**
166
- * Number of live watch-subscription cleanups currently retained.
172
+ * The number of live watch-subscription cleanup functions now.
167
173
  *
168
- * @internal Test-only accessor for asserting that the watch-cleanup
169
- * collection tracks live registrations (no per-mount leak). Not part of the
170
- * public API and may change without notice.
174
+ * @internal This accessor is for a test only. A test asserts with it that the
175
+ * collection of the watch cleanups holds the live registrations, and that no mount
176
+ * leaks. It is not part of the public API, and it can change without a notice.
171
177
  */
172
178
  get watchCleanupCount() {
173
179
  return this.watchCleanups.size;
174
180
  }
175
181
  render(view) {
176
- // ── Slice-only fast path ────────────────────────────────────────────
177
- // Same viewKey as the live tree → only the /context projection changed
178
- // (deriveCurrentView keys emissions to the selected meta entry, and the
179
- // authored spec is static per state). Refresh the store subtree in place
180
- // — the store subscription below already drives incremental.update(),
181
- // which diffs snapshots and patches only affected elements and skip
182
- // the teardown entirely so ephemeral view state survives.
183
- // createIncrementalRenderer binds the SPEC at construction, so this
184
- // path is only safe because the spec is unchanged; a real view change
185
- // (different viewKey, or no viewKey to compare) still rebuilds below,
186
- // per the incremental renderer's discard-on-view-transition contract.
182
+ // ── The fast path of a slice ────────────────────────────────────────────
183
+ // The viewKey of the live tree is the same → only the /context projection changed.
184
+ // deriveCurrentView uses the selected meta entry as the key of each emission, and the
185
+ // authored spec of a state is static. Refresh the subtree of the store in place: the
186
+ // store subscription below calls incremental.update() already, and that function
187
+ // compares the snapshots and patches the elements of the change only. Skip the
188
+ // teardown completely, so that the ephemeral view state stays.
189
+ // createIncrementalRenderer binds the SPEC at its construction. Therefore this path
190
+ // is safe only because the spec is the same. A real view change, which means a
191
+ // different viewKey or no viewKey for a comparison, still rebuilds the tree below, as
192
+ // the discard-on-view-transition contract of the incremental renderer says.
187
193
  if (view !== null &&
188
194
  view.viewKey !== undefined &&
189
195
  this.lastViewKey === view.viewKey &&
@@ -193,37 +199,40 @@ export class PlayRenderer {
193
199
  return;
194
200
  }
195
201
  this.alive = true;
196
- // Capture and clear before calling prevents the synchronous callback fired
197
- // by some store implementations during unsubscribe from seeing a live
198
- // storeUnsubscribe and re-entering the rerender path with stale view/store.
199
- // Mirrors the capture-then-clear pattern used in disconnect().
202
+ // Capture the values and clear them before the call. Some store implementations
203
+ // fire a synchronous callback during their unsubscribe(). Without this order, that
204
+ // callback sees a live storeUnsubscribe, and it enters the rerender path again with
205
+ // an old view and an old store.
206
+ // disconnect() uses the same capture-then-clear pattern.
200
207
  const oldUnsub = this.storeUnsubscribe;
201
208
  this.storeUnsubscribe = null;
202
209
  oldUnsub?.();
203
- // Release watch cleanups from the previous view's initial render.
204
- // Without this, watch subscriptions from the prior view remain active
205
- // between a view transition and the first store update in the new view,
206
- // holding references to stale DOM elements and preventing GC.
210
+ // Release the watch cleanups of the first render of the previous view.
211
+ // Without this step, the watch subscriptions of the previous view stay active between
212
+ // a view transition and the first store update of the new view. They then hold a
213
+ // reference to a DOM element that is gone, and the garbage collector cannot take
214
+ // it.
207
215
  const prevWatchCleanups = [...this.watchCleanups];
208
216
  this.watchCleanups = new Set();
209
217
  for (const cleanup of prevWatchCleanups)
210
218
  cleanup();
211
219
  this.container.replaceChildren();
212
- // A null emission is a gap between views, not a new view: keep
213
- // lastViewKey and currentStore so a return to the same identity reuses
214
- // the store below. disconnect() remains the lifetime boundary.
220
+ // A null emission is a gap between two views, and not a new view: keep lastViewKey
221
+ // and currentStore. A return to the same identity therefore uses the store below
222
+ // again. disconnect() stays the boundary of the lifetime.
215
223
  if (!view)
216
224
  return;
217
- // Resolve the store through the shared lifecycle: external (controlled,
218
- // /context refreshed machinery-owned in both modes), the kept store
219
- // when this emission returns to the live identity (view null same
220
- // view the fast path could not take it because the DOM is gone; the
221
- // coordinator refreshes /context in place, context may have moved
222
- // during the gap), or a fresh per-view store seeded from the composed
225
+ // Resolve the store through the shared lifecycle. There are three results: the
226
+ // external store, which is the controlled mode, and the coordinator refreshes its
227
+ // /context, because the machinery owns /context in both modes; the store that the
228
+ // coordinator kept, when this emission returns to the live identity (a view, then
229
+ // null, then the same view — the fast path could not take this case, because the DOM
230
+ // is gone, and the coordinator refreshes /context in place, because the context can
231
+ // move during the gap); or a new store of this view, with the values of the composed
223
232
  // state.
224
233
  const resolution = this.storeLifecycle.resolve(this.actor, view, this.options.store);
225
234
  this.lastViewKey = view.viewKey;
226
- // Kept unguarded for the slice-only fast path's refresh.
235
+ // The code keeps the store without a guard, for the refresh of the fast path of a slice.
227
236
  this.currentStore = resolution.store;
228
237
  try {
229
238
  this.renderView(view, resolution.guardedStore);
@@ -234,10 +243,10 @@ export class PlayRenderer {
234
243
  }
235
244
  }
236
245
  /**
237
- * A failed rebuild must not leave the fast-path guard armed on a dead tree
238
- * (the container was already cleared): reset the view identity so the next
239
- * emission same viewKey included retries a full render instead of
240
- * patching a store nothing displays.
246
+ * A rebuild that fails must not leave the guard of the fast path armed on a dead
247
+ * tree, because the container is empty already. Therefore this code resets the view
248
+ * identity. The next emission, also one with the same viewKey, then makes a
249
+ * complete render again. It does not patch a store that nothing shows.
241
250
  */
242
251
  resetFailedRebuild() {
243
252
  const failedUnsub = this.storeUnsubscribe;
@@ -248,30 +257,32 @@ export class PlayRenderer {
248
257
  this.storeLifecycle.reset();
249
258
  }
250
259
  /**
251
- * The throw-capable tail of a full rebuild see render()'s catch.
260
+ * The tail of a complete rebuild, which can throw. See the catch block of render().
252
261
  *
253
- * @param guardedStore - Everything the spec can write through ($bindState,
254
- * setState, chained set) gets the GUARDED store: /context is read-only to
255
- * the spec machine context changes only through events.
262
+ * @param guardedStore - Everything that the spec can write through, which includes
263
+ * $bindState, setState, and a chained set, receives the GUARDED store: /context is
264
+ * read-only to the spec, because the machine context changes through an event
265
+ * only.
256
266
  */
257
267
  renderView(view, guardedStore) {
258
268
  const send = this.actor.send.bind(this.actor);
259
- // Build a SetState function backed by the xstate store.
260
- // Called lazily at action-invocation time (not at handlers() call time)
261
- // so actions always see the latest store state.
269
+ // Build a SetState function on the xstate store.
270
+ // The code calls it late, at the moment of an action, and not at the moment of the
271
+ // handlers() call. Therefore each action sees the newest state of the store.
262
272
  const setState = (updater) => {
263
273
  const prev = guardedStore.getSnapshot();
264
274
  const next = updater(prev);
265
- // store.update() is called with a full state snapshot (not a patch map).
266
- // This is compatible with createStoreAdapter/createStateStore where update()
267
- // performs a shallow merge of the provided top-level keys, effectively
268
- // replacing the entire state model. Do not change this to a path-keyed
269
- // patch unless the StateStore contract is updated to match.
270
- // The guarded store lets the untouched context key of this read-modify-
271
- // write round-trip pass as a no-op; a genuine /context mutation throws.
275
+ // The code calls store.update() with a complete snapshot of the state, and not with
276
+ // a map of a patch. This works with createStoreAdapter and with createStateStore,
277
+ // where update() merges the given top-level keys in a shallow way, and therefore
278
+ // replaces the complete model of the state. Change this call to a patch with a path
279
+ // as its key only after a change of the StateStore contract.
280
+ // The store with the guard lets the context key of this read-modify-write round trip
281
+ // pass, because the code touches that key not. A real mutation of /context
282
+ // throws.
272
283
  guardedStore.update(next);
273
284
  };
274
- // Resolve handlers from registryResult (wires setState/getState from store).
285
+ // Resolve the handlers from registryResult. This connects setState and getState of the store.
275
286
  const handlers = this.options.registryResult
276
287
  ? this.options.registryResult.handlers(() => setState, () => guardedStore.getSnapshot())
277
288
  : {};
@@ -282,28 +293,29 @@ export class PlayRenderer {
282
293
  const navigate = this.options.navigate;
283
294
  const onConfirm = this.options.onConfirm;
284
295
  const onRenderError = this.options.onRenderError;
285
- // ── Watch lifecycle ─────────────────────────────────────────────────
286
- // Watch subscriptions follow element MOUNTS, managed by the incremental
287
- // renderer's per-instance registry: elements mounted on the initial
288
- // render register then, and elements that only appear later (visibility
289
- // flipping on, repeat items being appended) register at that moment with
290
- // the same skip-on-mount baseline semantics. Subscriptions are released
291
- // when their element unmounts (visibility off, repeat item removed), on
292
- // view change (top of this method), or on disconnect().
296
+ // ── The lifecycle of a watch ─────────────────────────────────────────────
297
+ // A watch subscription follows the MOUNT of an element, and the registry of each
298
+ // instance in the incremental renderer manages it: an element of the first render
299
+ // registers then, and an element that appears later, from a visibility that becomes
300
+ // true or from a repeat item that the code appends, registers at that moment, with
301
+ // the same skip-on-mount baseline. The renderer releases a subscription when its
302
+ // element unmounts, from a visibility that becomes false or from a repeat item that
303
+ // the code removes. It also releases each subscription on a view change, at the top of
304
+ // this method, and on a disconnect().
293
305
  //
294
- // Stable elements are NOT rewired per-rerender: the update subscription
295
- // below is registered with the store before renderSpec's watch
296
- // subscriptions, and @xstate/store notifies in insertion order. If
297
- // in-place re-renders tore watchers down and recreated them, the old
298
- // watchers would die queued-but-unfired and the new ones would baseline
299
- // against the already-updated snapshot watch actions would never
300
- // fire. The registry therefore preserves the ORIGINAL subscription
301
- // (baseline and notification position intact) whenever an instance is
302
- // merely re-rendered, and only registers genuinely new mounts.
306
+ // A stable element does NOT receive a new watch on each rerender. The code registers
307
+ // the update subscription below with the store before the watch subscriptions of
308
+ // renderSpec, and @xstate/store notifies in the order of the insertion. If a render
309
+ // in place removed the watchers and made them again, each old watcher would die in
310
+ // the queue, before it fires, and each new watcher would take the snapshot after the
311
+ // update as its baseline. A watch action would then fire never. Therefore the registry
312
+ // keeps the ORIGINAL subscription, with its baseline and its position in the
313
+ // notification, whenever the code only renders an instance again. It registers a
314
+ // real new mount only.
303
315
  //
304
- // Every registered cleanup is idempotent and also collected in
305
- // watchCleanups, so calling it again here after the incremental
306
- // renderer already released it is safe.
316
+ // Each registered cleanup is idempotent, and the Set watchCleanups also holds it.
317
+ // Therefore a second call here, after the incremental renderer released it already, is
318
+ // safe.
307
319
  const renderOptions = {
308
320
  send,
309
321
  handlers,
@@ -312,11 +324,11 @@ export class PlayRenderer {
312
324
  ...(directives !== undefined ? { directives } : {}),
313
325
  ...(loading !== undefined ? { loading } : {}),
314
326
  onWatchSetup: (cleanup) => {
315
- // Wrap so that invoking the cleanup from disconnect()/view change
316
- // here, OR from the incremental renderer when the owning element
317
- // unmounts also drops it from the Set. Returned so the incremental
318
- // renderer registers THIS wrapper and calls it on release, keeping
319
- // the Set in step with live subscriptions.
327
+ // Wrap each cleanup. A call of the wrapper, from the disconnect() here or from the
328
+ // view change here, OR from the incremental renderer when the element of the cleanup
329
+ // unmounts, also removes the cleanup from the Set. The code returns the wrapper.
330
+ // Therefore the incremental renderer registers THIS wrapper and calls it on a
331
+ // release, and the Set stays in step with the live subscriptions.
320
332
  const entry = () => {
321
333
  this.watchCleanups.delete(entry);
322
334
  cleanup();
@@ -328,20 +340,20 @@ export class PlayRenderer {
328
340
  ...(navigate !== undefined ? { navigate } : {}),
329
341
  ...(onConfirm !== undefined ? { onConfirm } : {}),
330
342
  };
331
- // ── Incremental updates ─────────────────────────────────────────────
332
- // Store updates no longer rebuild the whole tree: the incremental
333
- // renderer diffs the previous vs next snapshot on each element's
334
- // tracked $state paths and re-renders only the affected elements in
335
- // place. Elements without state bindings keep their DOM node identity
336
- // (focus, selection, scroll survive unrelated updates). View
337
- // transitions still perform a full rebuild — this method runs anew.
343
+ // ── The incremental updates ─────────────────────────────────────────────
344
+ // A store update rebuilds the complete tree no longer: the incremental renderer
345
+ // compares the previous snapshot and the next snapshot on the tracked $state paths of
346
+ // each element, and it renders the elements of the change again, in place. An element
347
+ // without a state binding keeps the identity of its DOM node. Therefore the focus, the
348
+ // selection, and the scroll position survive an update of another element. A view
349
+ // transition still rebuilds everything, because this method runs again.
338
350
  const incremental = createIncrementalRenderer(view, guardedStore, this.registry, this.container, renderOptions);
339
- // subscribe passes through the guard untouched (identical function
340
- // reference) only set/update are wrapped.
351
+ // subscribe passes through the guard without a change, and it keeps the same function
352
+ // reference. The guard wraps set and update only.
341
353
  this.storeUnsubscribe = guardedStore.subscribe(() => {
342
- // Guard: skip if PlayRenderer has been disconnected.
343
- // Handles the edge case where a StateStore implementation fires its
344
- // subscribed callbacks synchronously within its own unsubscribe() call.
354
+ // The guard: stop when a caller disconnected the PlayRenderer.
355
+ // This handles the case of a StateStore implementation that fires its subscribed
356
+ // callbacks synchronously inside its own unsubscribe() call.
345
357
  if (!this.alive)
346
358
  return;
347
359
  incremental.update();
@@ -1 +1 @@
1
- {"version":3,"file":"PlayRenderer.js","sourceRoot":"","sources":["../src/PlayRenderer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PlayRenderer.js","sourceRoot":"","sources":["../src/PlayRenderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAEtD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAIxF,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAKvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,MAAM,OAAO,YAAY;IA2DN;IACA;IACA;IACA;IA7DV,OAAO,GAAwB,IAAI,CAAC;IACpC,gBAAgB,GAAwB,IAAI,CAAC;IACrD;;;;;;;OAOG;IACK,aAAa,GAAG,IAAI,GAAG,EAAc,CAAC;IAC9C;;;;;;;;;;OAUG;IACK,WAAW,GAAuB,SAAS,CAAC;IAC5C,YAAY,GAAsB,IAAI,CAAC;IAC/C;;;;;;;OAOG;IACc,cAAc,GAAuB,wBAAwB,CAAC,CAAC,IAAI,EAAE,EAAE,CACvF,qBAAqB,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CACjD,CAAC;IACF;;;;;OAKG;IACK,KAAK,GAAG,IAAI,CAAC;IAErB;;;;;;;;;;;;;OAaG;IACH,YACkB,SAAsB,EACtB,KAA8C,EAC9C,QAAqB,EACrB,UAA0B,EAAE;QAH5B,cAAS,GAAT,SAAS,CAAa;QACtB,UAAK,GAAL,KAAK,CAAyC;QAC9C,aAAQ,GAAR,QAAQ,CAAa;QACrB,YAAO,GAAP,OAAO,CAAqB;IAC3C,CAAC;IAEJ;;;;;;;;OAQG;IACH,OAAO;QACN,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI;YAAE,IAAI,CAAC,UAAU,EAAE,CAAC;QAC7C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC;QAC1C,IAAI,CAAC,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IACjF,CAAC;IAED;;OAEG;IACH,UAAU;QACT,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,oFAAoF;QACpF,2BAA2B;QAC3B,kFAAkF;QAClF,oFAAoF;QACpF,iFAAiF;QACjF,sDAAsD;QACtD,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC;QACzC,MAAM,aAAa,GAAG,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC;QAC9C,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC7B,IAAI,CAAC,aAAa,GAAG,IAAI,GAAG,EAAE,CAAC;QAC/B,kFAAkF;QAClF,uDAAuD;QACvD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,UAAU,EAAE,EAAE,CAAC;QACf,KAAK,MAAM,OAAO,IAAI,aAAa;YAAE,OAAO,EAAE,CAAC;QAC/C,IAAI,CAAC,SAAS,CAAC,eAAe,EAAE,CAAC;QACjC,iFAAiF;QACjF,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;QAC7B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;IAC7B,CAAC;IAED;;;;;;OAMG;IACH,IAAI,iBAAiB;QACpB,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;IAChC,CAAC;IAEO,MAAM,CAAC,IAAqB;QACnC,2EAA2E;QAC3E,mFAAmF;QACnF,sFAAsF;QACtF,qFAAqF;QACrF,iFAAiF;QACjF,+EAA+E;QAC/E,+DAA+D;QAC/D,oFAAoF;QACpF,+EAA+E;QAC/E,sFAAsF;QACtF,4EAA4E;QAC5E,IACC,IAAI,KAAK,IAAI;YACb,IAAI,CAAC,OAAO,KAAK,SAAS;YAC1B,IAAI,CAAC,WAAW,KAAK,IAAI,CAAC,OAAO;YACjC,IAAI,CAAC,YAAY,KAAK,IAAI;YAC1B,IAAI,CAAC,gBAAgB,KAAK,IAAI,EAC7B,CAAC;YACF,qBAAqB,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;YAC/C,OAAO;QACR,CAAC;QAED,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,gFAAgF;QAChF,mFAAmF;QACnF,oFAAoF;QACpF,gCAAgC;QAChC,yDAAyD;QACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,CAAC;QACvC,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC7B,QAAQ,EAAE,EAAE,CAAC;QAEb,uEAAuE;QACvE,sFAAsF;QACtF,iFAAiF;QACjF,iFAAiF;QACjF,MAAM;QACN,MAAM,iBAAiB,GAAG,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC;QAClD,IAAI,CAAC,aAAa,GAAG,IAAI,GAAG,EAAE,CAAC;QAC/B,KAAK,MAAM,OAAO,IAAI,iBAAiB;YAAE,OAAO,EAAE,CAAC;QAEnD,IAAI,CAAC,SAAS,CAAC,eAAe,EAAE,CAAC;QACjC,mFAAmF;QACnF,iFAAiF;QACjF,0DAA0D;QAC1D,IAAI,CAAC,IAAI;YAAE,OAAO;QAElB,+EAA+E;QAC/E,kFAAkF;QAClF,kFAAkF;QAClF,kFAAkF;QAClF,qFAAqF;QACrF,oFAAoF;QACpF,qFAAqF;QACrF,SAAS;QACT,MAAM,UAAU,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACrF,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC;QAChC,yFAAyF;QACzF,IAAI,CAAC,YAAY,GAAG,UAAU,CAAC,KAAK,CAAC;QAErC,IAAI,CAAC;YACJ,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC;QAChD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC1B,MAAM,KAAK,CAAC;QACb,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACK,kBAAkB;QACzB,MAAM,WAAW,GAAG,IAAI,CAAC,gBAAgB,CAAC;QAC1C,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC7B,WAAW,EAAE,EAAE,CAAC;QAChB,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;QAC7B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;IAC7B,CAAC;IAED;;;;;;;OAOG;IACK,UAAU,CAAC,IAAc,EAAE,YAAwB;QAC1D,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAE9C,iDAAiD;QACjD,mFAAmF;QACnF,6EAA6E;QAC7E,MAAM,QAAQ,GAAa,CAAC,OAAO,EAAE,EAAE;YACtC,MAAM,IAAI,GAAG,YAAY,CAAC,WAAW,EAAE,CAAC;YACxC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;YAC3B,oFAAoF;YACpF,kFAAkF;YAClF,iFAAiF;YACjF,oFAAoF;YACpF,6DAA6D;YAC7D,qFAAqF;YACrF,2EAA2E;YAC3E,UAAU;YACV,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC,CAAC;QAEF,8FAA8F;QAC9F,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc;YAC3C,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,QAAQ,CACpC,GAAG,EAAE,CAAC,QAAQ,EACd,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,CAChC;YACF,CAAC,CAAC,EAAE,CAAC;QAEN,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;QAErC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;QACzC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;QAC3C,MAAM,mBAAmB,GAAG,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC;QAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;QACvC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;QACzC,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC;QAEjD,4EAA4E;QAC5E,iFAAiF;QACjF,kFAAkF;QAClF,oFAAoF;QACpF,mFAAmF;QACnF,iFAAiF;QACjF,oFAAoF;QACpF,uFAAuF;QACvF,sCAAsC;QACtC,EAAE;QACF,qFAAqF;QACrF,iFAAiF;QACjF,oFAAoF;QACpF,mFAAmF;QACnF,qFAAqF;QACrF,uFAAuF;QACvF,6EAA6E;QAC7E,iFAAiF;QACjF,uBAAuB;QACvB,EAAE;QACF,kFAAkF;QAClF,uFAAuF;QACvF,QAAQ;QACR,MAAM,aAAa,GAAsB;YACxC,IAAI;YACJ,QAAQ;YACR,GAAG,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzD,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjD,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACnD,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7C,YAAY,EAAE,CAAC,OAAmB,EAAgB,EAAE;gBACnD,mFAAmF;gBACnF,qFAAqF;gBACrF,iFAAiF;gBACjF,8EAA8E;gBAC9E,kEAAkE;gBAClE,MAAM,KAAK,GAAG,GAAS,EAAE;oBACxB,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;oBACjC,OAAO,EAAE,CAAC;gBACX,CAAC,CAAC;gBACF,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBAC9B,OAAO,KAAK,CAAC;YACd,CAAC;YACD,GAAG,CAAC,mBAAmB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACrE,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/C,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACjD,CAAC;QAEF,2EAA2E;QAC3E,gFAAgF;QAChF,sFAAsF;QACtF,sFAAsF;QACtF,uFAAuF;QACvF,kFAAkF;QAClF,wEAAwE;QACxE,MAAM,WAAW,GAAG,yBAAyB,CAC5C,IAAI,EACJ,YAAY,EACZ,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,SAAS,EACd,aAAa,CACb,CAAC;QAEF,sFAAsF;QACtF,kDAAkD;QAClD,IAAI,CAAC,gBAAgB,GAAG,YAAY,CAAC,SAAS,CAAC,GAAG,EAAE;YACnD,+DAA+D;YAC/D,iFAAiF;YACjF,6DAA6D;YAC7D,IAAI,CAAC,IAAI,CAAC,KAAK;gBAAE,OAAO;YACxB,WAAW,CAAC,MAAM,EAAE,CAAC;QACtB,CAAC,CAAC,CAAC;QACH,WAAW,CAAC,MAAM,EAAE,CAAC;IACtB,CAAC;CACD"}