@xmachines/play-dom 1.0.0-beta.53 → 1.0.0-beta.55
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/PlayRenderer.d.ts +16 -0
- package/dist/PlayRenderer.d.ts.map +1 -1
- package/dist/PlayRenderer.js +82 -41
- package/dist/PlayRenderer.js.map +1 -1
- package/dist/create-play-ui.d.ts.map +1 -1
- package/dist/create-play-ui.js +2 -1
- package/dist/create-play-ui.js.map +1 -1
- package/dist/errors.d.ts +2 -2
- package/dist/errors.js +4 -4
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/json-render/incremental.d.ts +102 -0
- package/dist/json-render/incremental.d.ts.map +1 -0
- package/dist/json-render/incremental.js +830 -0
- package/dist/json-render/incremental.js.map +1 -0
- package/dist/json-render/index.d.ts +2 -1
- package/dist/json-render/index.d.ts.map +1 -1
- package/dist/json-render/index.js.map +1 -1
- package/dist/json-render/renderer.d.ts +156 -41
- package/dist/json-render/renderer.d.ts.map +1 -1
- package/dist/json-render/renderer.js +152 -223
- package/dist/json-render/renderer.js.map +1 -1
- package/dist/json-render/types.d.ts +49 -1
- package/dist/json-render/types.d.ts.map +1 -1
- package/dist/json-render/types.js +56 -20
- package/dist/json-render/types.js.map +1 -1
- package/package.json +11 -8
package/dist/PlayRenderer.d.ts
CHANGED
|
@@ -61,6 +61,14 @@ export declare class PlayRenderer {
|
|
|
61
61
|
private readonly options;
|
|
62
62
|
private unwatch;
|
|
63
63
|
private storeUnsubscribe;
|
|
64
|
+
/**
|
|
65
|
+
* Live watch-subscription cleanups. A `Set` (not an array) so that each
|
|
66
|
+
* registered cleanup can delete ITSELF on invocation: the incremental
|
|
67
|
+
* renderer releases a watcher when its element unmounts, and the registered
|
|
68
|
+
* wrapper is what it invokes — so the Set shrinks in lock-step with live
|
|
69
|
+
* subscriptions instead of accumulating one spent closure per historical
|
|
70
|
+
* mount over a long-lived view.
|
|
71
|
+
*/
|
|
64
72
|
private watchCleanups;
|
|
65
73
|
/**
|
|
66
74
|
* Set to `false` in `disconnect()` before calling `storeUnsub()`.
|
|
@@ -98,6 +106,14 @@ export declare class PlayRenderer {
|
|
|
98
106
|
* Stop watching and clear the container.
|
|
99
107
|
*/
|
|
100
108
|
disconnect(): void;
|
|
109
|
+
/**
|
|
110
|
+
* Number of live watch-subscription cleanups currently retained.
|
|
111
|
+
*
|
|
112
|
+
* @internal Test-only accessor for asserting that the watch-cleanup
|
|
113
|
+
* collection tracks live registrations (no per-mount leak). Not part of the
|
|
114
|
+
* public API and may change without notice.
|
|
115
|
+
*/
|
|
116
|
+
get watchCleanupCount(): number;
|
|
101
117
|
private render;
|
|
102
118
|
}
|
|
103
119
|
//# sourceMappingURL=PlayRenderer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlayRenderer.d.ts","sourceRoot":"","sources":["../src/PlayRenderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"PlayRenderer.d.ts","sourceRoot":"","sources":["../src/PlayRenderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAY,MAAM,uBAAuB,CAAC;AAC/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAG5C,OAAO,KAAK,EAAE,WAAW,EAAY,MAAM,wBAAwB,CAAC;AACpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,qBAAa,YAAY;IAmCvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO;IArCzB,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,gBAAgB,CAA6B;IACrD;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa,CAAyB;IAC9C;;;;;;OAMG;IACH,OAAO,CAAC,KAAK,CAAQ;IAErB;;;;;;;;;;;;OAYG;gBAEe,SAAS,EAAE,WAAW,EACtB,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,GAAG,QAAQ,EAC9C,QAAQ,EAAE,WAAW,EACrB,OAAO,GAAE,cAAmB;IAG9C;;;;;;;;OAQG;IACH,OAAO,IAAI,IAAI;IAMf;;OAEG;IACH,UAAU,IAAI,IAAI;IAmBlB;;;;;;OAMG;IACH,IAAI,iBAAiB,IAAI,MAAM,CAE9B;IAED,OAAO,CAAC,MAAM;CAqId"}
|
package/dist/PlayRenderer.js
CHANGED
|
@@ -11,29 +11,8 @@
|
|
|
11
11
|
import { watchSignal } from "@xmachines/play-signals";
|
|
12
12
|
import { createAtom } from "@xstate/store";
|
|
13
13
|
import { xstateStoreStateStore } from "@json-render/xstate";
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
* Safely coerce a spec's `state` field to a plain object for `createAtom`.
|
|
17
|
-
*
|
|
18
|
-
* `spec.state` is typed as `unknown` in `PlaySpec`. At runtime it can be
|
|
19
|
-
* `null`, `undefined`, a primitive, or a plain object depending on what the
|
|
20
|
-
* machine author put in the view spec. `createAtom` requires a plain object as
|
|
21
|
-
* its initial value — anything else produces a broken store at runtime.
|
|
22
|
-
*
|
|
23
|
-
* Only plain objects (prototype is `Object.prototype` or `null`) are accepted.
|
|
24
|
-
* Class instances and built-in objects (Date, Map, Set, etc.) are rejected and
|
|
25
|
-
* fall back to `{}` — this prevents silent broken-store bugs at runtime.
|
|
26
|
-
* Arrays are also rejected (they have `Array.prototype`).
|
|
27
|
-
*/
|
|
28
|
-
function toAtomState(state) {
|
|
29
|
-
if (state !== null && typeof state === "object" && !Array.isArray(state)) {
|
|
30
|
-
const proto = Object.getPrototypeOf(state);
|
|
31
|
-
if (proto === Object.prototype || proto === null) {
|
|
32
|
-
return state;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return {};
|
|
36
|
-
}
|
|
14
|
+
import { toAtomState } from "@xmachines/play-actor";
|
|
15
|
+
import { createIncrementalRenderer } from "./json-render/incremental.js";
|
|
37
16
|
/**
|
|
38
17
|
* PlayRenderer connects an actor's `currentView` signal to the DOM renderer.
|
|
39
18
|
*
|
|
@@ -83,7 +62,15 @@ export class PlayRenderer {
|
|
|
83
62
|
options;
|
|
84
63
|
unwatch = null;
|
|
85
64
|
storeUnsubscribe = null;
|
|
86
|
-
|
|
65
|
+
/**
|
|
66
|
+
* Live watch-subscription cleanups. A `Set` (not an array) so that each
|
|
67
|
+
* registered cleanup can delete ITSELF on invocation: the incremental
|
|
68
|
+
* renderer releases a watcher when its element unmounts, and the registered
|
|
69
|
+
* wrapper is what it invokes — so the Set shrinks in lock-step with live
|
|
70
|
+
* subscriptions instead of accumulating one spent closure per historical
|
|
71
|
+
* mount over a long-lived view.
|
|
72
|
+
*/
|
|
73
|
+
watchCleanups = new Set();
|
|
87
74
|
/**
|
|
88
75
|
* Set to `false` in `disconnect()` before calling `storeUnsub()`.
|
|
89
76
|
* The `rerender` closure checks this flag at entry so that any synchronous
|
|
@@ -139,7 +126,7 @@ export class PlayRenderer {
|
|
|
139
126
|
const storeUnsub = this.storeUnsubscribe;
|
|
140
127
|
const watchCleanups = [...this.watchCleanups];
|
|
141
128
|
this.storeUnsubscribe = null;
|
|
142
|
-
this.watchCleanups =
|
|
129
|
+
this.watchCleanups = new Set();
|
|
143
130
|
// Set alive = false before calling storeUnsub() so that any synchronous
|
|
144
131
|
// rerender callback triggered within unsubscribe() exits immediately.
|
|
145
132
|
this.alive = false;
|
|
@@ -148,6 +135,16 @@ export class PlayRenderer {
|
|
|
148
135
|
cleanup();
|
|
149
136
|
this.container.replaceChildren();
|
|
150
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* Number of live watch-subscription cleanups currently retained.
|
|
140
|
+
*
|
|
141
|
+
* @internal Test-only accessor for asserting that the watch-cleanup
|
|
142
|
+
* collection tracks live registrations (no per-mount leak). Not part of the
|
|
143
|
+
* public API and may change without notice.
|
|
144
|
+
*/
|
|
145
|
+
get watchCleanupCount() {
|
|
146
|
+
return this.watchCleanups.size;
|
|
147
|
+
}
|
|
151
148
|
render(view) {
|
|
152
149
|
this.alive = true;
|
|
153
150
|
// Capture and clear before calling — prevents the synchronous callback fired
|
|
@@ -161,8 +158,8 @@ export class PlayRenderer {
|
|
|
161
158
|
// Without this, watch subscriptions from the prior view remain active
|
|
162
159
|
// between a view transition and the first store update in the new view,
|
|
163
160
|
// holding references to stale DOM elements and preventing GC.
|
|
164
|
-
const prevWatchCleanups = this.watchCleanups;
|
|
165
|
-
this.watchCleanups =
|
|
161
|
+
const prevWatchCleanups = [...this.watchCleanups];
|
|
162
|
+
this.watchCleanups = new Set();
|
|
166
163
|
for (const cleanup of prevWatchCleanups)
|
|
167
164
|
cleanup();
|
|
168
165
|
this.container.replaceChildren();
|
|
@@ -199,26 +196,70 @@ export class PlayRenderer {
|
|
|
199
196
|
const functions = this.options.functions;
|
|
200
197
|
const validationFunctions = this.options.validationFunctions;
|
|
201
198
|
const navigate = this.options.navigate;
|
|
199
|
+
const onConfirm = this.options.onConfirm;
|
|
202
200
|
const onRenderError = this.options.onRenderError;
|
|
203
|
-
|
|
201
|
+
// ── Watch lifecycle ─────────────────────────────────────────────────
|
|
202
|
+
// Watch subscriptions follow element MOUNTS, managed by the incremental
|
|
203
|
+
// renderer's per-instance registry: elements mounted on the initial
|
|
204
|
+
// render register then, and elements that only appear later (visibility
|
|
205
|
+
// flipping on, repeat items being appended) register at that moment with
|
|
206
|
+
// the same skip-on-mount baseline semantics. Subscriptions are released
|
|
207
|
+
// when their element unmounts (visibility off, repeat item removed), on
|
|
208
|
+
// view change (top of this method), or on disconnect().
|
|
209
|
+
//
|
|
210
|
+
// Stable elements are NOT rewired per-rerender: the update subscription
|
|
211
|
+
// below is registered with the store before renderSpec's watch
|
|
212
|
+
// subscriptions, and @xstate/store notifies in insertion order. If
|
|
213
|
+
// in-place re-renders tore watchers down and recreated them, the old
|
|
214
|
+
// watchers would die queued-but-unfired and the new ones would baseline
|
|
215
|
+
// against the already-updated snapshot — watch actions would never
|
|
216
|
+
// fire. The registry therefore preserves the ORIGINAL subscription
|
|
217
|
+
// (baseline and notification position intact) whenever an instance is
|
|
218
|
+
// merely re-rendered, and only registers genuinely new mounts.
|
|
219
|
+
//
|
|
220
|
+
// Every registered cleanup is idempotent and also collected in
|
|
221
|
+
// watchCleanups, so calling it again here after the incremental
|
|
222
|
+
// renderer already released it is safe.
|
|
223
|
+
const renderOptions = {
|
|
224
|
+
send,
|
|
225
|
+
handlers,
|
|
226
|
+
...(onRenderError !== undefined ? { onRenderError } : {}),
|
|
227
|
+
...(functions !== undefined ? { functions } : {}),
|
|
228
|
+
...(loading !== undefined ? { loading } : {}),
|
|
229
|
+
onWatchSetup: (cleanup) => {
|
|
230
|
+
// Wrap so that invoking the cleanup — from disconnect()/view change
|
|
231
|
+
// here, OR from the incremental renderer when the owning element
|
|
232
|
+
// unmounts — also drops it from the Set. Returned so the incremental
|
|
233
|
+
// renderer registers THIS wrapper and calls it on release, keeping
|
|
234
|
+
// the Set in step with live subscriptions.
|
|
235
|
+
const entry = () => {
|
|
236
|
+
this.watchCleanups.delete(entry);
|
|
237
|
+
cleanup();
|
|
238
|
+
};
|
|
239
|
+
this.watchCleanups.add(entry);
|
|
240
|
+
return entry;
|
|
241
|
+
},
|
|
242
|
+
...(validationFunctions !== undefined ? { validationFunctions } : {}),
|
|
243
|
+
...(navigate !== undefined ? { navigate } : {}),
|
|
244
|
+
...(onConfirm !== undefined ? { onConfirm } : {}),
|
|
245
|
+
};
|
|
246
|
+
// ── Incremental updates ─────────────────────────────────────────────
|
|
247
|
+
// Store updates no longer rebuild the whole tree: the incremental
|
|
248
|
+
// renderer diffs the previous vs next snapshot on each element's
|
|
249
|
+
// tracked $state paths and re-renders only the affected elements in
|
|
250
|
+
// place. Elements without state bindings keep their DOM node identity
|
|
251
|
+
// (focus, selection, scroll survive unrelated updates). View
|
|
252
|
+
// transitions still perform a full rebuild — this method runs anew.
|
|
253
|
+
const incremental = createIncrementalRenderer(view, store, this.registry, this.container, renderOptions);
|
|
254
|
+
this.storeUnsubscribe = store.subscribe(() => {
|
|
204
255
|
// Guard: skip if PlayRenderer has been disconnected.
|
|
205
256
|
// Handles the edge case where a StateStore implementation fires its
|
|
206
257
|
// subscribed callbacks synchronously within its own unsubscribe() call.
|
|
207
258
|
if (!this.alive)
|
|
208
259
|
return;
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
this.watchCleanups = [];
|
|
213
|
-
this.container.replaceChildren();
|
|
214
|
-
const node = renderSpec(view, store, this.registry, send, handlers, undefined, onRenderError, functions, loading, (cleanup) => {
|
|
215
|
-
this.watchCleanups.push(cleanup);
|
|
216
|
-
}, validationFunctions, navigate);
|
|
217
|
-
if (node)
|
|
218
|
-
this.container.appendChild(node);
|
|
219
|
-
};
|
|
220
|
-
this.storeUnsubscribe = store.subscribe(rerender);
|
|
221
|
-
rerender();
|
|
260
|
+
incremental.update();
|
|
261
|
+
});
|
|
262
|
+
incremental.render();
|
|
222
263
|
}
|
|
223
264
|
}
|
|
224
265
|
//# sourceMappingURL=PlayRenderer.js.map
|
package/dist/PlayRenderer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlayRenderer.js","sourceRoot":"","sources":["../src/PlayRenderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAEtD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"PlayRenderer.js","sourceRoot":"","sources":["../src/PlayRenderer.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-play-ui.d.ts","sourceRoot":"","sources":["../src/create-play-ui.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC5B;;;;OAIG;IACH,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,OAAO,GAAG,CACrB,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,GAAG,QAAQ,EAC9C,SAAS,EAAE,WAAW,EACtB,OAAO,CAAC,EAAE,YAAY,KAClB,MAAM,IAAI,CAAC;AAEhB;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAC3B,cAAc,EAAE,oBAAoB,EACpC,OAAO,GAAE,mBAAwB,GAC/B,OAAO,
|
|
1
|
+
{"version":3,"file":"create-play-ui.d.ts","sourceRoot":"","sources":["../src/create-play-ui.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC5B;;;;OAIG;IACH,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,OAAO,GAAG,CACrB,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,GAAG,QAAQ,EAC9C,SAAS,EAAE,WAAW,EACtB,OAAO,CAAC,EAAE,YAAY,KAClB,MAAM,IAAI,CAAC;AAEhB;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAC3B,cAAc,EAAE,oBAAoB,EACpC,OAAO,GAAE,mBAAwB,GAC/B,OAAO,CAqCT"}
|
package/dist/create-play-ui.js
CHANGED
|
@@ -49,7 +49,7 @@ import { PlayRenderer } from "./PlayRenderer.js";
|
|
|
49
49
|
* @returns `MountFn`: `(actor, container, mountOptions?) → disconnect`
|
|
50
50
|
*/
|
|
51
51
|
export function createPlayUI(registryResult, options = {}) {
|
|
52
|
-
const { onRenderError, fallback, functions, validationFunctions, navigate } = options;
|
|
52
|
+
const { onRenderError, fallback, functions, validationFunctions, navigate, onConfirm } = options;
|
|
53
53
|
return function mount(actor, container, mountOptions) {
|
|
54
54
|
// All UIProviderOptions (onRenderError, functions, validationFunctions, navigate) are
|
|
55
55
|
// forwarded directly through PlayDomOptions → PlayRenderer → renderSpec → DomRenderContext.
|
|
@@ -60,6 +60,7 @@ export function createPlayUI(registryResult, options = {}) {
|
|
|
60
60
|
...(functions !== undefined && { functions }),
|
|
61
61
|
...(validationFunctions !== undefined && { validationFunctions }),
|
|
62
62
|
...(navigate !== undefined && { navigate }),
|
|
63
|
+
...(onConfirm !== undefined && { onConfirm }),
|
|
63
64
|
...(onRenderError !== undefined && { onRenderError }),
|
|
64
65
|
};
|
|
65
66
|
const renderer = new PlayRenderer(container, actor, registryResult.registry, rendererOptions);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-play-ui.js","sourceRoot":"","sources":["../src/create-play-ui.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAKH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAsCjD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,YAAY,CAC3B,cAAoC,EACpC,UAA+B,EAAE;IAEjC,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,mBAAmB,EAAE,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"create-play-ui.js","sourceRoot":"","sources":["../src/create-play-ui.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAKH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAsCjD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,YAAY,CAC3B,cAAoC,EACpC,UAA+B,EAAE;IAEjC,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,mBAAmB,EAAE,QAAQ,EAAE,SAAS,EAAE,GACrF,OAAO,CAAC;IAET,OAAO,SAAS,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,YAAY;QACnD,sFAAsF;QACtF,4FAA4F;QAC5F,MAAM,eAAe,GAAG;YACvB,cAAc;YACd,GAAG,CAAC,YAAY,EAAE,KAAK,KAAK,SAAS,IAAI,EAAE,KAAK,EAAE,YAAY,CAAC,KAAK,EAAE,CAAC;YACvE,GAAG,CAAC,YAAY,EAAE,OAAO,KAAK,SAAS,IAAI,EAAE,OAAO,EAAE,YAAY,CAAC,OAAO,EAAE,CAAC;YAC7E,GAAG,CAAC,SAAS,KAAK,SAAS,IAAI,EAAE,SAAS,EAAE,CAAC;YAC7C,GAAG,CAAC,mBAAmB,KAAK,SAAS,IAAI,EAAE,mBAAmB,EAAE,CAAC;YACjE,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,EAAE,QAAQ,EAAE,CAAC;YAC3C,GAAG,CAAC,SAAS,KAAK,SAAS,IAAI,EAAE,SAAS,EAAE,CAAC;YAC7C,GAAG,CAAC,aAAa,KAAK,SAAS,IAAI,EAAE,aAAa,EAAE,CAAC;SACrD,CAAC;QAEF,MAAM,QAAQ,GAAG,IAAI,YAAY,CAChC,SAAS,EACT,KAAK,EACL,cAAc,CAAC,QAAQ,EACvB,eAAe,CACf,CAAC;QACF,QAAQ,CAAC,OAAO,EAAE,CAAC;QAEnB,kDAAkD;QAClD,gFAAgF;QAChF,kDAAkD;QAClD,IAAI,QAAQ,IAAI,IAAI,IAAI,SAAS,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3D,SAAS,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC;QAED,OAAO,SAAS,UAAU;YACzB,QAAQ,CAAC,UAAU,EAAE,CAAC;QACvB,CAAC,CAAC;IACH,CAAC,CAAC;AACH,CAAC"}
|
package/dist/errors.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { PlayError } from "@xmachines/play";
|
|
|
6
6
|
* to the renderer. The `componentName` that was being looked up is encoded in
|
|
7
7
|
* the error message.
|
|
8
8
|
*
|
|
9
|
-
* **Error code:** `
|
|
9
|
+
* **Error code:** `PLAY_DOM_MISSING_CATALOG`
|
|
10
10
|
*
|
|
11
11
|
* @example
|
|
12
12
|
* ```typescript
|
|
@@ -28,7 +28,7 @@ export declare class MissingCatalogError extends PlayError {
|
|
|
28
28
|
* This is a programmer error — either the machine's `meta.view.component` name is
|
|
29
29
|
* misspelled, or the component was not registered in the catalog passed to the renderer.
|
|
30
30
|
*
|
|
31
|
-
* **Error code:** `
|
|
31
|
+
* **Error code:** `PLAY_DOM_MISSING_COMPONENT`
|
|
32
32
|
*
|
|
33
33
|
* @example
|
|
34
34
|
* ```typescript
|
package/dist/errors.js
CHANGED
|
@@ -6,7 +6,7 @@ import { PlayError } from "@xmachines/play";
|
|
|
6
6
|
* to the renderer. The `componentName` that was being looked up is encoded in
|
|
7
7
|
* the error message.
|
|
8
8
|
*
|
|
9
|
-
* **Error code:** `
|
|
9
|
+
* **Error code:** `PLAY_DOM_MISSING_CATALOG`
|
|
10
10
|
*
|
|
11
11
|
* @example
|
|
12
12
|
* ```typescript
|
|
@@ -20,7 +20,7 @@ import { PlayError } from "@xmachines/play";
|
|
|
20
20
|
*/
|
|
21
21
|
export class MissingCatalogError extends PlayError {
|
|
22
22
|
constructor(componentName, catalogValue) {
|
|
23
|
-
super("PlayRenderer", "
|
|
23
|
+
super("PlayRenderer", "PLAY_DOM_MISSING_CATALOG", `Components catalog is ${catalogValue === null ? "null" : "undefined"}. Cannot render component "${componentName}".`);
|
|
24
24
|
this.name = "MissingCatalogError";
|
|
25
25
|
}
|
|
26
26
|
}
|
|
@@ -31,7 +31,7 @@ export class MissingCatalogError extends PlayError {
|
|
|
31
31
|
* This is a programmer error — either the machine's `meta.view.component` name is
|
|
32
32
|
* misspelled, or the component was not registered in the catalog passed to the renderer.
|
|
33
33
|
*
|
|
34
|
-
* **Error code:** `
|
|
34
|
+
* **Error code:** `PLAY_DOM_MISSING_COMPONENT`
|
|
35
35
|
*
|
|
36
36
|
* @example
|
|
37
37
|
* ```typescript
|
|
@@ -45,7 +45,7 @@ export class MissingCatalogError extends PlayError {
|
|
|
45
45
|
*/
|
|
46
46
|
export class MissingComponentError extends PlayError {
|
|
47
47
|
constructor(componentName, availableComponents) {
|
|
48
|
-
super("PlayRenderer", "
|
|
48
|
+
super("PlayRenderer", "PLAY_DOM_MISSING_COMPONENT", `Component "${componentName}" not found in catalog. Available components: ${availableComponents.join(", ")}`);
|
|
49
49
|
this.name = "MissingComponentError";
|
|
50
50
|
}
|
|
51
51
|
}
|
package/dist/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,OAAO,mBAAoB,SAAQ,SAAS;IACjD,YAAY,aAAqB,EAAE,YAA8B;QAChE,KAAK,CACJ,cAAc,EACd
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,OAAO,mBAAoB,SAAQ,SAAS;IACjD,YAAY,aAAqB,EAAE,YAA8B;QAChE,KAAK,CACJ,cAAc,EACd,0BAA0B,EAC1B,yBAAyB,YAAY,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,8BAA8B,aAAa,IAAI,CACpH,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACnC,CAAC;CACD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,OAAO,qBAAsB,SAAQ,SAAS;IACnD,YAAY,aAAqB,EAAE,mBAA6B;QAC/D,KAAK,CACJ,cAAc,EACd,4BAA4B,EAC5B,cAAc,aAAa,iDAAiD,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC5G,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACrC,CAAC;CACD"}
|
package/dist/index.d.ts
CHANGED
|
@@ -31,5 +31,6 @@ export { createPlayUI } from "./create-play-ui.js";
|
|
|
31
31
|
export type { MountFn, MountOptions } from "./create-play-ui.js";
|
|
32
32
|
export type { PlayDomOptions, CreatePlayUIOptions } from "./types.js";
|
|
33
33
|
export { defineRegistry, renderSpec, schema } from "./json-render/index.js";
|
|
34
|
-
export type {
|
|
34
|
+
export type { RenderSpecOptions } from "./json-render/index.js";
|
|
35
|
+
export type { ConfirmHandler, EventHandle, SetState, RenderErrorHandler, UIProviderOptions, CatalogHasActions, BaseComponentProps, DomRenderContext, DomComponentRenderer, ComponentContext, ComponentFn, ComponentRegistry, Actions, ActionFn, DefineRegistryOptions, DefineRegistryResult, DomRegistry, DomSchema, } from "./json-render/index.js";
|
|
35
36
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGjE,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAGtE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC5E,YAAY,EACX,WAAW,EACX,QAAQ,EACR,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,OAAO,EACP,QAAQ,EACR,qBAAqB,EACrB,oBAAoB,EACpB,WAAW,EACX,SAAS,GACT,MAAM,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGjE,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAGtE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC5E,YAAY,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,YAAY,EACX,cAAc,EACd,WAAW,EACX,QAAQ,EACR,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,OAAO,EACP,QAAQ,EACR,qBAAqB,EACrB,oBAAoB,EACpB,WAAW,EACX,SAAS,GACT,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* incremental.ts — Targeted store-driven re-rendering for the DOM renderer.
|
|
3
|
+
*
|
|
4
|
+
* Zero XMachines dependencies. Upstreamable to @json-render/dom.
|
|
5
|
+
*
|
|
6
|
+
* `createIncrementalRenderer` wraps {@link renderSpec} with a per-element
|
|
7
|
+
* dependency registry: while rendering, every element instance is recorded as
|
|
8
|
+
* a {@link RenderUnit} carrying the resolved `$state` paths its props and
|
|
9
|
+
* visibility depend on (a conservative superset extracted statically from the
|
|
10
|
+
* raw spec). On each store update the previous and next snapshots are diffed
|
|
11
|
+
* per tracked path (shallow reference compare via `getByPath`) and ONLY the
|
|
12
|
+
* affected elements are re-rendered in place — untouched siblings and
|
|
13
|
+
* ancestors keep their DOM node identity, focus, selection, and scroll.
|
|
14
|
+
*
|
|
15
|
+
* Granularity rules:
|
|
16
|
+
* - `$state` / `$template` / `$cond` / `$computed` args → the referenced
|
|
17
|
+
* absolute paths are re-render dependencies of the element.
|
|
18
|
+
* - Visibility conditions → their referenced paths are dependencies; while an
|
|
19
|
+
* element is invisible a `Comment` placeholder holds its position so it can
|
|
20
|
+
* be mounted in place when the condition flips.
|
|
21
|
+
* - `repeat` containers → reconciled per index when their array path changes
|
|
22
|
+
* (index-based diffing — the spec has no user-provided item keys):
|
|
23
|
+
* unchanged-reference items keep their DOM nodes untouched, trailing growth
|
|
24
|
+
* appends new item instances in place, trailing shrink removes them, and
|
|
25
|
+
* changed indices re-render through the per-unit diff (see next bullet).
|
|
26
|
+
* Wholesale container re-renders remain as documented fallbacks — see
|
|
27
|
+
* {@link reconcileRepeat}.
|
|
28
|
+
* - `$item` / `$index` / `$bindItem` inside a repeat → attributed to the
|
|
29
|
+
* enclosing item's absolute path (e.g. `"/todos/1"`), so mutating one
|
|
30
|
+
* item's object re-renders only the element instances inside that index.
|
|
31
|
+
* - `$bindState` / `$bindItem` (two-way bindings) → tracked separately: when
|
|
32
|
+
* ONLY bound paths changed and the element currently contains focus, the
|
|
33
|
+
* re-render is skipped. The focused input already displays the value it
|
|
34
|
+
* just wrote to the store, and replacing its node would destroy focus and
|
|
35
|
+
* selection on every keystroke. Unfocused bound elements re-render normally
|
|
36
|
+
* so external writes still propagate.
|
|
37
|
+
* - Elements with no state bindings are never touched by store updates.
|
|
38
|
+
*
|
|
39
|
+
* Fallbacks (correctness over cleverness):
|
|
40
|
+
* - Re-rendering the root element (or any unit whose DOM node is no longer
|
|
41
|
+
* connected, e.g. a component that ignored its children) escalates to the
|
|
42
|
+
* nearest ancestor and ultimately to a full container re-render.
|
|
43
|
+
* - If a store notification delivers a snapshot that is reference-identical
|
|
44
|
+
* to the previous one (in-place mutation cannot be diffed), a full
|
|
45
|
+
* re-render preserves the pre-incremental behavior.
|
|
46
|
+
*
|
|
47
|
+
* `watch` bindings are NOT re-render dependencies — they are managed as a
|
|
48
|
+
* per-element-instance subscription registry: a subscription is created when
|
|
49
|
+
* an instance first MOUNTS (initial render, visibility flipping on, a repeat
|
|
50
|
+
* item being appended) with the skip-on-mount baseline captured at that
|
|
51
|
+
* moment; it is PRESERVED — never rewired — across in-place re-renders of the
|
|
52
|
+
* same instance (so its baseline and store-notification position survive, see
|
|
53
|
+
* PlayRenderer's watch lifecycle notes); and it is RELEASED when the instance
|
|
54
|
+
* unmounts (visibility off, repeat item removed, or the element vanishing
|
|
55
|
+
* from a re-rendered subtree). Each registration's cleanup is idempotent and
|
|
56
|
+
* is also forwarded to `options.onWatchSetup`, so callers may safely invoke
|
|
57
|
+
* it again on teardown (view change / disconnect).
|
|
58
|
+
*
|
|
59
|
+
* @packageDocumentation
|
|
60
|
+
*/
|
|
61
|
+
import type { Spec, StateStore } from "@json-render/core";
|
|
62
|
+
import type { RenderSpecOptions } from "./renderer.js";
|
|
63
|
+
import type { DomRegistry } from "./types.js";
|
|
64
|
+
/**
|
|
65
|
+
* Handle returned by {@link createIncrementalRenderer}.
|
|
66
|
+
*/
|
|
67
|
+
export interface IncrementalDomRenderer {
|
|
68
|
+
/**
|
|
69
|
+
* Full initial render into the container (clears it first). Registers
|
|
70
|
+
* `watch` subscriptions via `options.onWatchSetup` for every mounted
|
|
71
|
+
* element that declares them.
|
|
72
|
+
*/
|
|
73
|
+
render(): void;
|
|
74
|
+
/**
|
|
75
|
+
* Diff the current store snapshot against the previous one and re-render
|
|
76
|
+
* only the affected element instances in place. Elements mounted by the
|
|
77
|
+
* update (visibility flips, appended repeat items) register their `watch`
|
|
78
|
+
* subscriptions; unmounted elements release theirs; instances re-rendered
|
|
79
|
+
* in place keep their original subscriptions (never rewired).
|
|
80
|
+
*/
|
|
81
|
+
update(): void;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Create an incremental DOM renderer for one spec/store/container triple.
|
|
85
|
+
*
|
|
86
|
+
* Call {@link IncrementalDomRenderer.render} once for the initial mount, then
|
|
87
|
+
* {@link IncrementalDomRenderer.update} on every store notification. A view
|
|
88
|
+
* transition should discard the instance and create a fresh one (matching
|
|
89
|
+
* PlayRenderer's full-rebuild-per-view contract).
|
|
90
|
+
*
|
|
91
|
+
* @param spec - The json-render `Spec` for the current view.
|
|
92
|
+
* @param store - Live `StateStore` bound to `spec.state`.
|
|
93
|
+
* @param registry - Map of element type names → `DomComponentRenderer`.
|
|
94
|
+
* @param container - Host element that owns the rendered tree.
|
|
95
|
+
* @param options - Forwarded to {@link renderSpec}. `onWatchSetup` receives
|
|
96
|
+
* one idempotent cleanup per watch registration, over the
|
|
97
|
+
* whole lifetime of the instance (initial mounts AND
|
|
98
|
+
* late mounts) — never a duplicate for an instance that is
|
|
99
|
+
* merely re-rendered in place.
|
|
100
|
+
*/
|
|
101
|
+
export declare function createIncrementalRenderer(spec: Spec, store: StateStore, registry: DomRegistry, container: HTMLElement, options?: RenderSpecOptions): IncrementalDomRenderer;
|
|
102
|
+
//# sourceMappingURL=incremental.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"incremental.d.ts","sourceRoot":"","sources":["../../src/json-render/incremental.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAa,MAAM,mBAAmB,CAAC;AAErE,OAAO,KAAK,EAAE,iBAAiB,EAA8B,MAAM,eAAe,CAAC;AACnF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA6N9C;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACtC;;;;OAIG;IACH,MAAM,IAAI,IAAI,CAAC;IACf;;;;;;OAMG;IACH,MAAM,IAAI,IAAI,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACxC,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,WAAW,EACrB,SAAS,EAAE,WAAW,EACtB,OAAO,GAAE,iBAAsB,GAC7B,sBAAsB,CAgkBxB"}
|