@adaas/are-html 0.0.20 → 0.0.22
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/.conf/tsconfig.base.json +1 -0
- package/.conf/tsconfig.browser.json +1 -0
- package/.conf/tsconfig.node.json +1 -0
- package/dist/browser/index.d.mts +206 -7
- package/dist/browser/index.mjs +527 -65
- package/dist/browser/index.mjs.map +1 -1
- package/dist/node/directives/AreDirectiveFor.directive.d.mts +44 -1
- package/dist/node/directives/AreDirectiveFor.directive.d.ts +44 -1
- package/dist/node/directives/AreDirectiveFor.directive.js +102 -6
- package/dist/node/directives/AreDirectiveFor.directive.js.map +1 -1
- package/dist/node/directives/AreDirectiveFor.directive.mjs +102 -6
- 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/engine/AreHTML.lifecycle.d.mts +8 -1
- package/dist/node/engine/AreHTML.lifecycle.d.ts +8 -1
- package/dist/node/engine/AreHTML.lifecycle.js +46 -3
- package/dist/node/engine/AreHTML.lifecycle.js.map +1 -1
- package/dist/node/engine/AreHTML.lifecycle.mjs +46 -3
- package/dist/node/engine/AreHTML.lifecycle.mjs.map +1 -1
- package/dist/node/helpers/AreScheduler.helper.d.mts +39 -0
- package/dist/node/helpers/AreScheduler.helper.d.ts +39 -0
- package/dist/node/helpers/AreScheduler.helper.js +40 -0
- package/dist/node/helpers/AreScheduler.helper.js.map +1 -0
- package/dist/node/helpers/AreScheduler.helper.mjs +40 -0
- package/dist/node/helpers/AreScheduler.helper.mjs.map +1 -0
- 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 +138 -49
- package/dist/node/lib/AreRoot/AreRoot.component.js.map +1 -1
- package/dist/node/lib/AreRoot/AreRoot.component.mjs +140 -51
- 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/dashboard/dist/index.html +1 -1
- package/examples/dashboard/dist/{mq19zxz4-mnlgmd.js → mqh9ryml-xat335.js} +1922 -1316
- package/examples/dashboard/src/concept.ts +3 -2
- package/examples/for-perf/concept.ts +45 -0
- package/examples/for-perf/containers/UI.container.ts +161 -0
- package/examples/for-perf/dist/index.html +270 -0
- package/examples/for-perf/dist/mqh9ryde-m243t8.js +15223 -0
- package/examples/for-perf/dist/mqh9ryfo-6a8d0o.js +15223 -0
- package/examples/for-perf/dist/mqh9ryfq-4pf5cv.js +15223 -0
- package/examples/for-perf/public/index.html +270 -0
- package/examples/for-perf/src/components/PerfApp.component.ts +37 -0
- package/examples/for-perf/src/components/PerfControls.component.ts +34 -0
- package/examples/for-perf/src/components/PerfGrid.component.ts +225 -0
- package/examples/for-perf/src/components/PerfHeader.component.ts +34 -0
- package/examples/for-perf/src/components/PerfStats.component.ts +43 -0
- package/examples/for-perf/src/concept.ts +94 -0
- package/examples/jumpstart/dist/index.html +1 -1
- package/examples/jumpstart/dist/{mq1a0fv0-ccgtz6.js → mq7mgf58-vbf07e.js} +895 -521
- package/examples/signal-routing/dist/index.html +1 -1
- package/examples/signal-routing/dist/{mq1bzrik-4lec86.js → mqh9ryc9-dkcbkx.js} +2024 -1300
- package/examples/signal-routing/src/components/SettingsPage.component.ts +39 -0
- package/examples/signal-routing/src/concept.ts +2 -0
- package/jest.config.ts +1 -0
- package/package.json +10 -9
- package/src/directives/AreDirectiveFor.directive.ts +185 -12
- 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/engine/AreHTML.lifecycle.ts +83 -6
- package/src/helpers/AreScheduler.helper.ts +61 -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 +205 -72
- package/src/lib/AreRoot/AreRootCache.context.ts +133 -0
- package/tsconfig.json +1 -0
package/dist/browser/index.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { AreStore, AreScene, AreSyntax, AreCompiler, AreInterpreter, AreInstructionDefaultNames, AreNodeFeatures, AreContext, AreLifecycle, AreSignalsContext, AreAttributeFeatures, Are, AreNode, AreDeclaration, AreAttribute,
|
|
1
|
+
import { AreStore, AreScene, AreSyntax, AreCompiler, AreInterpreter, AreInstructionDefaultNames, AreNodeFeatures, AreContext, AreLifecycle, AreSignalsContext, AreAttributeFeatures, Are, AreCompilerError, AreNode, AreDeclaration, AreAttribute, AreMutation, AreSignal, AreInterpreterError, AreTokenizer, AreTransformer, AreEngine, AreSignals, AreEvent } from '@adaas/are';
|
|
2
2
|
import { A_Frame } from '@adaas/a-frame/core';
|
|
3
3
|
import { A_Inject, A_Caller, A_Feature, A_Meta, A_Scope, A_Dependency, A_Component, A_Context, A_ComponentMeta, A_FormatterHelper, A_Fragment } from '@adaas/a-concept';
|
|
4
4
|
import { A_Logger } from '@adaas/a-utils/a-logger';
|
|
5
5
|
import { A_ExecutionContext } from '@adaas/a-utils/a-execution';
|
|
6
6
|
import { A_Route } from '@adaas/a-utils/a-route';
|
|
7
7
|
import { A_ServiceFeatures } from '@adaas/a-utils/a-service';
|
|
8
|
-
import { A_SignalVector } from '@adaas/a-utils/a-signal';
|
|
8
|
+
import { A_SignalState, A_SignalVector } from '@adaas/a-utils/a-signal';
|
|
9
9
|
|
|
10
10
|
var __defProp = Object.defineProperty;
|
|
11
11
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -207,7 +207,8 @@ var AreHTMLInstructions = {
|
|
|
207
207
|
AddStyle: "_AreHTML_AddStyle",
|
|
208
208
|
AddListener: "_AreHTML_AddListener",
|
|
209
209
|
AddInterpolation: "_AreHTML_AddInterpolation",
|
|
210
|
-
AddComment: "_AreHTML_AddComment"
|
|
210
|
+
AddComment: "_AreHTML_AddComment",
|
|
211
|
+
HideElement: "_AreHTML_HideElement"
|
|
211
212
|
};
|
|
212
213
|
|
|
213
214
|
// src/instructions/AddComment.instruction.ts
|
|
@@ -235,6 +236,44 @@ var AreDirectiveContext = class extends A_ExecutionContext {
|
|
|
235
236
|
this.scope = {};
|
|
236
237
|
}
|
|
237
238
|
};
|
|
239
|
+
|
|
240
|
+
// src/helpers/AreScheduler.helper.ts
|
|
241
|
+
var AreSchedulerHelper = class {
|
|
242
|
+
/**
|
|
243
|
+
* High-resolution wall-clock time in milliseconds. Uses `performance.now()`
|
|
244
|
+
* when available (monotonic, sub-millisecond), falling back to `Date.now()`.
|
|
245
|
+
*/
|
|
246
|
+
static now() {
|
|
247
|
+
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Schedule `fn` to run on the next macrotask.
|
|
251
|
+
*
|
|
252
|
+
* `MessageChannel` yields a true macrotask without the ~4ms clamp that nested
|
|
253
|
+
* `setTimeout(0)` calls incur, so the browser can paint between chunks with
|
|
254
|
+
* minimal scheduling overhead. Falls back to `setTimeout` in non-DOM
|
|
255
|
+
* environments (e.g. tests / SSR).
|
|
256
|
+
*/
|
|
257
|
+
static scheduleMacrotask(fn) {
|
|
258
|
+
if (typeof MessageChannel === "undefined") {
|
|
259
|
+
setTimeout(fn, 0);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (!this._channel) {
|
|
263
|
+
this._channel = new MessageChannel();
|
|
264
|
+
this._channel.port1.onmessage = () => {
|
|
265
|
+
const next = this._queue.shift();
|
|
266
|
+
if (next) next();
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
this._queue.push(fn);
|
|
270
|
+
this._channel.port2.postMessage(null);
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
/** FIFO queue of callbacks waiting for their posted macrotask to fire. */
|
|
274
|
+
AreSchedulerHelper._queue = [];
|
|
275
|
+
|
|
276
|
+
// src/directives/AreDirectiveFor.directive.ts
|
|
238
277
|
var AreDirectiveFor = class extends AreDirective {
|
|
239
278
|
transform(attribute, scope, store, scene, logger, ...args) {
|
|
240
279
|
logger.debug(`[Transform] directive $FOR for <${attribute.owner.aseid.toString()}>`);
|
|
@@ -263,11 +302,30 @@ var AreDirectiveFor = class extends AreDirective {
|
|
|
263
302
|
scene.unPlan(hostInstruction);
|
|
264
303
|
}
|
|
265
304
|
update(attribute, store, scene, ...args) {
|
|
305
|
+
let state = AreDirectiveFor.renderState.get(attribute);
|
|
306
|
+
if (!state) {
|
|
307
|
+
state = { running: false, pending: false };
|
|
308
|
+
AreDirectiveFor.renderState.set(attribute, state);
|
|
309
|
+
}
|
|
310
|
+
if (state.running) {
|
|
311
|
+
state.pending = true;
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
return this.performUpdate(attribute, store, scene, state);
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Core of the `$for` update: re-diff the source array against the current
|
|
318
|
+
* children, reconcile reused/removed items, then mount the new ones (small
|
|
319
|
+
* lists synchronously, large lists time-sliced). Never called while another
|
|
320
|
+
* pass for the same `$for` is in flight (see `update`).
|
|
321
|
+
*/
|
|
322
|
+
performUpdate(attribute, store, scene, state) {
|
|
266
323
|
const { key, index, arrayExpr, trackExpr } = this.parseExpression(attribute.content);
|
|
267
324
|
const newArray = this.resolveArray(store, arrayExpr, attribute.content);
|
|
268
325
|
const owner = attribute.owner;
|
|
269
326
|
const currentChildren = [...owner.children];
|
|
270
327
|
attribute.value = newArray;
|
|
328
|
+
const attached = this.isAttached(owner);
|
|
271
329
|
const computeKey = this.makeKeyFn(key, index, trackExpr);
|
|
272
330
|
const childByKey = /* @__PURE__ */ new Map();
|
|
273
331
|
const remaining = /* @__PURE__ */ new Set();
|
|
@@ -278,7 +336,7 @@ var AreDirectiveFor = class extends AreDirective {
|
|
|
278
336
|
childByKey.set(k, child);
|
|
279
337
|
remaining.add(child);
|
|
280
338
|
}
|
|
281
|
-
const
|
|
339
|
+
const toCreate = [];
|
|
282
340
|
for (let i = 0; i < newArray.length; i++) {
|
|
283
341
|
const item = newArray[i];
|
|
284
342
|
const k = computeKey(item, i);
|
|
@@ -296,20 +354,73 @@ var AreDirectiveFor = class extends AreDirective {
|
|
|
296
354
|
[index || "index"]: i
|
|
297
355
|
};
|
|
298
356
|
} else {
|
|
299
|
-
|
|
300
|
-
newOnes.push(itemNode);
|
|
357
|
+
toCreate.push({ item, idx: i });
|
|
301
358
|
}
|
|
302
359
|
}
|
|
303
360
|
for (const child of remaining) {
|
|
304
|
-
child.unmount();
|
|
361
|
+
if (attached) child.unmount();
|
|
305
362
|
owner.removeChild(child);
|
|
306
363
|
}
|
|
307
|
-
|
|
364
|
+
const createItem = (desc) => {
|
|
365
|
+
const child = this.spawnItemNode(attribute.template, owner, key, index, desc.item, desc.idx);
|
|
308
366
|
child.transform();
|
|
309
367
|
child.compile();
|
|
310
|
-
child.mount();
|
|
368
|
+
if (attached) child.mount();
|
|
369
|
+
};
|
|
370
|
+
if (toCreate.length <= AreDirectiveFor.SYNC_THRESHOLD) {
|
|
371
|
+
for (const desc of toCreate) createItem(desc);
|
|
372
|
+
return this.finishUpdate(attribute, store, scene, state);
|
|
373
|
+
}
|
|
374
|
+
state.running = true;
|
|
375
|
+
let cursor = 0;
|
|
376
|
+
const processChunk = () => {
|
|
377
|
+
try {
|
|
378
|
+
const start = AreSchedulerHelper.now();
|
|
379
|
+
while (cursor < toCreate.length) {
|
|
380
|
+
createItem(toCreate[cursor]);
|
|
381
|
+
cursor++;
|
|
382
|
+
if (AreSchedulerHelper.now() - start >= AreDirectiveFor.CHUNK_BUDGET_MS) break;
|
|
383
|
+
}
|
|
384
|
+
} catch (error) {
|
|
385
|
+
state.running = false;
|
|
386
|
+
state.pending = false;
|
|
387
|
+
throw error;
|
|
388
|
+
}
|
|
389
|
+
if (cursor < toCreate.length) {
|
|
390
|
+
return new Promise((resolve) => {
|
|
391
|
+
AreSchedulerHelper.scheduleMacrotask(() => resolve(processChunk()));
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
return this.finishUpdate(attribute, store, scene, state);
|
|
395
|
+
};
|
|
396
|
+
return processChunk();
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Completes an update pass. If another update() arrived while a chunked
|
|
400
|
+
* render was streaming, run exactly one more pass now from the latest store
|
|
401
|
+
* value so the final DOM always reflects the most recent data.
|
|
402
|
+
*/
|
|
403
|
+
finishUpdate(attribute, store, scene, state) {
|
|
404
|
+
state.running = false;
|
|
405
|
+
if (state.pending) {
|
|
406
|
+
state.pending = false;
|
|
407
|
+
return this.performUpdate(attribute, store, scene, state);
|
|
311
408
|
}
|
|
312
409
|
}
|
|
410
|
+
/**
|
|
411
|
+
* Walks the node's ancestor chain (inclusive) and reports whether the
|
|
412
|
+
* whole path is currently active — i.e. the subtree is actually rendered
|
|
413
|
+
* into the DOM. A single inactive ancestor scene (e.g. a `$if` whose
|
|
414
|
+
* condition is false) means the subtree is detached.
|
|
415
|
+
*/
|
|
416
|
+
isAttached(node) {
|
|
417
|
+
let current = node;
|
|
418
|
+
while (current) {
|
|
419
|
+
if (current.scene?.isInactive) return false;
|
|
420
|
+
current = current.parent;
|
|
421
|
+
}
|
|
422
|
+
return true;
|
|
423
|
+
}
|
|
313
424
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
314
425
|
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
315
426
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -454,6 +565,29 @@ var AreDirectiveFor = class extends AreDirective {
|
|
|
454
565
|
return itemNode;
|
|
455
566
|
}
|
|
456
567
|
};
|
|
568
|
+
/**
|
|
569
|
+
* Lists whose number of NEW item nodes is at or below this threshold render
|
|
570
|
+
* fully synchronously — byte-for-byte the previous behavior. Typical UIs
|
|
571
|
+
* (menus, small tables) are therefore completely unaffected; only genuinely
|
|
572
|
+
* large lists pay the (tiny) scheduling cost to keep the main thread responsive.
|
|
573
|
+
*/
|
|
574
|
+
AreDirectiveFor.SYNC_THRESHOLD = 100;
|
|
575
|
+
/**
|
|
576
|
+
* Per-chunk time budget (ms). During a large-list render we mount item nodes
|
|
577
|
+
* until this much time has elapsed, then yield to the browser so it can paint
|
|
578
|
+
* and process input before the next chunk. ~16ms targets one animation frame.
|
|
579
|
+
*/
|
|
580
|
+
AreDirectiveFor.CHUNK_BUDGET_MS = 16;
|
|
581
|
+
/**
|
|
582
|
+
* Per-attribute serialization state. A new update() that arrives while a
|
|
583
|
+
* chunked render of the SAME `$for` is still in flight does NOT start a second
|
|
584
|
+
* concurrent pass (which could interleave mutations on the shared children
|
|
585
|
+
* list); instead it marks `pending` and the in-flight run re-runs once more
|
|
586
|
+
* with the latest data when it finishes. This guarantees the children list is
|
|
587
|
+
* only ever mutated by one pass at a time and the final state always reflects
|
|
588
|
+
* the most recent store value.
|
|
589
|
+
*/
|
|
590
|
+
AreDirectiveFor.renderState = /* @__PURE__ */ new WeakMap();
|
|
457
591
|
__decorateClass([
|
|
458
592
|
AreDirective.Transform,
|
|
459
593
|
__decorateParam(0, A_Inject(A_Caller)),
|
|
@@ -556,6 +690,79 @@ AreDirectiveIf = __decorateClass([
|
|
|
556
690
|
}),
|
|
557
691
|
AreDirective.Priority(2)
|
|
558
692
|
], AreDirectiveIf);
|
|
693
|
+
var HideElementInstruction = class extends AreMutation {
|
|
694
|
+
constructor(parent, props) {
|
|
695
|
+
if ("aseid" in props) {
|
|
696
|
+
super(props);
|
|
697
|
+
} else {
|
|
698
|
+
super(AreHTMLInstructions.HideElement, parent, props);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
HideElementInstruction = __decorateClass([
|
|
703
|
+
A_Frame.Define({
|
|
704
|
+
namespace: "a-are-html",
|
|
705
|
+
description: 'Toggles the visibility of an existing element by setting its inline display to "none" on apply and restoring the previous inline display on revert. Used by the $show directive to hide/show an element without unmounting it, preserving its subtree, listeners and scene state.'
|
|
706
|
+
})
|
|
707
|
+
], HideElementInstruction);
|
|
708
|
+
var AreDirectiveShow = class extends AreDirective {
|
|
709
|
+
transform(attribute, logger, ...args) {
|
|
710
|
+
logger.debug(`[Transform] directive $SHOW for <${attribute.owner.aseid.toString()}> (no structural change)`);
|
|
711
|
+
}
|
|
712
|
+
compile(attribute, store, scene, syntax, directiveContext, ...args) {
|
|
713
|
+
const visible = !!syntax.evaluate(attribute.content, store, {
|
|
714
|
+
...directiveContext?.scope || {}
|
|
715
|
+
});
|
|
716
|
+
attribute.value = visible;
|
|
717
|
+
const hide = new HideElementInstruction(scene.host, {});
|
|
718
|
+
attribute.cache = hide;
|
|
719
|
+
if (!visible)
|
|
720
|
+
scene.plan(hide);
|
|
721
|
+
}
|
|
722
|
+
update(attribute, store, scene, syntax, directiveContext, ...args) {
|
|
723
|
+
const previous = !!attribute.value;
|
|
724
|
+
const next = !!syntax.evaluate(attribute.content, store, {
|
|
725
|
+
...directiveContext?.scope || {}
|
|
726
|
+
});
|
|
727
|
+
attribute.value = next;
|
|
728
|
+
if (previous === next) return;
|
|
729
|
+
const hide = attribute.cache;
|
|
730
|
+
if (!hide) return;
|
|
731
|
+
if (next)
|
|
732
|
+
scene.unPlan(hide);
|
|
733
|
+
else
|
|
734
|
+
scene.plan(hide);
|
|
735
|
+
attribute.owner.interpret();
|
|
736
|
+
}
|
|
737
|
+
};
|
|
738
|
+
__decorateClass([
|
|
739
|
+
AreDirective.Transform,
|
|
740
|
+
__decorateParam(0, A_Inject(A_Caller)),
|
|
741
|
+
__decorateParam(1, A_Inject(A_Logger))
|
|
742
|
+
], AreDirectiveShow.prototype, "transform", 1);
|
|
743
|
+
__decorateClass([
|
|
744
|
+
AreDirective.Compile,
|
|
745
|
+
__decorateParam(0, A_Inject(A_Caller)),
|
|
746
|
+
__decorateParam(1, A_Inject(AreStore)),
|
|
747
|
+
__decorateParam(2, A_Inject(AreScene)),
|
|
748
|
+
__decorateParam(3, A_Inject(AreSyntax)),
|
|
749
|
+
__decorateParam(4, A_Inject(AreDirectiveContext))
|
|
750
|
+
], AreDirectiveShow.prototype, "compile", 1);
|
|
751
|
+
__decorateClass([
|
|
752
|
+
AreDirective.Update,
|
|
753
|
+
__decorateParam(0, A_Inject(A_Caller)),
|
|
754
|
+
__decorateParam(1, A_Inject(AreStore)),
|
|
755
|
+
__decorateParam(2, A_Inject(AreScene)),
|
|
756
|
+
__decorateParam(3, A_Inject(AreSyntax)),
|
|
757
|
+
__decorateParam(4, A_Inject(AreDirectiveContext))
|
|
758
|
+
], AreDirectiveShow.prototype, "update", 1);
|
|
759
|
+
AreDirectiveShow = __decorateClass([
|
|
760
|
+
A_Frame.Define({
|
|
761
|
+
namespace: "a-are-html",
|
|
762
|
+
description: "Built-in $show directive. Toggles an element's visibility by flipping its inline display value based on a store expression, keeping the element mounted (subtree, listeners and scene state preserved) instead of unmounting it like $if."
|
|
763
|
+
}),
|
|
764
|
+
AreDirective.Priority(3)
|
|
765
|
+
], AreDirectiveShow);
|
|
559
766
|
var AddAttributeInstruction = class extends AreMutation {
|
|
560
767
|
constructor(parent, props) {
|
|
561
768
|
if ("aseid" in props) {
|
|
@@ -1486,6 +1693,19 @@ var AreHTMLInterpreter = class extends AreInterpreter {
|
|
|
1486
1693
|
console.log("Error removing attribute:", error);
|
|
1487
1694
|
}
|
|
1488
1695
|
}
|
|
1696
|
+
hideElement(mutation, context) {
|
|
1697
|
+
const element = context.getElementByInstruction(mutation.parent);
|
|
1698
|
+
if (!element || element.nodeType !== Node.ELEMENT_NODE) return;
|
|
1699
|
+
const el = element;
|
|
1700
|
+
mutation.cache = el.style.display;
|
|
1701
|
+
el.style.display = "none";
|
|
1702
|
+
}
|
|
1703
|
+
showElement(mutation, context) {
|
|
1704
|
+
const element = context.getElementByInstruction(mutation.parent);
|
|
1705
|
+
if (!element || element.nodeType !== Node.ELEMENT_NODE) return;
|
|
1706
|
+
const el = element;
|
|
1707
|
+
el.style.display = mutation.payload?.display ?? mutation.cache ?? "";
|
|
1708
|
+
}
|
|
1489
1709
|
addEventListener(mutation, context, store, syntax, directiveContext, logger) {
|
|
1490
1710
|
const element = context.getElementByInstruction(mutation.parent);
|
|
1491
1711
|
if (!element) {
|
|
@@ -1738,6 +1958,22 @@ __decorateClass([
|
|
|
1738
1958
|
__decorateParam(0, A_Inject(A_Caller)),
|
|
1739
1959
|
__decorateParam(1, A_Inject(AreHTMLEngineContext))
|
|
1740
1960
|
], AreHTMLInterpreter.prototype, "removeAttribute", 1);
|
|
1961
|
+
__decorateClass([
|
|
1962
|
+
A_Frame.Define({
|
|
1963
|
+
description: "Hide an element by setting inline display:none, caching its previous inline display value for restoration on revert."
|
|
1964
|
+
}),
|
|
1965
|
+
AreInterpreter.Apply(AreHTMLInstructions.HideElement),
|
|
1966
|
+
__decorateParam(0, A_Inject(A_Caller)),
|
|
1967
|
+
__decorateParam(1, A_Inject(AreHTMLEngineContext))
|
|
1968
|
+
], AreHTMLInterpreter.prototype, "hideElement", 1);
|
|
1969
|
+
__decorateClass([
|
|
1970
|
+
A_Frame.Define({
|
|
1971
|
+
description: "Restore an element hidden by a HideElement instruction back to its previous inline display value."
|
|
1972
|
+
}),
|
|
1973
|
+
AreInterpreter.Revert(AreHTMLInstructions.HideElement),
|
|
1974
|
+
__decorateParam(0, A_Inject(A_Caller)),
|
|
1975
|
+
__decorateParam(1, A_Inject(AreHTMLEngineContext))
|
|
1976
|
+
], AreHTMLInterpreter.prototype, "showElement", 1);
|
|
1741
1977
|
__decorateClass([
|
|
1742
1978
|
A_Frame.Define({
|
|
1743
1979
|
description: "Add an event listener to an HTML element based on the provided mutation instruction."
|
|
@@ -1908,10 +2144,45 @@ var AreHTMLLifecycle = class extends AreLifecycle {
|
|
|
1908
2144
|
logger?.debug(`[Mount] Component Trigger for <${node.aseid.entity}> with aseid :{${node.aseid.toString()}}`);
|
|
1909
2145
|
if (scene.isInactive) return;
|
|
1910
2146
|
node.interpret();
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
}
|
|
2147
|
+
const stack = [];
|
|
2148
|
+
for (let i = node.children.length - 1; i >= 0; i--) {
|
|
2149
|
+
stack.push({ node: node.children[i], entered: false });
|
|
2150
|
+
}
|
|
2151
|
+
const step = () => {
|
|
2152
|
+
const frame = stack[stack.length - 1];
|
|
2153
|
+
const current = frame.node;
|
|
2154
|
+
if (frame.entered) {
|
|
2155
|
+
stack.pop();
|
|
2156
|
+
current.call(AreNodeFeatures.onAfterMount, current.scope);
|
|
2157
|
+
return;
|
|
2158
|
+
}
|
|
2159
|
+
frame.entered = true;
|
|
2160
|
+
current.call(AreNodeFeatures.onBeforeMount, current.scope);
|
|
2161
|
+
if (!current.scene.isInactive) {
|
|
2162
|
+
current.interpret();
|
|
2163
|
+
for (let i = current.children.length - 1; i >= 0; i--) {
|
|
2164
|
+
stack.push({ node: current.children[i], entered: false });
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
};
|
|
2168
|
+
const drive = () => {
|
|
2169
|
+
const start = AreSchedulerHelper.now();
|
|
2170
|
+
while (stack.length > 0) {
|
|
2171
|
+
step();
|
|
2172
|
+
if (stack.length > 0 && AreSchedulerHelper.now() - start >= AreHTMLLifecycle.MOUNT_BUDGET_MS) {
|
|
2173
|
+
return new Promise((resolve, reject) => {
|
|
2174
|
+
AreSchedulerHelper.scheduleMacrotask(() => {
|
|
2175
|
+
try {
|
|
2176
|
+
resolve(drive());
|
|
2177
|
+
} catch (error) {
|
|
2178
|
+
reject(error);
|
|
2179
|
+
}
|
|
2180
|
+
});
|
|
2181
|
+
});
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
};
|
|
2185
|
+
return drive();
|
|
1915
2186
|
}
|
|
1916
2187
|
updateDirectiveAttribute(directive, scope, feature, logger, ...args) {
|
|
1917
2188
|
if (directive.component) {
|
|
@@ -1921,6 +2192,13 @@ var AreHTMLLifecycle = class extends AreLifecycle {
|
|
|
1921
2192
|
}
|
|
1922
2193
|
}
|
|
1923
2194
|
};
|
|
2195
|
+
/**
|
|
2196
|
+
* Per-chunk time budget (ms) for the time-sliced initial mount walk. While
|
|
2197
|
+
* mounting a large subtree we keep applying nodes until this much wall-clock
|
|
2198
|
+
* time has elapsed, then yield to the browser so it can paint and process
|
|
2199
|
+
* input before the next chunk. ~16ms targets a single animation frame.
|
|
2200
|
+
*/
|
|
2201
|
+
AreHTMLLifecycle.MOUNT_BUDGET_MS = 16;
|
|
1924
2202
|
__decorateClass([
|
|
1925
2203
|
AreLifecycle.Init(AreComponentNode),
|
|
1926
2204
|
__decorateParam(0, A_Inject(A_Caller)),
|
|
@@ -2003,6 +2281,97 @@ AreHTMLTransformer = __decorateClass([
|
|
|
2003
2281
|
description: "HTML-specific transformer extending AreTransformer. Handles directive-attribute structural rewrites before compilation \u2014 sorting directives by declared priority and expanding compound directive expressions \u2014 so the compiler receives a clean, ordered AreHTMLNode tree ready for instruction emission."
|
|
2004
2282
|
})
|
|
2005
2283
|
], AreHTMLTransformer);
|
|
2284
|
+
var AreRootCache = class extends A_Fragment {
|
|
2285
|
+
constructor(limit = 10) {
|
|
2286
|
+
super({ name: "AreRootCache" });
|
|
2287
|
+
/**
|
|
2288
|
+
* rootId -> (component tag -> cache entry). The inner Map preserves
|
|
2289
|
+
* insertion order which is used as the LRU recency order: the first key is
|
|
2290
|
+
* the least-recently-used entry, the last key the most-recently-used.
|
|
2291
|
+
*/
|
|
2292
|
+
this._cache = /* @__PURE__ */ new Map();
|
|
2293
|
+
this._limit = Math.max(0, Math.floor(limit));
|
|
2294
|
+
}
|
|
2295
|
+
/**
|
|
2296
|
+
* Maximum number of cached subtrees kept per root.
|
|
2297
|
+
*/
|
|
2298
|
+
get limit() {
|
|
2299
|
+
return this._limit;
|
|
2300
|
+
}
|
|
2301
|
+
bucket(rootId) {
|
|
2302
|
+
let bucket = this._cache.get(rootId);
|
|
2303
|
+
if (!bucket) {
|
|
2304
|
+
bucket = /* @__PURE__ */ new Map();
|
|
2305
|
+
this._cache.set(rootId, bucket);
|
|
2306
|
+
}
|
|
2307
|
+
return bucket;
|
|
2308
|
+
}
|
|
2309
|
+
/**
|
|
2310
|
+
* Whether a subtree for the given component tag is currently cached.
|
|
2311
|
+
*/
|
|
2312
|
+
has(rootId, tag) {
|
|
2313
|
+
return this.bucket(rootId).has(tag);
|
|
2314
|
+
}
|
|
2315
|
+
/**
|
|
2316
|
+
* Retrieve AND remove a cached subtree so it can become live again. Returns
|
|
2317
|
+
* `undefined` on a cache miss.
|
|
2318
|
+
*/
|
|
2319
|
+
take(rootId, tag) {
|
|
2320
|
+
const bucket = this.bucket(rootId);
|
|
2321
|
+
const entry = bucket.get(tag);
|
|
2322
|
+
if (entry) {
|
|
2323
|
+
bucket.delete(tag);
|
|
2324
|
+
}
|
|
2325
|
+
return entry;
|
|
2326
|
+
}
|
|
2327
|
+
/**
|
|
2328
|
+
* Stash a detached subtree under the given component tag. Returns any entries
|
|
2329
|
+
* that were evicted to honour the LRU limit (or replaced for the same tag) so
|
|
2330
|
+
* the caller can `destroy()` them.
|
|
2331
|
+
*/
|
|
2332
|
+
put(rootId, tag, entry) {
|
|
2333
|
+
const bucket = this.bucket(rootId);
|
|
2334
|
+
const evicted = [];
|
|
2335
|
+
const existing = bucket.get(tag);
|
|
2336
|
+
if (existing) {
|
|
2337
|
+
bucket.delete(tag);
|
|
2338
|
+
if (existing.node !== entry.node) {
|
|
2339
|
+
evicted.push(existing);
|
|
2340
|
+
}
|
|
2341
|
+
}
|
|
2342
|
+
bucket.set(tag, entry);
|
|
2343
|
+
while (bucket.size > this._limit) {
|
|
2344
|
+
const oldestKey = bucket.keys().next().value;
|
|
2345
|
+
if (oldestKey === void 0) {
|
|
2346
|
+
break;
|
|
2347
|
+
}
|
|
2348
|
+
const oldest = bucket.get(oldestKey);
|
|
2349
|
+
bucket.delete(oldestKey);
|
|
2350
|
+
evicted.push(oldest);
|
|
2351
|
+
}
|
|
2352
|
+
return evicted;
|
|
2353
|
+
}
|
|
2354
|
+
/**
|
|
2355
|
+
* Remove and return every cached entry for a root (e.g. on teardown) so the
|
|
2356
|
+
* caller can destroy them.
|
|
2357
|
+
*/
|
|
2358
|
+
clear(rootId) {
|
|
2359
|
+
const bucket = this._cache.get(rootId);
|
|
2360
|
+
if (!bucket) {
|
|
2361
|
+
return [];
|
|
2362
|
+
}
|
|
2363
|
+
const entries = [...bucket.values()];
|
|
2364
|
+
bucket.clear();
|
|
2365
|
+
this._cache.delete(rootId);
|
|
2366
|
+
return entries;
|
|
2367
|
+
}
|
|
2368
|
+
};
|
|
2369
|
+
AreRootCache = __decorateClass([
|
|
2370
|
+
A_Frame.Define({
|
|
2371
|
+
namespace: "a-are-html",
|
|
2372
|
+
description: "AreRootCache is a fragment that keeps a small per-root LRU of previously rendered are-root subtrees. When an are-root swaps the component it displays, the outgoing subtree is stashed here (unmounted + detached, but not destroyed) so that routing back to it can re-inject the preserved scene instantly instead of rebuilding from scratch."
|
|
2373
|
+
})
|
|
2374
|
+
], AreRootCache);
|
|
2006
2375
|
|
|
2007
2376
|
// src/engine/AreHTML.engine.ts
|
|
2008
2377
|
var AreHTMLEngine = class extends AreEngine {
|
|
@@ -2049,7 +2418,7 @@ var AreHTMLEngine = class extends AreEngine {
|
|
|
2049
2418
|
]
|
|
2050
2419
|
});
|
|
2051
2420
|
}
|
|
2052
|
-
async init(scope, signalContext) {
|
|
2421
|
+
async init(scope, signalContext, rootCache) {
|
|
2053
2422
|
this.package(scope, {
|
|
2054
2423
|
context: new AreHTMLEngineContext({}),
|
|
2055
2424
|
syntax: this.DefaultSyntax,
|
|
@@ -2063,6 +2432,10 @@ var AreHTMLEngine = class extends AreEngine {
|
|
|
2063
2432
|
signalContext = new AreSignalsContext();
|
|
2064
2433
|
scope.register(signalContext);
|
|
2065
2434
|
}
|
|
2435
|
+
if (!rootCache) {
|
|
2436
|
+
rootCache = new AreRootCache();
|
|
2437
|
+
scope.register(rootCache);
|
|
2438
|
+
}
|
|
2066
2439
|
}
|
|
2067
2440
|
rootElementMatcher(source, from, to, build) {
|
|
2068
2441
|
const rootTag = "are-root";
|
|
@@ -2172,7 +2545,8 @@ __decorateClass([
|
|
|
2172
2545
|
before: /.*/
|
|
2173
2546
|
}),
|
|
2174
2547
|
__decorateParam(0, A_Inject(A_Scope)),
|
|
2175
|
-
__decorateParam(1, A_Inject(AreSignalsContext))
|
|
2548
|
+
__decorateParam(1, A_Inject(AreSignalsContext)),
|
|
2549
|
+
__decorateParam(2, A_Inject(AreRootCache))
|
|
2176
2550
|
], AreHTMLEngine.prototype, "init", 1);
|
|
2177
2551
|
AreHTMLEngine = __decorateClass([
|
|
2178
2552
|
A_Frame.Define({
|
|
@@ -2181,7 +2555,7 @@ AreHTMLEngine = __decorateClass([
|
|
|
2181
2555
|
})
|
|
2182
2556
|
], AreHTMLEngine);
|
|
2183
2557
|
var AreRoot = class extends Are {
|
|
2184
|
-
async template(root, logger, signalsContext) {
|
|
2558
|
+
async template(root, logger, signalsContext, signalState) {
|
|
2185
2559
|
const rootId = root.id;
|
|
2186
2560
|
if (signalsContext && !signalsContext.hasRoot(rootId)) {
|
|
2187
2561
|
if (!root.content?.trim()) {
|
|
@@ -2193,26 +2567,9 @@ var AreRoot = class extends Are {
|
|
|
2193
2567
|
}
|
|
2194
2568
|
return;
|
|
2195
2569
|
}
|
|
2196
|
-
const
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
const initialVector = new A_SignalVector([currentRoute]);
|
|
2200
|
-
let renderTarget = signalsContext?.findComponentByVector(rootId, initialVector);
|
|
2201
|
-
if (!renderTarget) {
|
|
2202
|
-
const signalsMeta = A_Context.meta(AreSignals);
|
|
2203
|
-
const pool = signalsContext?.getComponentById(rootId);
|
|
2204
|
-
const metaTarget = signalsMeta?.findComponentByVector(
|
|
2205
|
-
initialVector,
|
|
2206
|
-
pool?.length ? pool : void 0
|
|
2207
|
-
);
|
|
2208
|
-
if (metaTarget && (!pool?.length || pool.includes(metaTarget))) {
|
|
2209
|
-
renderTarget = metaTarget;
|
|
2210
|
-
}
|
|
2211
|
-
}
|
|
2212
|
-
if (renderTarget?.name) {
|
|
2213
|
-
componentName = A_FormatterHelper.toKebabCase(renderTarget.name);
|
|
2214
|
-
}
|
|
2215
|
-
}
|
|
2570
|
+
const initialVector = this.buildInitialVector(signalState);
|
|
2571
|
+
const renderTarget = this.matchComponent(rootId, initialVector, signalsContext);
|
|
2572
|
+
let componentName = renderTarget?.name ? A_FormatterHelper.toKebabCase(renderTarget.name) : void 0;
|
|
2216
2573
|
if (!componentName) {
|
|
2217
2574
|
if (root.content?.trim()) {
|
|
2218
2575
|
return;
|
|
@@ -2234,32 +2591,17 @@ var AreRoot = class extends Are {
|
|
|
2234
2591
|
}
|
|
2235
2592
|
root.setContent(`<${componentName}></${componentName}>`);
|
|
2236
2593
|
}
|
|
2237
|
-
async onSignal(root, vector, logger, signalsContext) {
|
|
2594
|
+
async onSignal(root, vector, logger, signalsContext, cache) {
|
|
2238
2595
|
const rootId = root.id;
|
|
2239
2596
|
if (signalsContext && !signalsContext.hasRoot(rootId)) {
|
|
2240
2597
|
return;
|
|
2241
2598
|
}
|
|
2242
|
-
|
|
2243
|
-
if (!renderTarget) {
|
|
2244
|
-
const signalsMeta = A_Context.meta(AreSignals);
|
|
2245
|
-
const pool = signalsContext?.getComponentById(rootId);
|
|
2246
|
-
const metaTarget = signalsMeta?.findComponentByVector(
|
|
2247
|
-
vector,
|
|
2248
|
-
pool?.length ? pool : void 0
|
|
2249
|
-
);
|
|
2250
|
-
if (metaTarget && (!pool?.length || pool.includes(metaTarget))) {
|
|
2251
|
-
renderTarget = metaTarget;
|
|
2252
|
-
}
|
|
2253
|
-
}
|
|
2599
|
+
const renderTarget = this.matchComponent(rootId, vector, signalsContext);
|
|
2254
2600
|
const def = signalsContext?.getDefault(rootId);
|
|
2255
2601
|
const componentName = renderTarget?.name ? A_FormatterHelper.toKebabCase(renderTarget.name) : def?.name ? A_FormatterHelper.toKebabCase(def.name) : void 0;
|
|
2256
2602
|
if (!componentName) {
|
|
2257
|
-
for (
|
|
2258
|
-
|
|
2259
|
-
signalsContext?.unsubscribe(child);
|
|
2260
|
-
child.unmount();
|
|
2261
|
-
child.destroy();
|
|
2262
|
-
root.removeChild(child);
|
|
2603
|
+
for (const child of [...root.children]) {
|
|
2604
|
+
this.stashChild(root, child, signalsContext, cache);
|
|
2263
2605
|
}
|
|
2264
2606
|
root.setContent("");
|
|
2265
2607
|
return;
|
|
@@ -2268,13 +2610,14 @@ var AreRoot = class extends Are {
|
|
|
2268
2610
|
if (currentChild?.type === componentName) {
|
|
2269
2611
|
return;
|
|
2270
2612
|
}
|
|
2613
|
+
for (const child of [...root.children]) {
|
|
2614
|
+
this.stashChild(root, child, signalsContext, cache);
|
|
2615
|
+
}
|
|
2271
2616
|
root.setContent(`<${componentName}></${componentName}>`);
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
signalsContext
|
|
2275
|
-
|
|
2276
|
-
child.destroy();
|
|
2277
|
-
root.removeChild(child);
|
|
2617
|
+
const cached = cache?.take(root.id, componentName);
|
|
2618
|
+
if (cached) {
|
|
2619
|
+
this.restoreChild(root, cached, signalsContext);
|
|
2620
|
+
return;
|
|
2278
2621
|
}
|
|
2279
2622
|
root.tokenize();
|
|
2280
2623
|
for (let i = 0; i < root.children.length; i++) {
|
|
@@ -2286,22 +2629,141 @@ var AreRoot = class extends Are {
|
|
|
2286
2629
|
}
|
|
2287
2630
|
child.transform();
|
|
2288
2631
|
child.compile();
|
|
2289
|
-
child.mount();
|
|
2632
|
+
await child.mount();
|
|
2633
|
+
}
|
|
2634
|
+
}
|
|
2635
|
+
/**
|
|
2636
|
+
* Resolves the component a vector should render for the given root, mirroring
|
|
2637
|
+
* the priority used everywhere in the routing system:
|
|
2638
|
+
* 1. Root-specific conditions registered on AreSignalsContext.
|
|
2639
|
+
* 2. The global AreSignalsMeta map, restricted to this outlet's pool.
|
|
2640
|
+
*
|
|
2641
|
+
* Passing the pool *into* the meta lookup is critical: without it, the first
|
|
2642
|
+
* globally matching component wins and may belong to a different outlet
|
|
2643
|
+
* (e.g. AisRequirementsPanel for the meta-outlet matching
|
|
2644
|
+
* AisEditorCursorScope) — the pool check would then reject it and the outlet
|
|
2645
|
+
* would fall back to its default, hiding a valid in-pool match (e.g.
|
|
2646
|
+
* AisDiagramTab matching AisSetPrimaryDisplay).
|
|
2647
|
+
*
|
|
2648
|
+
* Returns `undefined` when nothing matches — callers decide whether to use a
|
|
2649
|
+
* configured default, body content, or clear the outlet.
|
|
2650
|
+
*/
|
|
2651
|
+
matchComponent(rootId, vector, signalsContext) {
|
|
2652
|
+
if (!vector) return void 0;
|
|
2653
|
+
let renderTarget = signalsContext?.findComponentByVector(rootId, vector);
|
|
2654
|
+
if (!renderTarget) {
|
|
2655
|
+
const signalsMeta = A_Context.meta(AreSignals);
|
|
2656
|
+
const pool = signalsContext?.getComponentById(rootId);
|
|
2657
|
+
const metaTarget = signalsMeta?.findComponentByVector(
|
|
2658
|
+
vector,
|
|
2659
|
+
pool?.length ? pool : void 0,
|
|
2660
|
+
rootId
|
|
2661
|
+
);
|
|
2662
|
+
if (metaTarget && (!pool?.length || pool.includes(metaTarget))) {
|
|
2663
|
+
renderTarget = metaTarget;
|
|
2664
|
+
}
|
|
2290
2665
|
}
|
|
2666
|
+
return renderTarget;
|
|
2667
|
+
}
|
|
2668
|
+
/**
|
|
2669
|
+
* Builds the vector used for the INITIAL render. It is seeded from the
|
|
2670
|
+
* accumulated signal state (every signal dispatched on the bus so far) so a
|
|
2671
|
+
* freshly-mounted outlet reflects the live application state immediately,
|
|
2672
|
+
* not just on the next signal tick. The current URL route is appended when
|
|
2673
|
+
* no AreRoute is already present in the state, so route-driven outlets still
|
|
2674
|
+
* resolve on the very first paint (before AreRouteWatcher has dispatched).
|
|
2675
|
+
*/
|
|
2676
|
+
buildInitialVector(signalState) {
|
|
2677
|
+
const signals = [];
|
|
2678
|
+
if (signalState) {
|
|
2679
|
+
for (const signal of signalState.toVector()) {
|
|
2680
|
+
if (signal) signals.push(signal);
|
|
2681
|
+
}
|
|
2682
|
+
}
|
|
2683
|
+
if (!signals.some((signal) => signal instanceof AreRoute)) {
|
|
2684
|
+
try {
|
|
2685
|
+
const currentRoute = AreRoute.default();
|
|
2686
|
+
if (currentRoute) signals.push(currentRoute);
|
|
2687
|
+
} catch {
|
|
2688
|
+
}
|
|
2689
|
+
}
|
|
2690
|
+
return new A_SignalVector(signals);
|
|
2691
|
+
}
|
|
2692
|
+
/**
|
|
2693
|
+
* Detach a displayed child subtree from the outlet and stash it in the cache
|
|
2694
|
+
* for fast re-injection later. The subtree is unmounted (its scene plan is
|
|
2695
|
+
* preserved) and deregistered from the root scope, but NOT destroyed. The
|
|
2696
|
+
* nodes that were subscribed to the signal bus are unsubscribed while cached
|
|
2697
|
+
* so the detached DOM never reacts to signals, and recorded so they can be
|
|
2698
|
+
* re-subscribed verbatim on restore.
|
|
2699
|
+
*
|
|
2700
|
+
* When no cache is available, or the LRU evicts an entry, the affected
|
|
2701
|
+
* subtree is fully destroyed.
|
|
2702
|
+
*/
|
|
2703
|
+
stashChild(root, child, signalsContext, cache) {
|
|
2704
|
+
const tag = child.type;
|
|
2705
|
+
child.unmount();
|
|
2706
|
+
const subscribers = signalsContext ? this.collectSubscribers(child, signalsContext) : [];
|
|
2707
|
+
for (const node of subscribers) {
|
|
2708
|
+
signalsContext?.unsubscribe(node);
|
|
2709
|
+
}
|
|
2710
|
+
root.removeChild(child);
|
|
2711
|
+
if (!cache) {
|
|
2712
|
+
void child.destroy();
|
|
2713
|
+
return;
|
|
2714
|
+
}
|
|
2715
|
+
const evicted = cache.put(root.id, tag, { node: child, subscribers });
|
|
2716
|
+
for (const entry of evicted) {
|
|
2717
|
+
void entry.node.destroy();
|
|
2718
|
+
}
|
|
2719
|
+
}
|
|
2720
|
+
/**
|
|
2721
|
+
* Re-attach a cached subtree to the outlet and re-mount it from its preserved
|
|
2722
|
+
* scene plan, re-subscribing exactly the nodes that were subscribed before it
|
|
2723
|
+
* was cached.
|
|
2724
|
+
*/
|
|
2725
|
+
restoreChild(root, entry, signalsContext) {
|
|
2726
|
+
const child = entry.node;
|
|
2727
|
+
root.addChild(child);
|
|
2728
|
+
for (const node of entry.subscribers) {
|
|
2729
|
+
signalsContext?.subscribe(node);
|
|
2730
|
+
}
|
|
2731
|
+
child.mount();
|
|
2732
|
+
}
|
|
2733
|
+
/**
|
|
2734
|
+
* Walk a subtree and collect the nodes currently registered as signal
|
|
2735
|
+
* subscribers. Mirrors the subscription performed at init time in
|
|
2736
|
+
* AreHTMLLifecycle (component nodes and root nodes) without depending on the
|
|
2737
|
+
* concrete node classes — it simply intersects the subtree with the live
|
|
2738
|
+
* subscriber registry.
|
|
2739
|
+
*/
|
|
2740
|
+
collectSubscribers(node, signalsContext) {
|
|
2741
|
+
const result = [];
|
|
2742
|
+
const queue = [node];
|
|
2743
|
+
while (queue.length > 0) {
|
|
2744
|
+
const current = queue.shift();
|
|
2745
|
+
if (signalsContext.subscribers.has(current)) {
|
|
2746
|
+
result.push(current);
|
|
2747
|
+
}
|
|
2748
|
+
queue.push(...current.children);
|
|
2749
|
+
}
|
|
2750
|
+
return result;
|
|
2291
2751
|
}
|
|
2292
2752
|
};
|
|
2293
2753
|
__decorateClass([
|
|
2294
2754
|
Are.Template,
|
|
2295
2755
|
__decorateParam(0, A_Inject(A_Caller)),
|
|
2296
2756
|
__decorateParam(1, A_Inject(A_Logger)),
|
|
2297
|
-
__decorateParam(2, A_Inject(AreSignalsContext))
|
|
2757
|
+
__decorateParam(2, A_Inject(AreSignalsContext)),
|
|
2758
|
+
__decorateParam(3, A_Inject(A_SignalState))
|
|
2298
2759
|
], AreRoot.prototype, "template", 1);
|
|
2299
2760
|
__decorateClass([
|
|
2300
2761
|
Are.Signal,
|
|
2301
2762
|
__decorateParam(0, A_Inject(A_Caller)),
|
|
2302
2763
|
__decorateParam(1, A_Inject(A_SignalVector)),
|
|
2303
2764
|
__decorateParam(2, A_Inject(A_Logger)),
|
|
2304
|
-
__decorateParam(3, A_Inject(AreSignalsContext))
|
|
2765
|
+
__decorateParam(3, A_Inject(AreSignalsContext)),
|
|
2766
|
+
__decorateParam(4, A_Inject(AreRootCache))
|
|
2305
2767
|
], AreRoot.prototype, "onSignal", 1);
|
|
2306
2768
|
AreRoot = __decorateClass([
|
|
2307
2769
|
A_Frame.Define({
|
|
@@ -2372,6 +2834,6 @@ AreRouteWatcher = __decorateClass([
|
|
|
2372
2834
|
})
|
|
2373
2835
|
], AreRouteWatcher);
|
|
2374
2836
|
|
|
2375
|
-
export { AddAttributeInstruction, AddElementInstruction, AddInterpolationInstruction, AddListenerInstruction, AddStyleInstruction, AddTextInstruction, AreBindingAttribute, AreComment, AreComponentNode, AreDirective, AreDirectiveAttribute, AreDirectiveContext, AreDirectiveFeatures, AreDirectiveFor, AreDirectiveIf, AreDirectiveMeta, AreEventAttribute, AreHTMLAttribute, AreHTMLCompiler, AreHTMLEngine, AreHTMLEngineContext, AreHTMLInstructions, AreHTMLInterpreter, AreHTMLLifecycle, AreHTMLNode, AreHTMLTokenizer, AreHTMLTransformer, AreInterpolation, AreRoot, AreRootNode, AreRoute, AreRouteWatcher, AreStaticAttribute, AreStyle, AreText, BOOLEAN_ATTRIBUTES, IDL_FORM_PROPERTIES, LISTENER_OPTION_MODIFIERS, SVG_ATTRIBUTE_NS, SVG_NAMESPACE, VOID_ELEMENTS, isBooleanAttribute, isIDLFormProperty, isVoidElement, normalizeClassValue, normalizeStyleValue, parseEventName, toDOMString };
|
|
2837
|
+
export { AddAttributeInstruction, AddElementInstruction, AddInterpolationInstruction, AddListenerInstruction, AddStyleInstruction, AddTextInstruction, AreBindingAttribute, AreComment, AreComponentNode, AreDirective, AreDirectiveAttribute, AreDirectiveContext, AreDirectiveFeatures, AreDirectiveFor, AreDirectiveIf, AreDirectiveMeta, AreDirectiveShow, AreEventAttribute, AreHTMLAttribute, AreHTMLCompiler, AreHTMLEngine, AreHTMLEngineContext, AreHTMLInstructions, AreHTMLInterpreter, AreHTMLLifecycle, AreHTMLNode, AreHTMLTokenizer, AreHTMLTransformer, AreInterpolation, AreRoot, AreRootCache, AreRootNode, AreRoute, AreRouteWatcher, AreStaticAttribute, AreStyle, AreText, BOOLEAN_ATTRIBUTES, HideElementInstruction, IDL_FORM_PROPERTIES, LISTENER_OPTION_MODIFIERS, SVG_ATTRIBUTE_NS, SVG_NAMESPACE, VOID_ELEMENTS, isBooleanAttribute, isIDLFormProperty, isVoidElement, normalizeClassValue, normalizeStyleValue, parseEventName, toDOMString };
|
|
2376
2838
|
//# sourceMappingURL=index.mjs.map
|
|
2377
2839
|
//# sourceMappingURL=index.mjs.map
|