@fundamental-engine/elements 0.9.2 → 0.9.3
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/README.md +12 -3
- package/custom-elements.json +333 -13
- package/dist/field-cell.d.ts +34 -2
- package/dist/field-cell.d.ts.map +1 -1
- package/dist/field-cell.js +75 -7
- package/dist/field-cell.js.map +1 -1
- package/dist/index.d.ts +24 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +95 -23
- package/dist/index.js.map +1 -1
- package/dist/platform-runtime.d.ts.map +1 -1
- package/dist/platform-runtime.js +20 -9
- package/dist/platform-runtime.js.map +1 -1
- package/dist/preregistration-queue.d.ts +31 -0
- package/dist/preregistration-queue.d.ts.map +1 -0
- package/dist/preregistration-queue.js +136 -0
- package/dist/preregistration-queue.js.map +1 -0
- package/package.json +4 -4
package/dist/platform-runtime.js
CHANGED
|
@@ -101,9 +101,9 @@ export function makeFeedbackSink(platform) {
|
|
|
101
101
|
// heatmap density → --field-heatmap-density
|
|
102
102
|
if (ch.heatmapDensity !== undefined)
|
|
103
103
|
platform.feedback.set(el, { '--field-heatmap-density': f3(ch.heatmapDensity) });
|
|
104
|
-
// accretion load → --load
|
|
104
|
+
// accretion load → --load
|
|
105
105
|
if (ch.load !== undefined)
|
|
106
|
-
platform.feedback.set(el, { '--load': f3(ch.load)
|
|
106
|
+
platform.feedback.set(el, { '--load': f3(ch.load) });
|
|
107
107
|
// measured thermodynamics (workover v0.3) → the bare names, mirroring the engine's default
|
|
108
108
|
// sink exactly. These are engine-MEASURED local thermodynamics; the platform's
|
|
109
109
|
// `--field-entropy` / `--field-coherence` pipeline lanes (system-contracts §6) are
|
|
@@ -163,8 +163,19 @@ export function startPlatformRuntime(root) {
|
|
|
163
163
|
for (const [name, fn] of wired)
|
|
164
164
|
doc.removeEventListener(name, fn);
|
|
165
165
|
};
|
|
166
|
+
// Registry teardown shared by both destroy paths: disconnect the VisualBindingRegistry's live
|
|
167
|
+
// MutationObservers (they otherwise keep every observed source alive), then prune + clear the
|
|
168
|
+
// StateRegistry and FeedbackRegistry so removed elements are freed immediately — closing the
|
|
169
|
+
// strong-ref retention window instead of leaning on the platform object being collected.
|
|
170
|
+
const teardownRegistries = () => {
|
|
171
|
+
platform.visuals.setMirroring(false);
|
|
172
|
+
platform.state.prune();
|
|
173
|
+
platform.state.clearAll();
|
|
174
|
+
platform.feedback.prune();
|
|
175
|
+
platform.feedback.clearAll();
|
|
176
|
+
};
|
|
166
177
|
if (typeof window === 'undefined' || typeof requestAnimationFrame === 'undefined') {
|
|
167
|
-
return { platform, attachHandle: () => { }, destroy: unwireShadow };
|
|
178
|
+
return { platform, attachHandle: () => { }, destroy: () => { unwireShadow(); teardownRegistries(); } };
|
|
168
179
|
}
|
|
169
180
|
let raf = 0;
|
|
170
181
|
let handle = null;
|
|
@@ -236,12 +247,12 @@ export function startPlatformRuntime(root) {
|
|
|
236
247
|
handle = null;
|
|
237
248
|
document.removeEventListener('visibilitychange', onVisibility);
|
|
238
249
|
unwireShadow();
|
|
239
|
-
// Registry teardown: the VisualBindingRegistry holds live MutationObservers (one per
|
|
240
|
-
//
|
|
241
|
-
//
|
|
242
|
-
// and
|
|
243
|
-
//
|
|
244
|
-
|
|
250
|
+
// Registry teardown: the VisualBindingRegistry holds live MutationObservers (one per mirrored
|
|
251
|
+
// source) that the browser keeps firing — and keeps the registry, plus every observed element,
|
|
252
|
+
// alive long after this runtime is gone. Beyond disconnecting those, explicitly prune + clear
|
|
253
|
+
// the StateRegistry and FeedbackRegistry so every strong Element ref they hold is released now,
|
|
254
|
+
// closing the retention window rather than waiting for the platform object to be collected.
|
|
255
|
+
teardownRegistries();
|
|
245
256
|
},
|
|
246
257
|
};
|
|
247
258
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform-runtime.js","sourceRoot":"","sources":["../src/platform-runtime.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"platform-runtime.js","sourceRoot":"","sources":["../src/platform-runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Install the capturing document listeners — idempotent, SSR-guarded. Called from the custom
|
|
3
|
+
* element's constructor so it runs on the client before the element upgrades its peers, and never on
|
|
4
|
+
* the server (no `document`). Capturing (`{ capture: true }`) so the queue sees the event on the way
|
|
5
|
+
* down, independent of any later-added bubble-phase field listener.
|
|
6
|
+
*/
|
|
7
|
+
export declare function installPreRegistrationQueue(): void;
|
|
8
|
+
/**
|
|
9
|
+
* Mark that a field has become live. The first live field is what makes subsequent registration
|
|
10
|
+
* events skip the queue and reach the field directly. Paired with {@link markFieldInactive}.
|
|
11
|
+
*/
|
|
12
|
+
export declare function markFieldActive(): void;
|
|
13
|
+
/**
|
|
14
|
+
* Mark that a live field has torn down. When the last field goes away the queue resumes buffering, so
|
|
15
|
+
* an element that (re)connects during a field-less window is captured for the next field that boots.
|
|
16
|
+
*/
|
|
17
|
+
export declare function markFieldInactive(): void;
|
|
18
|
+
/**
|
|
19
|
+
* Replay every buffered registration event on its source element, then clear the buffer. Called by a
|
|
20
|
+
* field immediately after it wires its body-event listeners, so the events bubble (composed) to the
|
|
21
|
+
* document and the field registers them through its normal, idempotent path. Safe to call with an
|
|
22
|
+
* empty queue (the common client-only case) — it does nothing.
|
|
23
|
+
*/
|
|
24
|
+
export declare function flushPreRegistrationQueue(): void;
|
|
25
|
+
/** Test-only: the number of events currently buffered (0 once drained). */
|
|
26
|
+
export declare function pendingRegistrationCount(): number;
|
|
27
|
+
/** Test-only: reset all module state (queue, active-field count, install flag) between tests. */
|
|
28
|
+
export declare function resetPreRegistrationQueue(): void;
|
|
29
|
+
/** Whether the queue is currently buffering (no field live). Test/introspection helper. */
|
|
30
|
+
export declare function isBuffering(): boolean;
|
|
31
|
+
//# sourceMappingURL=preregistration-queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preregistration-queue.d.ts","sourceRoot":"","sources":["../src/preregistration-queue.ts"],"names":[],"mappings":"AAsEA;;;;;GAKG;AACH,wBAAgB,2BAA2B,IAAI,IAAI,CAMlD;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAEtC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAExC;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAahD;AAED,2EAA2E;AAC3E,wBAAgB,wBAAwB,IAAI,MAAM,CAEjD;AAED,iGAAiG;AACjG,wBAAgB,yBAAyB,IAAI,IAAI,CAOhD;AAED,2FAA2F;AAC3F,wBAAgB,WAAW,IAAI,OAAO,CAErC"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSR pre-registration queue for shadow hosts (docs/engine-reference/shadow-dom.md §31.10).
|
|
3
|
+
*
|
|
4
|
+
* ## The timing problem
|
|
5
|
+
*
|
|
6
|
+
* Custom elements dispatch composed `field:register-body` events (via {@link FieldController}) from
|
|
7
|
+
* their `connectedCallback`. The singleton `<field-root>` field only listens for those events *after*
|
|
8
|
+
* it boots — `start()` → `createBrowserField` → `host.onBodyEvent(REGISTER_BODY, …)` on `document`.
|
|
9
|
+
*
|
|
10
|
+
* On a **server-rendered** page the custom elements already exist in the DOM at hydration, and they
|
|
11
|
+
* upgrade in document order. A body element earlier in the document than `<field-root>` (or whose
|
|
12
|
+
* definition loads first) fires `connectedCallback` — and its registration event — **before** the
|
|
13
|
+
* field has wired its listeners. A one-shot `dispatchEvent` with no listener is simply lost, so the
|
|
14
|
+
* body never joins the field: it renders as inert HTML.
|
|
15
|
+
*
|
|
16
|
+
* ## The queue (§31.10)
|
|
17
|
+
*
|
|
18
|
+
* Importing `@fundamental-engine/elements` installs a **capturing** document listener at module load
|
|
19
|
+
* (this file is part of the package's side-effecting entry, so any SSR/hydration bundle that pulls in
|
|
20
|
+
* the custom elements installs the queue at exactly the right moment — before any element upgrades).
|
|
21
|
+
* While no field is live it **buffers** each register / unregister / update event, keyed by element
|
|
22
|
+
* (dedupe per §31.10 — last write wins, so an `unregister` supersedes a pending `register` and no
|
|
23
|
+
* stale body is replayed). When a field boots it calls {@link flushPreRegistrationQueue}, which
|
|
24
|
+
* **replays** the buffered events on their source elements; they bubble (composed) to `document`,
|
|
25
|
+
* where the field's now-wired, idempotent listeners register them. Component mount order no longer
|
|
26
|
+
* has to be perfect.
|
|
27
|
+
*
|
|
28
|
+
* ## Why replay rather than a private body set
|
|
29
|
+
*
|
|
30
|
+
* Replaying the original events reuses the entire existing registration path (the field's
|
|
31
|
+
* `onRegister`/`onUnregister`/`onUpdate` handlers, the idempotent element-keyed `ShadowRegistry`,
|
|
32
|
+
* the coalesced rescan) with zero duplicated logic and no new public surface — it is pure lifecycle
|
|
33
|
+
* plumbing. Registration is idempotent (element-keyed), so a client-only page whose field boots
|
|
34
|
+
* before any element (the common case: nothing is ever buffered) behaves exactly as before, and the
|
|
35
|
+
* live path is untouched: once a field is active, events flow straight through and are never buffered.
|
|
36
|
+
*
|
|
37
|
+
* SSR-safe: no bare `document` / `window` access at module load. The install is guarded and becomes a
|
|
38
|
+
* no-op under Node (no `document`), so importing this on the server never throws.
|
|
39
|
+
*/
|
|
40
|
+
import { REGISTER_BODY, UNREGISTER_BODY, UPDATE_BODY } from '@fundamental-engine/core';
|
|
41
|
+
/** The body registration event names the queue intercepts (all three `composed` shadow events). */
|
|
42
|
+
const QUEUED_EVENTS = [REGISTER_BODY, UNREGISTER_BODY, UPDATE_BODY];
|
|
43
|
+
/**
|
|
44
|
+
* Buffered registration events, keyed by their source element so a burst per element collapses to its
|
|
45
|
+
* latest intent (register → update → unregister). Dedupe by element per §31.10: replaying only the
|
|
46
|
+
* last event avoids re-registering a body a later `unregister` already retired.
|
|
47
|
+
*/
|
|
48
|
+
const pending = new Map();
|
|
49
|
+
/**
|
|
50
|
+
* How many fields are currently live. While zero, early registration events are buffered; once a
|
|
51
|
+
* field is active the events reach it directly, so the queue stops buffering (and, during a flush's
|
|
52
|
+
* replay, does not re-buffer the events it just dispatched — the field is active by then).
|
|
53
|
+
*/
|
|
54
|
+
let activeFields = 0;
|
|
55
|
+
/** Installed once, lazily, on the first `<field-root>`/`<field-field>` construction (guarded for SSR). */
|
|
56
|
+
let installed = false;
|
|
57
|
+
/** Capture an early registration event into the queue (only while no field is live). */
|
|
58
|
+
function capture(e) {
|
|
59
|
+
if (activeFields > 0)
|
|
60
|
+
return; // a field is live — it takes the event directly; don't buffer.
|
|
61
|
+
const detail = e.detail;
|
|
62
|
+
if (!detail?.element)
|
|
63
|
+
return;
|
|
64
|
+
// last write wins: a later unregister/update for the same element supersedes an earlier register.
|
|
65
|
+
pending.set(detail.element, { type: e.type, detail });
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Install the capturing document listeners — idempotent, SSR-guarded. Called from the custom
|
|
69
|
+
* element's constructor so it runs on the client before the element upgrades its peers, and never on
|
|
70
|
+
* the server (no `document`). Capturing (`{ capture: true }`) so the queue sees the event on the way
|
|
71
|
+
* down, independent of any later-added bubble-phase field listener.
|
|
72
|
+
*/
|
|
73
|
+
export function installPreRegistrationQueue() {
|
|
74
|
+
if (installed || typeof document === 'undefined')
|
|
75
|
+
return;
|
|
76
|
+
installed = true;
|
|
77
|
+
for (const type of QUEUED_EVENTS) {
|
|
78
|
+
document.addEventListener(type, capture, { capture: true });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Mark that a field has become live. The first live field is what makes subsequent registration
|
|
83
|
+
* events skip the queue and reach the field directly. Paired with {@link markFieldInactive}.
|
|
84
|
+
*/
|
|
85
|
+
export function markFieldActive() {
|
|
86
|
+
activeFields++;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Mark that a live field has torn down. When the last field goes away the queue resumes buffering, so
|
|
90
|
+
* an element that (re)connects during a field-less window is captured for the next field that boots.
|
|
91
|
+
*/
|
|
92
|
+
export function markFieldInactive() {
|
|
93
|
+
if (activeFields > 0)
|
|
94
|
+
activeFields--;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Replay every buffered registration event on its source element, then clear the buffer. Called by a
|
|
98
|
+
* field immediately after it wires its body-event listeners, so the events bubble (composed) to the
|
|
99
|
+
* document and the field registers them through its normal, idempotent path. Safe to call with an
|
|
100
|
+
* empty queue (the common client-only case) — it does nothing.
|
|
101
|
+
*/
|
|
102
|
+
export function flushPreRegistrationQueue() {
|
|
103
|
+
if (!pending.size)
|
|
104
|
+
return;
|
|
105
|
+
// snapshot + clear first: dispatching runs the field's synchronous handlers, and clearing up front
|
|
106
|
+
// means a re-entrant register during that dispatch buffers cleanly for the next flush.
|
|
107
|
+
const queued = [...pending.values()];
|
|
108
|
+
pending.clear();
|
|
109
|
+
for (const { type, detail } of queued) {
|
|
110
|
+
// only replay for an element still in the document — an element that connected and disconnected
|
|
111
|
+
// during the field-less window (unregister superseded register) is already gone; and a stale
|
|
112
|
+
// register whose element never made it into the DOM must not resurrect a body.
|
|
113
|
+
if (!detail.element.isConnected)
|
|
114
|
+
continue;
|
|
115
|
+
detail.element.dispatchEvent(new CustomEvent(type, { bubbles: true, composed: true, detail }));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/** Test-only: the number of events currently buffered (0 once drained). */
|
|
119
|
+
export function pendingRegistrationCount() {
|
|
120
|
+
return pending.size;
|
|
121
|
+
}
|
|
122
|
+
/** Test-only: reset all module state (queue, active-field count, install flag) between tests. */
|
|
123
|
+
export function resetPreRegistrationQueue() {
|
|
124
|
+
pending.clear();
|
|
125
|
+
activeFields = 0;
|
|
126
|
+
if (installed && typeof document !== 'undefined') {
|
|
127
|
+
for (const type of QUEUED_EVENTS)
|
|
128
|
+
document.removeEventListener(type, capture, { capture: true });
|
|
129
|
+
}
|
|
130
|
+
installed = false;
|
|
131
|
+
}
|
|
132
|
+
/** Whether the queue is currently buffering (no field live). Test/introspection helper. */
|
|
133
|
+
export function isBuffering() {
|
|
134
|
+
return activeFields === 0;
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=preregistration-queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preregistration-queue.js","sourceRoot":"","sources":["../src/preregistration-queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAA2B,MAAM,0BAA0B,CAAC;AAEhH,mGAAmG;AACnG,MAAM,aAAa,GAAG,CAAC,aAAa,EAAE,eAAe,EAAE,WAAW,CAAU,CAAC;AAE7E;;;;GAIG;AACH,MAAM,OAAO,GAAG,IAAI,GAAG,EAA6D,CAAC;AAErF;;;;GAIG;AACH,IAAI,YAAY,GAAG,CAAC,CAAC;AAErB,0GAA0G;AAC1G,IAAI,SAAS,GAAG,KAAK,CAAC;AAEtB,wFAAwF;AACxF,SAAS,OAAO,CAAC,CAAQ;IACvB,IAAI,YAAY,GAAG,CAAC;QAAE,OAAO,CAAC,+DAA+D;IAC7F,MAAM,MAAM,GAAI,CAAqC,CAAC,MAAM,CAAC;IAC7D,IAAI,CAAC,MAAM,EAAE,OAAO;QAAE,OAAO;IAC7B,kGAAkG;IAClG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;AACxD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,2BAA2B;IACzC,IAAI,SAAS,IAAI,OAAO,QAAQ,KAAK,WAAW;QAAE,OAAO;IACzD,SAAS,GAAG,IAAI,CAAC;IACjB,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;QACjC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9D,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe;IAC7B,YAAY,EAAE,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,IAAI,YAAY,GAAG,CAAC;QAAE,YAAY,EAAE,CAAC;AACvC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB;IACvC,IAAI,CAAC,OAAO,CAAC,IAAI;QAAE,OAAO;IAC1B,mGAAmG;IACnG,uFAAuF;IACvF,MAAM,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACrC,OAAO,CAAC,KAAK,EAAE,CAAC;IAChB,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,MAAM,EAAE,CAAC;QACtC,gGAAgG;QAChG,6FAA6F;QAC7F,+EAA+E;QAC/E,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW;YAAE,SAAS;QAC1C,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IACjG,CAAC;AACH,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,wBAAwB;IACtC,OAAO,OAAO,CAAC,IAAI,CAAC;AACtB,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,yBAAyB;IACvC,OAAO,CAAC,KAAK,EAAE,CAAC;IAChB,YAAY,GAAG,CAAC,CAAC;IACjB,IAAI,SAAS,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;QACjD,KAAK,MAAM,IAAI,IAAI,aAAa;YAAE,QAAQ,CAAC,mBAAmB,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACnG,CAAC;IACD,SAAS,GAAG,KAAK,CAAC;AACpB,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,WAAW;IACzB,OAAO,YAAY,KAAK,CAAC,CAAC;AAC5B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fundamental-engine/elements",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.3",
|
|
4
4
|
"description": "Web-component keystone for Fundamental — the <field-root> custom element + declarative data-body bodies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -48,9 +48,9 @@
|
|
|
48
48
|
"access": "public"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@fundamental-engine/
|
|
52
|
-
"@fundamental-engine/
|
|
53
|
-
"@fundamental-engine/
|
|
51
|
+
"@fundamental-engine/dom": "0.9.3",
|
|
52
|
+
"@fundamental-engine/vanilla": "0.9.3",
|
|
53
|
+
"@fundamental-engine/core": "0.9.3"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"typescript": "^5.9.3"
|