@adaas/are-html 0.0.19 → 0.0.21
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/browser/index.d.mts +161 -5
- package/dist/browser/index.mjs +357 -55
- package/dist/browser/index.mjs.map +1 -1
- package/dist/node/directives/AreDirectiveFor.directive.d.mts +7 -0
- package/dist/node/directives/AreDirectiveFor.directive.d.ts +7 -0
- package/dist/node/directives/AreDirectiveFor.directive.js +17 -2
- package/dist/node/directives/AreDirectiveFor.directive.js.map +1 -1
- package/dist/node/directives/AreDirectiveFor.directive.mjs +17 -2
- package/dist/node/directives/AreDirectiveFor.directive.mjs.map +1 -1
- package/dist/node/directives/AreDirectiveShow.directive.d.mts +32 -0
- package/dist/node/directives/AreDirectiveShow.directive.d.ts +32 -0
- package/dist/node/directives/AreDirectiveShow.directive.js +81 -0
- package/dist/node/directives/AreDirectiveShow.directive.js.map +1 -0
- package/dist/node/directives/AreDirectiveShow.directive.mjs +71 -0
- package/dist/node/directives/AreDirectiveShow.directive.mjs.map +1 -0
- package/dist/node/engine/AreHTML.engine.d.mts +2 -1
- package/dist/node/engine/AreHTML.engine.d.ts +2 -1
- package/dist/node/engine/AreHTML.engine.js +8 -2
- package/dist/node/engine/AreHTML.engine.js.map +1 -1
- package/dist/node/engine/AreHTML.engine.mjs +8 -2
- package/dist/node/engine/AreHTML.engine.mjs.map +1 -1
- package/dist/node/engine/AreHTML.interpreter.d.mts +3 -0
- package/dist/node/engine/AreHTML.interpreter.d.ts +3 -0
- package/dist/node/engine/AreHTML.interpreter.js +29 -0
- package/dist/node/engine/AreHTML.interpreter.js.map +1 -1
- package/dist/node/engine/AreHTML.interpreter.mjs +29 -0
- package/dist/node/engine/AreHTML.interpreter.mjs.map +1 -1
- package/dist/node/index.d.mts +4 -1
- package/dist/node/index.d.ts +4 -1
- package/dist/node/index.js +21 -0
- package/dist/node/index.mjs +3 -0
- package/dist/node/instructions/AreHTML.instructions.constants.d.mts +1 -0
- package/dist/node/instructions/AreHTML.instructions.constants.d.ts +1 -0
- package/dist/node/instructions/AreHTML.instructions.constants.js +2 -1
- package/dist/node/instructions/AreHTML.instructions.constants.js.map +1 -1
- package/dist/node/instructions/AreHTML.instructions.constants.mjs +2 -1
- package/dist/node/instructions/AreHTML.instructions.constants.mjs.map +1 -1
- package/dist/node/instructions/AreHTML.instructions.types.d.mts +9 -1
- package/dist/node/instructions/AreHTML.instructions.types.d.ts +9 -1
- package/dist/node/instructions/HideElement.instruction.d.mts +13 -0
- package/dist/node/instructions/HideElement.instruction.d.ts +13 -0
- package/dist/node/instructions/HideElement.instruction.js +31 -0
- package/dist/node/instructions/HideElement.instruction.js.map +1 -0
- package/dist/node/instructions/HideElement.instruction.mjs +24 -0
- package/dist/node/instructions/HideElement.instruction.mjs.map +1 -0
- package/dist/node/lib/AreRoot/AreRoot.component.d.mts +57 -3
- package/dist/node/lib/AreRoot/AreRoot.component.d.ts +57 -3
- package/dist/node/lib/AreRoot/AreRoot.component.js +137 -48
- package/dist/node/lib/AreRoot/AreRoot.component.js.map +1 -1
- package/dist/node/lib/AreRoot/AreRoot.component.mjs +139 -50
- package/dist/node/lib/AreRoot/AreRoot.component.mjs.map +1 -1
- package/dist/node/lib/AreRoot/AreRootCache.context.d.mts +58 -0
- package/dist/node/lib/AreRoot/AreRootCache.context.d.ts +58 -0
- package/dist/node/lib/AreRoot/AreRootCache.context.js +106 -0
- package/dist/node/lib/AreRoot/AreRootCache.context.js.map +1 -0
- package/dist/node/lib/AreRoot/AreRootCache.context.mjs +99 -0
- package/dist/node/lib/AreRoot/AreRootCache.context.mjs.map +1 -0
- package/examples/jumpstart/dist/index.html +1 -1
- package/examples/jumpstart/dist/{mq1a0fv0-ccgtz6.js → mq7hqrxy-4kus50.js} +629 -433
- package/examples/signal-routing/dist/index.html +1 -1
- package/examples/signal-routing/dist/{mq1bzrik-4lec86.js → mq7k53th-qiwy4x.js} +903 -486
- package/examples/signal-routing/src/components/SettingsPage.component.ts +39 -0
- package/examples/signal-routing/src/concept.ts +2 -0
- package/package.json +9 -9
- package/src/directives/AreDirectiveFor.directive.ts +44 -2
- package/src/directives/AreDirectiveShow.directive.ts +127 -0
- package/src/engine/AreHTML.engine.ts +11 -1
- package/src/engine/AreHTML.interpreter.ts +50 -0
- package/src/index.ts +3 -0
- package/src/instructions/AreHTML.instructions.constants.ts +1 -0
- package/src/instructions/AreHTML.instructions.types.ts +9 -0
- package/src/instructions/HideElement.instruction.ts +29 -0
- package/src/lib/AreRoot/AreRoot.component.ts +201 -71
- package/src/lib/AreRoot/AreRootCache.context.ts +133 -0
|
@@ -6,6 +6,7 @@ var aLogger = require('@adaas/a-utils/a-logger');
|
|
|
6
6
|
var aSignal = require('@adaas/a-utils/a-signal');
|
|
7
7
|
var are = require('@adaas/are');
|
|
8
8
|
var AreRoute_signal = require('@adaas/are-html/signals/AreRoute.signal');
|
|
9
|
+
var AreRootCache_context = require('./AreRootCache.context');
|
|
9
10
|
|
|
10
11
|
var __defProp = Object.defineProperty;
|
|
11
12
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -19,7 +20,7 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
19
20
|
};
|
|
20
21
|
var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
|
|
21
22
|
exports.AreRoot = class AreRoot extends are.Are {
|
|
22
|
-
async template(root, logger, signalsContext) {
|
|
23
|
+
async template(root, logger, signalsContext, signalState) {
|
|
23
24
|
const rootId = root.id;
|
|
24
25
|
if (signalsContext && !signalsContext.hasRoot(rootId)) {
|
|
25
26
|
if (!root.content?.trim()) {
|
|
@@ -31,26 +32,9 @@ exports.AreRoot = class AreRoot extends are.Are {
|
|
|
31
32
|
}
|
|
32
33
|
return;
|
|
33
34
|
}
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const initialVector = new aSignal.A_SignalVector([currentRoute]);
|
|
38
|
-
let renderTarget = signalsContext?.findComponentByVector(rootId, initialVector);
|
|
39
|
-
if (!renderTarget) {
|
|
40
|
-
const signalsMeta = aConcept.A_Context.meta(are.AreSignals);
|
|
41
|
-
const pool = signalsContext?.getComponentById(rootId);
|
|
42
|
-
const metaTarget = signalsMeta?.findComponentByVector(
|
|
43
|
-
initialVector,
|
|
44
|
-
pool?.length ? pool : void 0
|
|
45
|
-
);
|
|
46
|
-
if (metaTarget && (!pool?.length || pool.includes(metaTarget))) {
|
|
47
|
-
renderTarget = metaTarget;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
if (renderTarget?.name) {
|
|
51
|
-
componentName = aConcept.A_FormatterHelper.toKebabCase(renderTarget.name);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
35
|
+
const initialVector = this.buildInitialVector(signalState);
|
|
36
|
+
const renderTarget = this.matchComponent(rootId, initialVector, signalsContext);
|
|
37
|
+
let componentName = renderTarget?.name ? aConcept.A_FormatterHelper.toKebabCase(renderTarget.name) : void 0;
|
|
54
38
|
if (!componentName) {
|
|
55
39
|
if (root.content?.trim()) {
|
|
56
40
|
return;
|
|
@@ -72,32 +56,17 @@ exports.AreRoot = class AreRoot extends are.Are {
|
|
|
72
56
|
}
|
|
73
57
|
root.setContent(`<${componentName}></${componentName}>`);
|
|
74
58
|
}
|
|
75
|
-
async onSignal(root, vector, logger, signalsContext) {
|
|
59
|
+
async onSignal(root, vector, logger, signalsContext, cache) {
|
|
76
60
|
const rootId = root.id;
|
|
77
61
|
if (signalsContext && !signalsContext.hasRoot(rootId)) {
|
|
78
62
|
return;
|
|
79
63
|
}
|
|
80
|
-
|
|
81
|
-
if (!renderTarget) {
|
|
82
|
-
const signalsMeta = aConcept.A_Context.meta(are.AreSignals);
|
|
83
|
-
const pool = signalsContext?.getComponentById(rootId);
|
|
84
|
-
const metaTarget = signalsMeta?.findComponentByVector(
|
|
85
|
-
vector,
|
|
86
|
-
pool?.length ? pool : void 0
|
|
87
|
-
);
|
|
88
|
-
if (metaTarget && (!pool?.length || pool.includes(metaTarget))) {
|
|
89
|
-
renderTarget = metaTarget;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
64
|
+
const renderTarget = this.matchComponent(rootId, vector, signalsContext);
|
|
92
65
|
const def = signalsContext?.getDefault(rootId);
|
|
93
66
|
const componentName = renderTarget?.name ? aConcept.A_FormatterHelper.toKebabCase(renderTarget.name) : def?.name ? aConcept.A_FormatterHelper.toKebabCase(def.name) : void 0;
|
|
94
67
|
if (!componentName) {
|
|
95
|
-
for (
|
|
96
|
-
|
|
97
|
-
signalsContext?.unsubscribe(child);
|
|
98
|
-
child.unmount();
|
|
99
|
-
child.destroy();
|
|
100
|
-
root.removeChild(child);
|
|
68
|
+
for (const child of [...root.children]) {
|
|
69
|
+
this.stashChild(root, child, signalsContext, cache);
|
|
101
70
|
}
|
|
102
71
|
root.setContent("");
|
|
103
72
|
return;
|
|
@@ -106,13 +75,14 @@ exports.AreRoot = class AreRoot extends are.Are {
|
|
|
106
75
|
if (currentChild?.type === componentName) {
|
|
107
76
|
return;
|
|
108
77
|
}
|
|
78
|
+
for (const child of [...root.children]) {
|
|
79
|
+
this.stashChild(root, child, signalsContext, cache);
|
|
80
|
+
}
|
|
109
81
|
root.setContent(`<${componentName}></${componentName}>`);
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
signalsContext
|
|
113
|
-
|
|
114
|
-
child.destroy();
|
|
115
|
-
root.removeChild(child);
|
|
82
|
+
const cached = cache?.take(root.id, componentName);
|
|
83
|
+
if (cached) {
|
|
84
|
+
this.restoreChild(root, cached, signalsContext);
|
|
85
|
+
return;
|
|
116
86
|
}
|
|
117
87
|
root.tokenize();
|
|
118
88
|
for (let i = 0; i < root.children.length; i++) {
|
|
@@ -127,19 +97,138 @@ exports.AreRoot = class AreRoot extends are.Are {
|
|
|
127
97
|
child.mount();
|
|
128
98
|
}
|
|
129
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Resolves the component a vector should render for the given root, mirroring
|
|
102
|
+
* the priority used everywhere in the routing system:
|
|
103
|
+
* 1. Root-specific conditions registered on AreSignalsContext.
|
|
104
|
+
* 2. The global AreSignalsMeta map, restricted to this outlet's pool.
|
|
105
|
+
*
|
|
106
|
+
* Passing the pool *into* the meta lookup is critical: without it, the first
|
|
107
|
+
* globally matching component wins and may belong to a different outlet
|
|
108
|
+
* (e.g. AisRequirementsPanel for the meta-outlet matching
|
|
109
|
+
* AisEditorCursorScope) — the pool check would then reject it and the outlet
|
|
110
|
+
* would fall back to its default, hiding a valid in-pool match (e.g.
|
|
111
|
+
* AisDiagramTab matching AisSetPrimaryDisplay).
|
|
112
|
+
*
|
|
113
|
+
* Returns `undefined` when nothing matches — callers decide whether to use a
|
|
114
|
+
* configured default, body content, or clear the outlet.
|
|
115
|
+
*/
|
|
116
|
+
matchComponent(rootId, vector, signalsContext) {
|
|
117
|
+
if (!vector) return void 0;
|
|
118
|
+
let renderTarget = signalsContext?.findComponentByVector(rootId, vector);
|
|
119
|
+
if (!renderTarget) {
|
|
120
|
+
const signalsMeta = aConcept.A_Context.meta(are.AreSignals);
|
|
121
|
+
const pool = signalsContext?.getComponentById(rootId);
|
|
122
|
+
const metaTarget = signalsMeta?.findComponentByVector(
|
|
123
|
+
vector,
|
|
124
|
+
pool?.length ? pool : void 0,
|
|
125
|
+
rootId
|
|
126
|
+
);
|
|
127
|
+
if (metaTarget && (!pool?.length || pool.includes(metaTarget))) {
|
|
128
|
+
renderTarget = metaTarget;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return renderTarget;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Builds the vector used for the INITIAL render. It is seeded from the
|
|
135
|
+
* accumulated signal state (every signal dispatched on the bus so far) so a
|
|
136
|
+
* freshly-mounted outlet reflects the live application state immediately,
|
|
137
|
+
* not just on the next signal tick. The current URL route is appended when
|
|
138
|
+
* no AreRoute is already present in the state, so route-driven outlets still
|
|
139
|
+
* resolve on the very first paint (before AreRouteWatcher has dispatched).
|
|
140
|
+
*/
|
|
141
|
+
buildInitialVector(signalState) {
|
|
142
|
+
const signals = [];
|
|
143
|
+
if (signalState) {
|
|
144
|
+
for (const signal of signalState.toVector()) {
|
|
145
|
+
if (signal) signals.push(signal);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (!signals.some((signal) => signal instanceof AreRoute_signal.AreRoute)) {
|
|
149
|
+
try {
|
|
150
|
+
const currentRoute = AreRoute_signal.AreRoute.default();
|
|
151
|
+
if (currentRoute) signals.push(currentRoute);
|
|
152
|
+
} catch {
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return new aSignal.A_SignalVector(signals);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Detach a displayed child subtree from the outlet and stash it in the cache
|
|
159
|
+
* for fast re-injection later. The subtree is unmounted (its scene plan is
|
|
160
|
+
* preserved) and deregistered from the root scope, but NOT destroyed. The
|
|
161
|
+
* nodes that were subscribed to the signal bus are unsubscribed while cached
|
|
162
|
+
* so the detached DOM never reacts to signals, and recorded so they can be
|
|
163
|
+
* re-subscribed verbatim on restore.
|
|
164
|
+
*
|
|
165
|
+
* When no cache is available, or the LRU evicts an entry, the affected
|
|
166
|
+
* subtree is fully destroyed.
|
|
167
|
+
*/
|
|
168
|
+
stashChild(root, child, signalsContext, cache) {
|
|
169
|
+
const tag = child.type;
|
|
170
|
+
child.unmount();
|
|
171
|
+
const subscribers = signalsContext ? this.collectSubscribers(child, signalsContext) : [];
|
|
172
|
+
for (const node of subscribers) {
|
|
173
|
+
signalsContext?.unsubscribe(node);
|
|
174
|
+
}
|
|
175
|
+
root.removeChild(child);
|
|
176
|
+
if (!cache) {
|
|
177
|
+
void child.destroy();
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const evicted = cache.put(root.id, tag, { node: child, subscribers });
|
|
181
|
+
for (const entry of evicted) {
|
|
182
|
+
void entry.node.destroy();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Re-attach a cached subtree to the outlet and re-mount it from its preserved
|
|
187
|
+
* scene plan, re-subscribing exactly the nodes that were subscribed before it
|
|
188
|
+
* was cached.
|
|
189
|
+
*/
|
|
190
|
+
restoreChild(root, entry, signalsContext) {
|
|
191
|
+
const child = entry.node;
|
|
192
|
+
root.addChild(child);
|
|
193
|
+
for (const node of entry.subscribers) {
|
|
194
|
+
signalsContext?.subscribe(node);
|
|
195
|
+
}
|
|
196
|
+
child.mount();
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Walk a subtree and collect the nodes currently registered as signal
|
|
200
|
+
* subscribers. Mirrors the subscription performed at init time in
|
|
201
|
+
* AreHTMLLifecycle (component nodes and root nodes) without depending on the
|
|
202
|
+
* concrete node classes — it simply intersects the subtree with the live
|
|
203
|
+
* subscriber registry.
|
|
204
|
+
*/
|
|
205
|
+
collectSubscribers(node, signalsContext) {
|
|
206
|
+
const result = [];
|
|
207
|
+
const queue = [node];
|
|
208
|
+
while (queue.length > 0) {
|
|
209
|
+
const current = queue.shift();
|
|
210
|
+
if (signalsContext.subscribers.has(current)) {
|
|
211
|
+
result.push(current);
|
|
212
|
+
}
|
|
213
|
+
queue.push(...current.children);
|
|
214
|
+
}
|
|
215
|
+
return result;
|
|
216
|
+
}
|
|
130
217
|
};
|
|
131
218
|
__decorateClass([
|
|
132
219
|
are.Are.Template,
|
|
133
220
|
__decorateParam(0, aConcept.A_Inject(aConcept.A_Caller)),
|
|
134
221
|
__decorateParam(1, aConcept.A_Inject(aLogger.A_Logger)),
|
|
135
|
-
__decorateParam(2, aConcept.A_Inject(are.AreSignalsContext))
|
|
222
|
+
__decorateParam(2, aConcept.A_Inject(are.AreSignalsContext)),
|
|
223
|
+
__decorateParam(3, aConcept.A_Inject(aSignal.A_SignalState))
|
|
136
224
|
], exports.AreRoot.prototype, "template", 1);
|
|
137
225
|
__decorateClass([
|
|
138
226
|
are.Are.Signal,
|
|
139
227
|
__decorateParam(0, aConcept.A_Inject(aConcept.A_Caller)),
|
|
140
228
|
__decorateParam(1, aConcept.A_Inject(aSignal.A_SignalVector)),
|
|
141
229
|
__decorateParam(2, aConcept.A_Inject(aLogger.A_Logger)),
|
|
142
|
-
__decorateParam(3, aConcept.A_Inject(are.AreSignalsContext))
|
|
230
|
+
__decorateParam(3, aConcept.A_Inject(are.AreSignalsContext)),
|
|
231
|
+
__decorateParam(4, aConcept.A_Inject(AreRootCache_context.AreRootCache))
|
|
143
232
|
], exports.AreRoot.prototype, "onSignal", 1);
|
|
144
233
|
exports.AreRoot = __decorateClass([
|
|
145
234
|
core.A_Frame.Define({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/lib/AreRoot/AreRoot.component.ts"],"names":["AreRoot","Are","AreRoute","A_SignalVector","A_Context","AreSignals","A_FormatterHelper","A_Caller","A_Logger","AreSignalsContext","A_Frame"],"mappings":"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","file":"AreRoot.component.js","sourcesContent":["import { A_Caller, A_Context, A_FormatterHelper, A_Inject, } from \"@adaas/a-concept\";\nimport { A_Frame } from \"@adaas/a-frame/core\";\nimport { A_Logger } from \"@adaas/a-utils/a-logger\";\nimport { A_SignalVector } from \"@adaas/a-utils/a-signal\";\nimport { Are, AreNode, AreSignals, AreSignalsMeta, AreSignalsContext } from \"@adaas/are\";\nimport { AreRoute } from \"@adaas/are-html/signals/AreRoute.signal\";\n\n\n@A_Frame.Define({\n namespace: 'a-are-html',\n description: 'The AreRoot component serves as the foundational entry point for the A-Concept Rendering Engine (ARE). It is responsible for initializing the rendering process, managing the root node of the component tree, and handling signal-based rendering logic. The AreRoot component processes incoming signals to determine which child components to render, allowing for dynamic and responsive UI updates based on application state and user interactions.'\n})\nexport class AreRoot extends Are {\n\n @Are.Template\n async template(\n @A_Inject(A_Caller) root: AreNode,\n @A_Inject(A_Logger) logger: A_Logger,\n @A_Inject(AreSignalsContext) signalsContext?: AreSignalsContext,\n ) {\n\n const rootId = root.id;\n\n // No routing config for this root — but still honour body content or\n // a 'default' attribute if one is present on the markup.\n if (signalsContext && !signalsContext.hasRoot(rootId)) {\n if (!root.content?.trim()) {\n // Fallback: legacy default= attribute\n const defaultMatch = root.markup?.match(/\\bdefault=[\"']([^\"']*)[\"']/);\n const defaultComponent = defaultMatch?.[1];\n if (defaultComponent) {\n root.setContent(`<${defaultComponent}></${defaultComponent}>`);\n }\n }\n // Body content (or none) — tokenizer picks it up without intervention\n return;\n }\n\n const currentRoute = AreRoute.default();\n\n let componentName: string | undefined;\n\n if (currentRoute) {\n const initialVector = new A_SignalVector([currentRoute]);\n\n // 1. Lookup via AreSignalsContext (per root-id conditions)\n let renderTarget = signalsContext?.findComponentByVector(rootId, initialVector);\n\n // 2. Fall back to global AreSignalsMeta, pool-filtered.\n // IMPORTANT: pass the pool *into* the lookup so it can skip over\n // out-of-pool matches (e.g. a meta-outlet component whose condition\n // also matches the same vector) and find the highest-priority match\n // that this outlet can actually render. Filtering only after the\n // fact would mask valid in-pool matches and surface the outlet's\n // default instead.\n if (!renderTarget) {\n const signalsMeta = A_Context.meta<AreSignalsMeta>(AreSignals);\n const pool = signalsContext?.getComponentById(rootId);\n const metaTarget = signalsMeta?.findComponentByVector(\n initialVector,\n pool?.length ? pool : undefined,\n );\n if (metaTarget && (!pool?.length || pool.includes(metaTarget))) {\n renderTarget = metaTarget;\n }\n }\n\n if (renderTarget?.name) {\n componentName = A_FormatterHelper.toKebabCase(renderTarget.name);\n }\n }\n\n // 3. Fall back to body content (the nodes already placed inside the\n // <are-root> tag act as the default). No setContent() call needed —\n // the tokenizer will process root.content as-is.\n if (!componentName) {\n if (root.content?.trim()) {\n return;\n }\n }\n // 3.5. Fall back to AreSignalsContext default component for this root.\n if (!componentName) {\n const defaultComp = signalsContext?.getDefault(rootId);\n if (defaultComp?.name) {\n componentName = A_FormatterHelper.toKebabCase(defaultComp.name);\n }\n }\n // 4. Last resort: legacy default= attribute on the markup.\n if (!componentName) {\n const defaultMatch = root.markup?.match(/\\bdefault=[\"']([^\"']*)[\"']/);\n componentName = defaultMatch?.[1];\n }\n\n if (!componentName) {\n logger.warning('AreRoot: No component found for initial render. Provide body content, a route condition, or a \"default\" attribute.');\n return;\n }\n\n root.setContent(`<${componentName}></${componentName}>`);\n }\n\n\n @Are.Signal\n async onSignal(\n @A_Inject(A_Caller) root: AreNode,\n @A_Inject(A_SignalVector) vector: A_SignalVector,\n @A_Inject(A_Logger) logger: A_Logger,\n @A_Inject(AreSignalsContext) signalsContext?: AreSignalsContext,\n ) {\n const rootId = root.id;\n\n // No routing config for this root — signals do not affect its content\n if (signalsContext && !signalsContext.hasRoot(rootId)) {\n return;\n }\n\n // 1. Try root-specific lookup via AreSignalsContext (keyed by the are-root's id attribute)\n let renderTarget = signalsContext?.findComponentByVector(rootId, vector);\n\n // 2. Fall back to global AreSignalsMeta lookup, restricted to this\n // outlet's pool. Passing the pool *into* the lookup is critical:\n // without it, the first globally matching component wins and may\n // belong to a different outlet (e.g. AisRequirementsPanel for the\n // meta-outlet matching AisEditorCursorScope) — the pool check then\n // rejects it and the outlet falls back to default, hiding a valid\n // in-pool match (e.g. AisDiagramTab matching AisSetPrimaryDisplay).\n if (!renderTarget) {\n const signalsMeta = A_Context.meta<AreSignalsMeta>(AreSignals);\n const pool = signalsContext?.getComponentById(rootId);\n const metaTarget = signalsMeta?.findComponentByVector(\n vector,\n pool?.length ? pool : undefined,\n );\n if (metaTarget && (!pool?.length || pool.includes(metaTarget))) {\n renderTarget = metaTarget;\n }\n }\n\n const def = signalsContext?.getDefault(rootId);\n const componentName = renderTarget?.name\n ? A_FormatterHelper.toKebabCase(renderTarget.name)\n : def?.name\n ? A_FormatterHelper.toKebabCase(def.name)\n : undefined;\n\n // No matching condition for this signal vector and no default — clear the outlet.\n if (!componentName) {\n for (let i = 0; i < root.children.length; i++) {\n const child = root.children[i];\n signalsContext?.unsubscribe(child);\n child.unmount();\n child.destroy();\n root.removeChild(child);\n }\n root.setContent('');\n return;\n }\n\n // Guard: if the outlet already shows the same component, do nothing.\n // Prevents infinite remount loops when a non-routing signal carries a\n // stale routing signal in the accumulated A_SignalState vector.\n // node.type is the kebab-case tag name — the most direct and reliable\n // identifier (no constructor-name resolution, no proxy wrapping issues).\n const currentChild = root.children[0] as AreNode | undefined;\n if (currentChild?.type === componentName) {\n return;\n }\n\n root.setContent(`<${componentName}></${componentName}>`);\n\n // Unsubscribe old children BEFORE destroying them.\n // Without this, AreSignals.handleSignalVector keeps iterating stale\n // (scope-less) nodes on every subsequent signal and throws an error.\n for (let i = 0; i < root.children.length; i++) {\n const child = root.children[i];\n signalsContext?.unsubscribe(child);\n child.unmount();\n child.destroy();\n root.removeChild(child);\n }\n\n\n root.tokenize();\n\n for (let i = 0; i < root.children.length; i++) {\n const child = root.children[i];\n child.init();\n\n const res = child.load();\n if (res instanceof Promise) {\n await res;\n }\n child.transform();\n\n child.compile();\n child.mount();\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/AreRoot/AreRoot.component.ts"],"names":["AreRoot","Are","A_FormatterHelper","A_Context","AreSignals","AreRoute","A_SignalVector","A_Caller","A_Logger","AreSignalsContext","A_SignalState","AreRootCache","A_Frame"],"mappings":"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","file":"AreRoot.component.js","sourcesContent":["import { A_Caller, A_Context, A_FormatterHelper, A_Inject, A_TYPES__Ctor } from \"@adaas/a-concept\";\nimport { A_Frame } from \"@adaas/a-frame/core\";\nimport { A_Logger } from \"@adaas/a-utils/a-logger\";\nimport { A_Signal, A_SignalState, A_SignalVector } from \"@adaas/a-utils/a-signal\";\nimport { Are, AreNode, AreSignals, AreSignalsMeta, AreSignalsContext } from \"@adaas/are\";\nimport { AreRoute } from \"@adaas/are-html/signals/AreRoute.signal\";\nimport { AreRootCache, AreRootCacheEntry } from \"./AreRootCache.context\";\n\n\n@A_Frame.Define({\n namespace: 'a-are-html',\n description: 'The AreRoot component serves as the foundational entry point for the A-Concept Rendering Engine (ARE). It is responsible for initializing the rendering process, managing the root node of the component tree, and handling signal-based rendering logic. The AreRoot component processes incoming signals to determine which child components to render, allowing for dynamic and responsive UI updates based on application state and user interactions.'\n})\nexport class AreRoot extends Are {\n\n @Are.Template\n async template(\n @A_Inject(A_Caller) root: AreNode,\n @A_Inject(A_Logger) logger: A_Logger,\n @A_Inject(AreSignalsContext) signalsContext?: AreSignalsContext,\n @A_Inject(A_SignalState) signalState?: A_SignalState,\n ) {\n\n const rootId = root.id;\n\n // No routing config for this root — but still honour body content or\n // a 'default' attribute if one is present on the markup.\n if (signalsContext && !signalsContext.hasRoot(rootId)) {\n if (!root.content?.trim()) {\n // Fallback: legacy default= attribute\n const defaultMatch = root.markup?.match(/\\bdefault=[\"']([^\"']*)[\"']/);\n const defaultComponent = defaultMatch?.[1];\n if (defaultComponent) {\n root.setContent(`<${defaultComponent}></${defaultComponent}>`);\n }\n }\n // Body content (or none) — tokenizer picks it up without intervention\n return;\n }\n\n // Select from the ACCUMULATED signal state (every signal dispatched so\n // far), not just the current URL route. Outlets keyed on domain signals\n // (e.g. a primary-display selector) must reflect the live vector the\n // moment they mount — even when they mount AFTER the routing signal was\n // dispatched (a nested outlet inside a just-rendered parent). Using the\n // same vector + lookup as onSignal keeps initial render and subsequent\n // updates consistent.\n const initialVector = this.buildInitialVector(signalState);\n const renderTarget = this.matchComponent(rootId, initialVector, signalsContext);\n\n let componentName: string | undefined = renderTarget?.name\n ? A_FormatterHelper.toKebabCase(renderTarget.name)\n : undefined;\n\n // 3. Fall back to body content (the nodes already placed inside the\n // <are-root> tag act as the default). No setContent() call needed —\n // the tokenizer will process root.content as-is.\n if (!componentName) {\n if (root.content?.trim()) {\n return;\n }\n }\n // 3.5. Fall back to AreSignalsContext default component for this root.\n if (!componentName) {\n const defaultComp = signalsContext?.getDefault(rootId);\n if (defaultComp?.name) {\n componentName = A_FormatterHelper.toKebabCase(defaultComp.name);\n }\n }\n // 4. Last resort: legacy default= attribute on the markup.\n if (!componentName) {\n const defaultMatch = root.markup?.match(/\\bdefault=[\"']([^\"']*)[\"']/);\n componentName = defaultMatch?.[1];\n }\n\n if (!componentName) {\n logger.warning('AreRoot: No component found for initial render. Provide body content, a route condition, or a \"default\" attribute.');\n return;\n }\n\n root.setContent(`<${componentName}></${componentName}>`);\n }\n\n\n @Are.Signal\n async onSignal(\n @A_Inject(A_Caller) root: AreNode,\n @A_Inject(A_SignalVector) vector: A_SignalVector,\n @A_Inject(A_Logger) logger: A_Logger,\n @A_Inject(AreSignalsContext) signalsContext?: AreSignalsContext,\n @A_Inject(AreRootCache) cache?: AreRootCache,\n ) {\n const rootId = root.id;\n\n // No routing config for this root — signals do not affect its content\n if (signalsContext && !signalsContext.hasRoot(rootId)) {\n return;\n }\n\n // Resolve the target component for the incoming vector using the SAME\n // lookup the initial template render uses (root-id conditions first,\n // then the global pool-filtered meta map).\n const renderTarget = this.matchComponent(rootId, vector, signalsContext);\n\n const def = signalsContext?.getDefault(rootId);\n const componentName = renderTarget?.name\n ? A_FormatterHelper.toKebabCase(renderTarget.name)\n : def?.name\n ? A_FormatterHelper.toKebabCase(def.name)\n : undefined;\n\n // No matching condition for this signal vector and no default — clear the outlet.\n if (!componentName) {\n for (const child of [...root.children]) {\n this.stashChild(root, child, signalsContext, cache);\n }\n root.setContent('');\n return;\n }\n\n // Guard: if the outlet already shows the same component, do nothing.\n // Prevents infinite remount loops when a non-routing signal carries a\n // stale routing signal in the accumulated A_SignalState vector.\n // node.type is the kebab-case tag name — the most direct and reliable\n // identifier (no constructor-name resolution, no proxy wrapping issues).\n const currentChild = root.children[0] as AreNode | undefined;\n if (currentChild?.type === componentName) {\n return;\n }\n\n // Stash the currently displayed children so routing back to them can be\n // re-injected instantly from the cache (they are unmounted + detached but\n // NOT destroyed). Falls back to full teardown when no cache is available.\n for (const child of [...root.children]) {\n this.stashChild(root, child, signalsContext, cache);\n }\n\n root.setContent(`<${componentName}></${componentName}>`);\n\n // Fast path: a previously rendered subtree for this component is cached —\n // re-attach it and re-mount from the preserved scene plan, skipping the\n // expensive tokenize/init/load/transform/compile pipeline.\n const cached = cache?.take(root.id, componentName);\n if (cached) {\n this.restoreChild(root, cached, signalsContext);\n return;\n }\n\n // Slow path: build the component subtree from scratch.\n root.tokenize();\n\n for (let i = 0; i < root.children.length; i++) {\n const child = root.children[i];\n child.init();\n\n const res = child.load();\n if (res instanceof Promise) {\n await res;\n }\n child.transform();\n\n child.compile();\n child.mount();\n }\n }\n\n /**\n * Resolves the component a vector should render for the given root, mirroring\n * the priority used everywhere in the routing system:\n * 1. Root-specific conditions registered on AreSignalsContext.\n * 2. The global AreSignalsMeta map, restricted to this outlet's pool.\n *\n * Passing the pool *into* the meta lookup is critical: without it, the first\n * globally matching component wins and may belong to a different outlet\n * (e.g. AisRequirementsPanel for the meta-outlet matching\n * AisEditorCursorScope) — the pool check would then reject it and the outlet\n * would fall back to its default, hiding a valid in-pool match (e.g.\n * AisDiagramTab matching AisSetPrimaryDisplay).\n *\n * Returns `undefined` when nothing matches — callers decide whether to use a\n * configured default, body content, or clear the outlet.\n */\n protected matchComponent(\n rootId: string,\n vector: A_SignalVector | undefined,\n signalsContext?: AreSignalsContext,\n ): A_TYPES__Ctor<Are> | undefined {\n if (!vector) return undefined;\n\n // 1. Root-specific conditions.\n let renderTarget = signalsContext?.findComponentByVector(rootId, vector);\n\n // 2. Global pool-filtered meta map.\n if (!renderTarget) {\n const signalsMeta = A_Context.meta<AreSignalsMeta>(AreSignals);\n const pool = signalsContext?.getComponentById(rootId);\n const metaTarget = signalsMeta?.findComponentByVector(\n vector,\n pool?.length ? pool : undefined,\n rootId,\n );\n if (metaTarget && (!pool?.length || pool.includes(metaTarget))) {\n renderTarget = metaTarget;\n }\n }\n\n return renderTarget as A_TYPES__Ctor<Are> | undefined;\n }\n\n /**\n * Builds the vector used for the INITIAL render. It is seeded from the\n * accumulated signal state (every signal dispatched on the bus so far) so a\n * freshly-mounted outlet reflects the live application state immediately,\n * not just on the next signal tick. The current URL route is appended when\n * no AreRoute is already present in the state, so route-driven outlets still\n * resolve on the very first paint (before AreRouteWatcher has dispatched).\n */\n protected buildInitialVector(signalState?: A_SignalState): A_SignalVector {\n const signals: A_Signal[] = [];\n\n if (signalState) {\n for (const signal of signalState.toVector()) {\n if (signal) signals.push(signal);\n }\n }\n\n if (!signals.some(signal => signal instanceof AreRoute)) {\n try {\n const currentRoute = AreRoute.default();\n if (currentRoute) signals.push(currentRoute);\n } catch {\n // Non-browser environment (no document) — route is simply absent.\n }\n }\n\n return new A_SignalVector(signals);\n }\n\n /**\n * Detach a displayed child subtree from the outlet and stash it in the cache\n * for fast re-injection later. The subtree is unmounted (its scene plan is\n * preserved) and deregistered from the root scope, but NOT destroyed. The\n * nodes that were subscribed to the signal bus are unsubscribed while cached\n * so the detached DOM never reacts to signals, and recorded so they can be\n * re-subscribed verbatim on restore.\n *\n * When no cache is available, or the LRU evicts an entry, the affected\n * subtree is fully destroyed.\n */\n protected stashChild(\n root: AreNode,\n child: AreNode,\n signalsContext: AreSignalsContext | undefined,\n cache: AreRootCache | undefined,\n ): void {\n const tag = child.type;\n\n child.unmount();\n\n // Collect exactly the nodes that are currently subscribed within this\n // subtree, then unsubscribe them. Without this, AreSignals keeps\n // delivering vectors to a detached subtree that would update reverted\n // DOM (unmount does not deactivate the scene).\n const subscribers = signalsContext\n ? this.collectSubscribers(child, signalsContext)\n : [];\n for (const node of subscribers) {\n signalsContext?.unsubscribe(node);\n }\n\n // Deregister from the root scope (the \"deregister node from parent\").\n root.removeChild(child);\n\n if (!cache) {\n void child.destroy();\n return;\n }\n\n const evicted = cache.put(root.id, tag, { node: child, subscribers });\n for (const entry of evicted) {\n // Evicted entries are already unmounted + unsubscribed + detached.\n void entry.node.destroy();\n }\n }\n\n /**\n * Re-attach a cached subtree to the outlet and re-mount it from its preserved\n * scene plan, re-subscribing exactly the nodes that were subscribed before it\n * was cached.\n */\n protected restoreChild(\n root: AreNode,\n entry: AreRootCacheEntry,\n signalsContext: AreSignalsContext | undefined,\n ): void {\n const child = entry.node;\n\n root.addChild(child);\n\n for (const node of entry.subscribers) {\n signalsContext?.subscribe(node);\n }\n\n child.mount();\n }\n\n /**\n * Walk a subtree and collect the nodes currently registered as signal\n * subscribers. Mirrors the subscription performed at init time in\n * AreHTMLLifecycle (component nodes and root nodes) without depending on the\n * concrete node classes — it simply intersects the subtree with the live\n * subscriber registry.\n */\n protected collectSubscribers(\n node: AreNode,\n signalsContext: AreSignalsContext,\n ): AreNode[] {\n const result: AreNode[] = [];\n const queue: AreNode[] = [node];\n while (queue.length > 0) {\n const current = queue.shift()!;\n if (signalsContext.subscribers.has(current)) {\n result.push(current);\n }\n queue.push(...current.children);\n }\n return result;\n }\n}\n"]}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { __decorateClass, __decorateParam } from '../../chunk-EQQGB2QZ.mjs';
|
|
2
|
-
import { A_Inject, A_Caller,
|
|
2
|
+
import { A_Inject, A_Caller, A_FormatterHelper, A_Context } from '@adaas/a-concept';
|
|
3
3
|
import { A_Frame } from '@adaas/a-frame/core';
|
|
4
4
|
import { A_Logger } from '@adaas/a-utils/a-logger';
|
|
5
|
-
import { A_SignalVector } from '@adaas/a-utils/a-signal';
|
|
5
|
+
import { A_SignalState, A_SignalVector } from '@adaas/a-utils/a-signal';
|
|
6
6
|
import { Are, AreSignalsContext, AreSignals } from '@adaas/are';
|
|
7
7
|
import { AreRoute } from '@adaas/are-html/signals/AreRoute.signal';
|
|
8
|
+
import { AreRootCache } from './AreRootCache.context';
|
|
8
9
|
|
|
9
10
|
let AreRoot = class extends Are {
|
|
10
|
-
async template(root, logger, signalsContext) {
|
|
11
|
+
async template(root, logger, signalsContext, signalState) {
|
|
11
12
|
const rootId = root.id;
|
|
12
13
|
if (signalsContext && !signalsContext.hasRoot(rootId)) {
|
|
13
14
|
if (!root.content?.trim()) {
|
|
@@ -19,26 +20,9 @@ let AreRoot = class extends Are {
|
|
|
19
20
|
}
|
|
20
21
|
return;
|
|
21
22
|
}
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const initialVector = new A_SignalVector([currentRoute]);
|
|
26
|
-
let renderTarget = signalsContext?.findComponentByVector(rootId, initialVector);
|
|
27
|
-
if (!renderTarget) {
|
|
28
|
-
const signalsMeta = A_Context.meta(AreSignals);
|
|
29
|
-
const pool = signalsContext?.getComponentById(rootId);
|
|
30
|
-
const metaTarget = signalsMeta?.findComponentByVector(
|
|
31
|
-
initialVector,
|
|
32
|
-
pool?.length ? pool : void 0
|
|
33
|
-
);
|
|
34
|
-
if (metaTarget && (!pool?.length || pool.includes(metaTarget))) {
|
|
35
|
-
renderTarget = metaTarget;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
if (renderTarget?.name) {
|
|
39
|
-
componentName = A_FormatterHelper.toKebabCase(renderTarget.name);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
23
|
+
const initialVector = this.buildInitialVector(signalState);
|
|
24
|
+
const renderTarget = this.matchComponent(rootId, initialVector, signalsContext);
|
|
25
|
+
let componentName = renderTarget?.name ? A_FormatterHelper.toKebabCase(renderTarget.name) : void 0;
|
|
42
26
|
if (!componentName) {
|
|
43
27
|
if (root.content?.trim()) {
|
|
44
28
|
return;
|
|
@@ -60,32 +44,17 @@ let AreRoot = class extends Are {
|
|
|
60
44
|
}
|
|
61
45
|
root.setContent(`<${componentName}></${componentName}>`);
|
|
62
46
|
}
|
|
63
|
-
async onSignal(root, vector, logger, signalsContext) {
|
|
47
|
+
async onSignal(root, vector, logger, signalsContext, cache) {
|
|
64
48
|
const rootId = root.id;
|
|
65
49
|
if (signalsContext && !signalsContext.hasRoot(rootId)) {
|
|
66
50
|
return;
|
|
67
51
|
}
|
|
68
|
-
|
|
69
|
-
if (!renderTarget) {
|
|
70
|
-
const signalsMeta = A_Context.meta(AreSignals);
|
|
71
|
-
const pool = signalsContext?.getComponentById(rootId);
|
|
72
|
-
const metaTarget = signalsMeta?.findComponentByVector(
|
|
73
|
-
vector,
|
|
74
|
-
pool?.length ? pool : void 0
|
|
75
|
-
);
|
|
76
|
-
if (metaTarget && (!pool?.length || pool.includes(metaTarget))) {
|
|
77
|
-
renderTarget = metaTarget;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
52
|
+
const renderTarget = this.matchComponent(rootId, vector, signalsContext);
|
|
80
53
|
const def = signalsContext?.getDefault(rootId);
|
|
81
54
|
const componentName = renderTarget?.name ? A_FormatterHelper.toKebabCase(renderTarget.name) : def?.name ? A_FormatterHelper.toKebabCase(def.name) : void 0;
|
|
82
55
|
if (!componentName) {
|
|
83
|
-
for (
|
|
84
|
-
|
|
85
|
-
signalsContext?.unsubscribe(child);
|
|
86
|
-
child.unmount();
|
|
87
|
-
child.destroy();
|
|
88
|
-
root.removeChild(child);
|
|
56
|
+
for (const child of [...root.children]) {
|
|
57
|
+
this.stashChild(root, child, signalsContext, cache);
|
|
89
58
|
}
|
|
90
59
|
root.setContent("");
|
|
91
60
|
return;
|
|
@@ -94,13 +63,14 @@ let AreRoot = class extends Are {
|
|
|
94
63
|
if (currentChild?.type === componentName) {
|
|
95
64
|
return;
|
|
96
65
|
}
|
|
66
|
+
for (const child of [...root.children]) {
|
|
67
|
+
this.stashChild(root, child, signalsContext, cache);
|
|
68
|
+
}
|
|
97
69
|
root.setContent(`<${componentName}></${componentName}>`);
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
signalsContext
|
|
101
|
-
|
|
102
|
-
child.destroy();
|
|
103
|
-
root.removeChild(child);
|
|
70
|
+
const cached = cache?.take(root.id, componentName);
|
|
71
|
+
if (cached) {
|
|
72
|
+
this.restoreChild(root, cached, signalsContext);
|
|
73
|
+
return;
|
|
104
74
|
}
|
|
105
75
|
root.tokenize();
|
|
106
76
|
for (let i = 0; i < root.children.length; i++) {
|
|
@@ -115,19 +85,138 @@ let AreRoot = class extends Are {
|
|
|
115
85
|
child.mount();
|
|
116
86
|
}
|
|
117
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Resolves the component a vector should render for the given root, mirroring
|
|
90
|
+
* the priority used everywhere in the routing system:
|
|
91
|
+
* 1. Root-specific conditions registered on AreSignalsContext.
|
|
92
|
+
* 2. The global AreSignalsMeta map, restricted to this outlet's pool.
|
|
93
|
+
*
|
|
94
|
+
* Passing the pool *into* the meta lookup is critical: without it, the first
|
|
95
|
+
* globally matching component wins and may belong to a different outlet
|
|
96
|
+
* (e.g. AisRequirementsPanel for the meta-outlet matching
|
|
97
|
+
* AisEditorCursorScope) — the pool check would then reject it and the outlet
|
|
98
|
+
* would fall back to its default, hiding a valid in-pool match (e.g.
|
|
99
|
+
* AisDiagramTab matching AisSetPrimaryDisplay).
|
|
100
|
+
*
|
|
101
|
+
* Returns `undefined` when nothing matches — callers decide whether to use a
|
|
102
|
+
* configured default, body content, or clear the outlet.
|
|
103
|
+
*/
|
|
104
|
+
matchComponent(rootId, vector, signalsContext) {
|
|
105
|
+
if (!vector) return void 0;
|
|
106
|
+
let renderTarget = signalsContext?.findComponentByVector(rootId, vector);
|
|
107
|
+
if (!renderTarget) {
|
|
108
|
+
const signalsMeta = A_Context.meta(AreSignals);
|
|
109
|
+
const pool = signalsContext?.getComponentById(rootId);
|
|
110
|
+
const metaTarget = signalsMeta?.findComponentByVector(
|
|
111
|
+
vector,
|
|
112
|
+
pool?.length ? pool : void 0,
|
|
113
|
+
rootId
|
|
114
|
+
);
|
|
115
|
+
if (metaTarget && (!pool?.length || pool.includes(metaTarget))) {
|
|
116
|
+
renderTarget = metaTarget;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return renderTarget;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Builds the vector used for the INITIAL render. It is seeded from the
|
|
123
|
+
* accumulated signal state (every signal dispatched on the bus so far) so a
|
|
124
|
+
* freshly-mounted outlet reflects the live application state immediately,
|
|
125
|
+
* not just on the next signal tick. The current URL route is appended when
|
|
126
|
+
* no AreRoute is already present in the state, so route-driven outlets still
|
|
127
|
+
* resolve on the very first paint (before AreRouteWatcher has dispatched).
|
|
128
|
+
*/
|
|
129
|
+
buildInitialVector(signalState) {
|
|
130
|
+
const signals = [];
|
|
131
|
+
if (signalState) {
|
|
132
|
+
for (const signal of signalState.toVector()) {
|
|
133
|
+
if (signal) signals.push(signal);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (!signals.some((signal) => signal instanceof AreRoute)) {
|
|
137
|
+
try {
|
|
138
|
+
const currentRoute = AreRoute.default();
|
|
139
|
+
if (currentRoute) signals.push(currentRoute);
|
|
140
|
+
} catch {
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return new A_SignalVector(signals);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Detach a displayed child subtree from the outlet and stash it in the cache
|
|
147
|
+
* for fast re-injection later. The subtree is unmounted (its scene plan is
|
|
148
|
+
* preserved) and deregistered from the root scope, but NOT destroyed. The
|
|
149
|
+
* nodes that were subscribed to the signal bus are unsubscribed while cached
|
|
150
|
+
* so the detached DOM never reacts to signals, and recorded so they can be
|
|
151
|
+
* re-subscribed verbatim on restore.
|
|
152
|
+
*
|
|
153
|
+
* When no cache is available, or the LRU evicts an entry, the affected
|
|
154
|
+
* subtree is fully destroyed.
|
|
155
|
+
*/
|
|
156
|
+
stashChild(root, child, signalsContext, cache) {
|
|
157
|
+
const tag = child.type;
|
|
158
|
+
child.unmount();
|
|
159
|
+
const subscribers = signalsContext ? this.collectSubscribers(child, signalsContext) : [];
|
|
160
|
+
for (const node of subscribers) {
|
|
161
|
+
signalsContext?.unsubscribe(node);
|
|
162
|
+
}
|
|
163
|
+
root.removeChild(child);
|
|
164
|
+
if (!cache) {
|
|
165
|
+
void child.destroy();
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const evicted = cache.put(root.id, tag, { node: child, subscribers });
|
|
169
|
+
for (const entry of evicted) {
|
|
170
|
+
void entry.node.destroy();
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Re-attach a cached subtree to the outlet and re-mount it from its preserved
|
|
175
|
+
* scene plan, re-subscribing exactly the nodes that were subscribed before it
|
|
176
|
+
* was cached.
|
|
177
|
+
*/
|
|
178
|
+
restoreChild(root, entry, signalsContext) {
|
|
179
|
+
const child = entry.node;
|
|
180
|
+
root.addChild(child);
|
|
181
|
+
for (const node of entry.subscribers) {
|
|
182
|
+
signalsContext?.subscribe(node);
|
|
183
|
+
}
|
|
184
|
+
child.mount();
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Walk a subtree and collect the nodes currently registered as signal
|
|
188
|
+
* subscribers. Mirrors the subscription performed at init time in
|
|
189
|
+
* AreHTMLLifecycle (component nodes and root nodes) without depending on the
|
|
190
|
+
* concrete node classes — it simply intersects the subtree with the live
|
|
191
|
+
* subscriber registry.
|
|
192
|
+
*/
|
|
193
|
+
collectSubscribers(node, signalsContext) {
|
|
194
|
+
const result = [];
|
|
195
|
+
const queue = [node];
|
|
196
|
+
while (queue.length > 0) {
|
|
197
|
+
const current = queue.shift();
|
|
198
|
+
if (signalsContext.subscribers.has(current)) {
|
|
199
|
+
result.push(current);
|
|
200
|
+
}
|
|
201
|
+
queue.push(...current.children);
|
|
202
|
+
}
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
118
205
|
};
|
|
119
206
|
__decorateClass([
|
|
120
207
|
Are.Template,
|
|
121
208
|
__decorateParam(0, A_Inject(A_Caller)),
|
|
122
209
|
__decorateParam(1, A_Inject(A_Logger)),
|
|
123
|
-
__decorateParam(2, A_Inject(AreSignalsContext))
|
|
210
|
+
__decorateParam(2, A_Inject(AreSignalsContext)),
|
|
211
|
+
__decorateParam(3, A_Inject(A_SignalState))
|
|
124
212
|
], AreRoot.prototype, "template", 1);
|
|
125
213
|
__decorateClass([
|
|
126
214
|
Are.Signal,
|
|
127
215
|
__decorateParam(0, A_Inject(A_Caller)),
|
|
128
216
|
__decorateParam(1, A_Inject(A_SignalVector)),
|
|
129
217
|
__decorateParam(2, A_Inject(A_Logger)),
|
|
130
|
-
__decorateParam(3, A_Inject(AreSignalsContext))
|
|
218
|
+
__decorateParam(3, A_Inject(AreSignalsContext)),
|
|
219
|
+
__decorateParam(4, A_Inject(AreRootCache))
|
|
131
220
|
], AreRoot.prototype, "onSignal", 1);
|
|
132
221
|
AreRoot = __decorateClass([
|
|
133
222
|
A_Frame.Define({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/lib/AreRoot/AreRoot.component.ts"],"names":[],"mappings":"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","file":"AreRoot.component.mjs","sourcesContent":["import { A_Caller, A_Context, A_FormatterHelper, A_Inject, } from \"@adaas/a-concept\";\nimport { A_Frame } from \"@adaas/a-frame/core\";\nimport { A_Logger } from \"@adaas/a-utils/a-logger\";\nimport { A_SignalVector } from \"@adaas/a-utils/a-signal\";\nimport { Are, AreNode, AreSignals, AreSignalsMeta, AreSignalsContext } from \"@adaas/are\";\nimport { AreRoute } from \"@adaas/are-html/signals/AreRoute.signal\";\n\n\n@A_Frame.Define({\n namespace: 'a-are-html',\n description: 'The AreRoot component serves as the foundational entry point for the A-Concept Rendering Engine (ARE). It is responsible for initializing the rendering process, managing the root node of the component tree, and handling signal-based rendering logic. The AreRoot component processes incoming signals to determine which child components to render, allowing for dynamic and responsive UI updates based on application state and user interactions.'\n})\nexport class AreRoot extends Are {\n\n @Are.Template\n async template(\n @A_Inject(A_Caller) root: AreNode,\n @A_Inject(A_Logger) logger: A_Logger,\n @A_Inject(AreSignalsContext) signalsContext?: AreSignalsContext,\n ) {\n\n const rootId = root.id;\n\n // No routing config for this root — but still honour body content or\n // a 'default' attribute if one is present on the markup.\n if (signalsContext && !signalsContext.hasRoot(rootId)) {\n if (!root.content?.trim()) {\n // Fallback: legacy default= attribute\n const defaultMatch = root.markup?.match(/\\bdefault=[\"']([^\"']*)[\"']/);\n const defaultComponent = defaultMatch?.[1];\n if (defaultComponent) {\n root.setContent(`<${defaultComponent}></${defaultComponent}>`);\n }\n }\n // Body content (or none) — tokenizer picks it up without intervention\n return;\n }\n\n const currentRoute = AreRoute.default();\n\n let componentName: string | undefined;\n\n if (currentRoute) {\n const initialVector = new A_SignalVector([currentRoute]);\n\n // 1. Lookup via AreSignalsContext (per root-id conditions)\n let renderTarget = signalsContext?.findComponentByVector(rootId, initialVector);\n\n // 2. Fall back to global AreSignalsMeta, pool-filtered.\n // IMPORTANT: pass the pool *into* the lookup so it can skip over\n // out-of-pool matches (e.g. a meta-outlet component whose condition\n // also matches the same vector) and find the highest-priority match\n // that this outlet can actually render. Filtering only after the\n // fact would mask valid in-pool matches and surface the outlet's\n // default instead.\n if (!renderTarget) {\n const signalsMeta = A_Context.meta<AreSignalsMeta>(AreSignals);\n const pool = signalsContext?.getComponentById(rootId);\n const metaTarget = signalsMeta?.findComponentByVector(\n initialVector,\n pool?.length ? pool : undefined,\n );\n if (metaTarget && (!pool?.length || pool.includes(metaTarget))) {\n renderTarget = metaTarget;\n }\n }\n\n if (renderTarget?.name) {\n componentName = A_FormatterHelper.toKebabCase(renderTarget.name);\n }\n }\n\n // 3. Fall back to body content (the nodes already placed inside the\n // <are-root> tag act as the default). No setContent() call needed —\n // the tokenizer will process root.content as-is.\n if (!componentName) {\n if (root.content?.trim()) {\n return;\n }\n }\n // 3.5. Fall back to AreSignalsContext default component for this root.\n if (!componentName) {\n const defaultComp = signalsContext?.getDefault(rootId);\n if (defaultComp?.name) {\n componentName = A_FormatterHelper.toKebabCase(defaultComp.name);\n }\n }\n // 4. Last resort: legacy default= attribute on the markup.\n if (!componentName) {\n const defaultMatch = root.markup?.match(/\\bdefault=[\"']([^\"']*)[\"']/);\n componentName = defaultMatch?.[1];\n }\n\n if (!componentName) {\n logger.warning('AreRoot: No component found for initial render. Provide body content, a route condition, or a \"default\" attribute.');\n return;\n }\n\n root.setContent(`<${componentName}></${componentName}>`);\n }\n\n\n @Are.Signal\n async onSignal(\n @A_Inject(A_Caller) root: AreNode,\n @A_Inject(A_SignalVector) vector: A_SignalVector,\n @A_Inject(A_Logger) logger: A_Logger,\n @A_Inject(AreSignalsContext) signalsContext?: AreSignalsContext,\n ) {\n const rootId = root.id;\n\n // No routing config for this root — signals do not affect its content\n if (signalsContext && !signalsContext.hasRoot(rootId)) {\n return;\n }\n\n // 1. Try root-specific lookup via AreSignalsContext (keyed by the are-root's id attribute)\n let renderTarget = signalsContext?.findComponentByVector(rootId, vector);\n\n // 2. Fall back to global AreSignalsMeta lookup, restricted to this\n // outlet's pool. Passing the pool *into* the lookup is critical:\n // without it, the first globally matching component wins and may\n // belong to a different outlet (e.g. AisRequirementsPanel for the\n // meta-outlet matching AisEditorCursorScope) — the pool check then\n // rejects it and the outlet falls back to default, hiding a valid\n // in-pool match (e.g. AisDiagramTab matching AisSetPrimaryDisplay).\n if (!renderTarget) {\n const signalsMeta = A_Context.meta<AreSignalsMeta>(AreSignals);\n const pool = signalsContext?.getComponentById(rootId);\n const metaTarget = signalsMeta?.findComponentByVector(\n vector,\n pool?.length ? pool : undefined,\n );\n if (metaTarget && (!pool?.length || pool.includes(metaTarget))) {\n renderTarget = metaTarget;\n }\n }\n\n const def = signalsContext?.getDefault(rootId);\n const componentName = renderTarget?.name\n ? A_FormatterHelper.toKebabCase(renderTarget.name)\n : def?.name\n ? A_FormatterHelper.toKebabCase(def.name)\n : undefined;\n\n // No matching condition for this signal vector and no default — clear the outlet.\n if (!componentName) {\n for (let i = 0; i < root.children.length; i++) {\n const child = root.children[i];\n signalsContext?.unsubscribe(child);\n child.unmount();\n child.destroy();\n root.removeChild(child);\n }\n root.setContent('');\n return;\n }\n\n // Guard: if the outlet already shows the same component, do nothing.\n // Prevents infinite remount loops when a non-routing signal carries a\n // stale routing signal in the accumulated A_SignalState vector.\n // node.type is the kebab-case tag name — the most direct and reliable\n // identifier (no constructor-name resolution, no proxy wrapping issues).\n const currentChild = root.children[0] as AreNode | undefined;\n if (currentChild?.type === componentName) {\n return;\n }\n\n root.setContent(`<${componentName}></${componentName}>`);\n\n // Unsubscribe old children BEFORE destroying them.\n // Without this, AreSignals.handleSignalVector keeps iterating stale\n // (scope-less) nodes on every subsequent signal and throws an error.\n for (let i = 0; i < root.children.length; i++) {\n const child = root.children[i];\n signalsContext?.unsubscribe(child);\n child.unmount();\n child.destroy();\n root.removeChild(child);\n }\n\n\n root.tokenize();\n\n for (let i = 0; i < root.children.length; i++) {\n const child = root.children[i];\n child.init();\n\n const res = child.load();\n if (res instanceof Promise) {\n await res;\n }\n child.transform();\n\n child.compile();\n child.mount();\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/AreRoot/AreRoot.component.ts"],"names":[],"mappings":"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","file":"AreRoot.component.mjs","sourcesContent":["import { A_Caller, A_Context, A_FormatterHelper, A_Inject, A_TYPES__Ctor } from \"@adaas/a-concept\";\nimport { A_Frame } from \"@adaas/a-frame/core\";\nimport { A_Logger } from \"@adaas/a-utils/a-logger\";\nimport { A_Signal, A_SignalState, A_SignalVector } from \"@adaas/a-utils/a-signal\";\nimport { Are, AreNode, AreSignals, AreSignalsMeta, AreSignalsContext } from \"@adaas/are\";\nimport { AreRoute } from \"@adaas/are-html/signals/AreRoute.signal\";\nimport { AreRootCache, AreRootCacheEntry } from \"./AreRootCache.context\";\n\n\n@A_Frame.Define({\n namespace: 'a-are-html',\n description: 'The AreRoot component serves as the foundational entry point for the A-Concept Rendering Engine (ARE). It is responsible for initializing the rendering process, managing the root node of the component tree, and handling signal-based rendering logic. The AreRoot component processes incoming signals to determine which child components to render, allowing for dynamic and responsive UI updates based on application state and user interactions.'\n})\nexport class AreRoot extends Are {\n\n @Are.Template\n async template(\n @A_Inject(A_Caller) root: AreNode,\n @A_Inject(A_Logger) logger: A_Logger,\n @A_Inject(AreSignalsContext) signalsContext?: AreSignalsContext,\n @A_Inject(A_SignalState) signalState?: A_SignalState,\n ) {\n\n const rootId = root.id;\n\n // No routing config for this root — but still honour body content or\n // a 'default' attribute if one is present on the markup.\n if (signalsContext && !signalsContext.hasRoot(rootId)) {\n if (!root.content?.trim()) {\n // Fallback: legacy default= attribute\n const defaultMatch = root.markup?.match(/\\bdefault=[\"']([^\"']*)[\"']/);\n const defaultComponent = defaultMatch?.[1];\n if (defaultComponent) {\n root.setContent(`<${defaultComponent}></${defaultComponent}>`);\n }\n }\n // Body content (or none) — tokenizer picks it up without intervention\n return;\n }\n\n // Select from the ACCUMULATED signal state (every signal dispatched so\n // far), not just the current URL route. Outlets keyed on domain signals\n // (e.g. a primary-display selector) must reflect the live vector the\n // moment they mount — even when they mount AFTER the routing signal was\n // dispatched (a nested outlet inside a just-rendered parent). Using the\n // same vector + lookup as onSignal keeps initial render and subsequent\n // updates consistent.\n const initialVector = this.buildInitialVector(signalState);\n const renderTarget = this.matchComponent(rootId, initialVector, signalsContext);\n\n let componentName: string | undefined = renderTarget?.name\n ? A_FormatterHelper.toKebabCase(renderTarget.name)\n : undefined;\n\n // 3. Fall back to body content (the nodes already placed inside the\n // <are-root> tag act as the default). No setContent() call needed —\n // the tokenizer will process root.content as-is.\n if (!componentName) {\n if (root.content?.trim()) {\n return;\n }\n }\n // 3.5. Fall back to AreSignalsContext default component for this root.\n if (!componentName) {\n const defaultComp = signalsContext?.getDefault(rootId);\n if (defaultComp?.name) {\n componentName = A_FormatterHelper.toKebabCase(defaultComp.name);\n }\n }\n // 4. Last resort: legacy default= attribute on the markup.\n if (!componentName) {\n const defaultMatch = root.markup?.match(/\\bdefault=[\"']([^\"']*)[\"']/);\n componentName = defaultMatch?.[1];\n }\n\n if (!componentName) {\n logger.warning('AreRoot: No component found for initial render. Provide body content, a route condition, or a \"default\" attribute.');\n return;\n }\n\n root.setContent(`<${componentName}></${componentName}>`);\n }\n\n\n @Are.Signal\n async onSignal(\n @A_Inject(A_Caller) root: AreNode,\n @A_Inject(A_SignalVector) vector: A_SignalVector,\n @A_Inject(A_Logger) logger: A_Logger,\n @A_Inject(AreSignalsContext) signalsContext?: AreSignalsContext,\n @A_Inject(AreRootCache) cache?: AreRootCache,\n ) {\n const rootId = root.id;\n\n // No routing config for this root — signals do not affect its content\n if (signalsContext && !signalsContext.hasRoot(rootId)) {\n return;\n }\n\n // Resolve the target component for the incoming vector using the SAME\n // lookup the initial template render uses (root-id conditions first,\n // then the global pool-filtered meta map).\n const renderTarget = this.matchComponent(rootId, vector, signalsContext);\n\n const def = signalsContext?.getDefault(rootId);\n const componentName = renderTarget?.name\n ? A_FormatterHelper.toKebabCase(renderTarget.name)\n : def?.name\n ? A_FormatterHelper.toKebabCase(def.name)\n : undefined;\n\n // No matching condition for this signal vector and no default — clear the outlet.\n if (!componentName) {\n for (const child of [...root.children]) {\n this.stashChild(root, child, signalsContext, cache);\n }\n root.setContent('');\n return;\n }\n\n // Guard: if the outlet already shows the same component, do nothing.\n // Prevents infinite remount loops when a non-routing signal carries a\n // stale routing signal in the accumulated A_SignalState vector.\n // node.type is the kebab-case tag name — the most direct and reliable\n // identifier (no constructor-name resolution, no proxy wrapping issues).\n const currentChild = root.children[0] as AreNode | undefined;\n if (currentChild?.type === componentName) {\n return;\n }\n\n // Stash the currently displayed children so routing back to them can be\n // re-injected instantly from the cache (they are unmounted + detached but\n // NOT destroyed). Falls back to full teardown when no cache is available.\n for (const child of [...root.children]) {\n this.stashChild(root, child, signalsContext, cache);\n }\n\n root.setContent(`<${componentName}></${componentName}>`);\n\n // Fast path: a previously rendered subtree for this component is cached —\n // re-attach it and re-mount from the preserved scene plan, skipping the\n // expensive tokenize/init/load/transform/compile pipeline.\n const cached = cache?.take(root.id, componentName);\n if (cached) {\n this.restoreChild(root, cached, signalsContext);\n return;\n }\n\n // Slow path: build the component subtree from scratch.\n root.tokenize();\n\n for (let i = 0; i < root.children.length; i++) {\n const child = root.children[i];\n child.init();\n\n const res = child.load();\n if (res instanceof Promise) {\n await res;\n }\n child.transform();\n\n child.compile();\n child.mount();\n }\n }\n\n /**\n * Resolves the component a vector should render for the given root, mirroring\n * the priority used everywhere in the routing system:\n * 1. Root-specific conditions registered on AreSignalsContext.\n * 2. The global AreSignalsMeta map, restricted to this outlet's pool.\n *\n * Passing the pool *into* the meta lookup is critical: without it, the first\n * globally matching component wins and may belong to a different outlet\n * (e.g. AisRequirementsPanel for the meta-outlet matching\n * AisEditorCursorScope) — the pool check would then reject it and the outlet\n * would fall back to its default, hiding a valid in-pool match (e.g.\n * AisDiagramTab matching AisSetPrimaryDisplay).\n *\n * Returns `undefined` when nothing matches — callers decide whether to use a\n * configured default, body content, or clear the outlet.\n */\n protected matchComponent(\n rootId: string,\n vector: A_SignalVector | undefined,\n signalsContext?: AreSignalsContext,\n ): A_TYPES__Ctor<Are> | undefined {\n if (!vector) return undefined;\n\n // 1. Root-specific conditions.\n let renderTarget = signalsContext?.findComponentByVector(rootId, vector);\n\n // 2. Global pool-filtered meta map.\n if (!renderTarget) {\n const signalsMeta = A_Context.meta<AreSignalsMeta>(AreSignals);\n const pool = signalsContext?.getComponentById(rootId);\n const metaTarget = signalsMeta?.findComponentByVector(\n vector,\n pool?.length ? pool : undefined,\n rootId,\n );\n if (metaTarget && (!pool?.length || pool.includes(metaTarget))) {\n renderTarget = metaTarget;\n }\n }\n\n return renderTarget as A_TYPES__Ctor<Are> | undefined;\n }\n\n /**\n * Builds the vector used for the INITIAL render. It is seeded from the\n * accumulated signal state (every signal dispatched on the bus so far) so a\n * freshly-mounted outlet reflects the live application state immediately,\n * not just on the next signal tick. The current URL route is appended when\n * no AreRoute is already present in the state, so route-driven outlets still\n * resolve on the very first paint (before AreRouteWatcher has dispatched).\n */\n protected buildInitialVector(signalState?: A_SignalState): A_SignalVector {\n const signals: A_Signal[] = [];\n\n if (signalState) {\n for (const signal of signalState.toVector()) {\n if (signal) signals.push(signal);\n }\n }\n\n if (!signals.some(signal => signal instanceof AreRoute)) {\n try {\n const currentRoute = AreRoute.default();\n if (currentRoute) signals.push(currentRoute);\n } catch {\n // Non-browser environment (no document) — route is simply absent.\n }\n }\n\n return new A_SignalVector(signals);\n }\n\n /**\n * Detach a displayed child subtree from the outlet and stash it in the cache\n * for fast re-injection later. The subtree is unmounted (its scene plan is\n * preserved) and deregistered from the root scope, but NOT destroyed. The\n * nodes that were subscribed to the signal bus are unsubscribed while cached\n * so the detached DOM never reacts to signals, and recorded so they can be\n * re-subscribed verbatim on restore.\n *\n * When no cache is available, or the LRU evicts an entry, the affected\n * subtree is fully destroyed.\n */\n protected stashChild(\n root: AreNode,\n child: AreNode,\n signalsContext: AreSignalsContext | undefined,\n cache: AreRootCache | undefined,\n ): void {\n const tag = child.type;\n\n child.unmount();\n\n // Collect exactly the nodes that are currently subscribed within this\n // subtree, then unsubscribe them. Without this, AreSignals keeps\n // delivering vectors to a detached subtree that would update reverted\n // DOM (unmount does not deactivate the scene).\n const subscribers = signalsContext\n ? this.collectSubscribers(child, signalsContext)\n : [];\n for (const node of subscribers) {\n signalsContext?.unsubscribe(node);\n }\n\n // Deregister from the root scope (the \"deregister node from parent\").\n root.removeChild(child);\n\n if (!cache) {\n void child.destroy();\n return;\n }\n\n const evicted = cache.put(root.id, tag, { node: child, subscribers });\n for (const entry of evicted) {\n // Evicted entries are already unmounted + unsubscribed + detached.\n void entry.node.destroy();\n }\n }\n\n /**\n * Re-attach a cached subtree to the outlet and re-mount it from its preserved\n * scene plan, re-subscribing exactly the nodes that were subscribed before it\n * was cached.\n */\n protected restoreChild(\n root: AreNode,\n entry: AreRootCacheEntry,\n signalsContext: AreSignalsContext | undefined,\n ): void {\n const child = entry.node;\n\n root.addChild(child);\n\n for (const node of entry.subscribers) {\n signalsContext?.subscribe(node);\n }\n\n child.mount();\n }\n\n /**\n * Walk a subtree and collect the nodes currently registered as signal\n * subscribers. Mirrors the subscription performed at init time in\n * AreHTMLLifecycle (component nodes and root nodes) without depending on the\n * concrete node classes — it simply intersects the subtree with the live\n * subscriber registry.\n */\n protected collectSubscribers(\n node: AreNode,\n signalsContext: AreSignalsContext,\n ): AreNode[] {\n const result: AreNode[] = [];\n const queue: AreNode[] = [node];\n while (queue.length > 0) {\n const current = queue.shift()!;\n if (signalsContext.subscribers.has(current)) {\n result.push(current);\n }\n queue.push(...current.children);\n }\n return result;\n }\n}\n"]}
|