mount-observer 0.1.12 → 0.1.14
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/DefineCustomElementHandler.js +99 -99
- package/ElementMountExtension.js +183 -8
- package/ElementMountExtension.ts +218 -11
- package/EnhanceMountedElementHandler.js +96 -96
- package/Events.js +27 -18
- package/Events.ts +18 -6
- package/EvtRt.js +16 -14
- package/EvtRt.ts +18 -15
- package/MountObserver.js +207 -71
- package/MountObserver.ts +234 -85
- package/README.md +1782 -251
- package/RegistryMountCoordinator.js +125 -0
- package/RegistryMountCoordinator.ts +181 -0
- package/connectionMonitor.js +1 -1
- package/connectionMonitor.ts +1 -1
- package/{getRootRegistryContainer.js → getRegistryRoot.js} +1 -1
- package/{getRootRegistryContainer.ts → getRegistryRoot.ts} +1 -1
- package/index.js +15 -10
- package/index.ts +15 -10
- package/mediaQuery.js +1 -1
- package/mediaQuery.ts +1 -1
- package/observedRootHas.js +87 -87
- package/package.json +67 -61
- package/playwright.config.ts +1 -0
- package/rootSizeObserver.js +1 -1
- package/rootSizeObserver.ts +1 -1
- package/upShadowSearch.js +67 -0
- package/upShadowSearch.ts +65 -0
- package/DefineCustomElementHandler.ts +0 -117
- package/EnhanceMountedElementHandler.ts +0 -111
package/MountObserver.ts
CHANGED
|
@@ -21,9 +21,10 @@ import {
|
|
|
21
21
|
type MutationCallback
|
|
22
22
|
} from './SharedMutationObserver.js';
|
|
23
23
|
import { withScopePerimeter } from './withScopePerimeter.js';
|
|
24
|
+
import { getRegistryRoot } from './getRegistryRoot.js';
|
|
24
25
|
import type { assignTentatively as AssignTentativelyType } from 'assign-gingerly/assignTentatively.js';
|
|
25
26
|
|
|
26
|
-
export class MountObserver extends EventTarget implements IMountObserver {
|
|
27
|
+
export class MountObserver<TKeys extends string = string> extends EventTarget implements IMountObserver {
|
|
27
28
|
// Static registry for registered handlers
|
|
28
29
|
static #handlerRegistry = new Map<string, Constructor>();
|
|
29
30
|
|
|
@@ -38,6 +39,7 @@ export class MountObserver extends EventTarget implements IMountObserver {
|
|
|
38
39
|
#options: MountObserverOptions;
|
|
39
40
|
#abortController: AbortController;
|
|
40
41
|
#modules: any[] = [];
|
|
42
|
+
#configFromPromise: Promise<void> | undefined;
|
|
41
43
|
#mountedElements: WeakDual<Element> = {
|
|
42
44
|
weakSet: new WeakSet(),
|
|
43
45
|
setWeak: new Set()
|
|
@@ -62,6 +64,8 @@ export class MountObserver extends EventTarget implements IMountObserver {
|
|
|
62
64
|
#assignTentatively: typeof AssignTentativelyType | undefined;
|
|
63
65
|
#elementNotifiers = new WeakMap<Element, EventTarget>();
|
|
64
66
|
#notifierMountedElements = new WeakSet<Element>();
|
|
67
|
+
#subObservers: Map<string, MountObserver> | undefined;
|
|
68
|
+
#whenDefinedResolved = false;
|
|
65
69
|
|
|
66
70
|
#mergeHandlerDefaults(config: MountConfig): MountConfig {
|
|
67
71
|
const doValue = config.do;
|
|
@@ -94,7 +98,7 @@ export class MountObserver extends EventTarget implements IMountObserver {
|
|
|
94
98
|
return { ...handlerDefaults, ...config };
|
|
95
99
|
}
|
|
96
100
|
|
|
97
|
-
constructor(config: MountConfig
|
|
101
|
+
constructor(config: MountConfig<TKeys>, options: MountObserverOptions = {}) {
|
|
98
102
|
super();
|
|
99
103
|
|
|
100
104
|
// Merge handler defaults if do is a string reference
|
|
@@ -105,8 +109,8 @@ export class MountObserver extends EventTarget implements IMountObserver {
|
|
|
105
109
|
this.#abortController = new AbortController();
|
|
106
110
|
|
|
107
111
|
const {
|
|
108
|
-
assignOnMount, assignOnDismount, stageOnMount, do: doValue,
|
|
109
|
-
import: imp
|
|
112
|
+
assignOnMount, assignOnDismount, stageOnMount, do: doValue, loadingEagerness,
|
|
113
|
+
import: imp, configFrom
|
|
110
114
|
} = mergedConfig;
|
|
111
115
|
// Make a copy of assignOnMount config using structuredClone
|
|
112
116
|
if (assignOnMount !== undefined) {
|
|
@@ -130,9 +134,9 @@ export class MountObserver extends EventTarget implements IMountObserver {
|
|
|
130
134
|
this.#validateDoHandlers();
|
|
131
135
|
}
|
|
132
136
|
|
|
133
|
-
//
|
|
134
|
-
if (
|
|
135
|
-
this.#
|
|
137
|
+
// Load configFrom modules if specified
|
|
138
|
+
if (configFrom !== undefined) {
|
|
139
|
+
this.#configFromPromise = this.#loadConfigFrom();
|
|
136
140
|
}
|
|
137
141
|
|
|
138
142
|
// Start loading imports if eager
|
|
@@ -155,35 +159,110 @@ export class MountObserver extends EventTarget implements IMountObserver {
|
|
|
155
159
|
}
|
|
156
160
|
}
|
|
157
161
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Loads configuration from external modules specified in configFrom property.
|
|
165
|
+
* Merges multiple configs left-to-right, with inline config taking final precedence.
|
|
166
|
+
*/
|
|
167
|
+
async #loadConfigFrom(): Promise<void> {
|
|
168
|
+
const { configFrom } = this.#init;
|
|
169
|
+
if (!configFrom) return;
|
|
170
|
+
|
|
171
|
+
// Normalize to array
|
|
172
|
+
const configPaths = Array.isArray(configFrom) ? configFrom : [configFrom];
|
|
173
|
+
|
|
174
|
+
// Check for duplicates
|
|
175
|
+
const pathSet = new Set<string>();
|
|
176
|
+
for (const path of configPaths) {
|
|
177
|
+
if (pathSet.has(path)) {
|
|
178
|
+
throw new Error(`Duplicate configFrom module: '${path}'`);
|
|
179
|
+
}
|
|
180
|
+
pathSet.add(path);
|
|
162
181
|
}
|
|
163
182
|
|
|
164
|
-
//
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
183
|
+
// Load all modules
|
|
184
|
+
const loadedConfigs: MountConfig[] = [];
|
|
185
|
+
for (const path of configPaths) {
|
|
186
|
+
try {
|
|
187
|
+
const module = await import(path);
|
|
188
|
+
|
|
189
|
+
if (!module.mountConfig) {
|
|
190
|
+
throw new Error(`Module '${path}' does not export 'mountConfig'`);
|
|
191
|
+
}
|
|
168
192
|
|
|
169
|
-
|
|
170
|
-
|
|
193
|
+
if (typeof module.mountConfig !== 'object' || module.mountConfig === null) {
|
|
194
|
+
throw new Error(`Module '${path}' exports invalid mountConfig: must be an object`);
|
|
195
|
+
}
|
|
171
196
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
197
|
+
loadedConfigs.push(module.mountConfig);
|
|
198
|
+
} catch (error) {
|
|
199
|
+
// Re-throw with better context if it's not already our error
|
|
200
|
+
if (error instanceof Error && !error.message.includes(path)) {
|
|
201
|
+
throw new Error(`Failed to load config from '${path}': ${error.message}`);
|
|
202
|
+
}
|
|
203
|
+
throw error;
|
|
177
204
|
}
|
|
205
|
+
}
|
|
178
206
|
|
|
179
|
-
|
|
207
|
+
// Merge configs: loaded configs first (left-to-right), then inline config
|
|
208
|
+
// Save the original inline config
|
|
209
|
+
const inlineConfig = { ...this.#init };
|
|
180
210
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
211
|
+
// Start with empty object, merge all loaded configs, then merge inline
|
|
212
|
+
let mergedConfig: MountConfig = {};
|
|
213
|
+
for (const loadedConfig of loadedConfigs) {
|
|
214
|
+
mergedConfig = Object.assign(mergedConfig, loadedConfig);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Inline config takes final precedence
|
|
218
|
+
mergedConfig = Object.assign(mergedConfig, inlineConfig);
|
|
219
|
+
|
|
220
|
+
// Update the init config with merged result
|
|
221
|
+
this.#init = mergedConfig;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Waits for custom elements to be defined before mounting.
|
|
226
|
+
* Only runs once per observer instance.
|
|
227
|
+
*/
|
|
228
|
+
async #waitForWhenDefined(rootNode: Node): Promise<void> {
|
|
229
|
+
// Skip if already resolved or not configured
|
|
230
|
+
if (this.#whenDefinedResolved || !this.#init.whenDefined) {
|
|
231
|
+
return;
|
|
185
232
|
}
|
|
233
|
+
|
|
234
|
+
// Get the custom element registry from the root node
|
|
235
|
+
const registry = (rootNode as any).customElementRegistry || customElements;
|
|
236
|
+
|
|
237
|
+
// Normalize to array
|
|
238
|
+
const tagNames = arr(this.#init.whenDefined);
|
|
239
|
+
|
|
240
|
+
// Wait for all tags to be defined
|
|
241
|
+
await Promise.all(tagNames.map(tag => registry.whenDefined(tag)));
|
|
242
|
+
|
|
243
|
+
// Mark as resolved so we don't check again
|
|
244
|
+
this.#whenDefinedResolved = true;
|
|
186
245
|
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Creates and initializes sub-observers from the `with` property.
|
|
249
|
+
* Each sub-observer observes the same root node as the parent.
|
|
250
|
+
* Sub-observers are stored in #subObservers Map for lifecycle management.
|
|
251
|
+
*/
|
|
252
|
+
async #createSubObservers(rootNode: Node): Promise<void> {
|
|
253
|
+
const withConfig = this.#init.with;
|
|
254
|
+
if (!withConfig) return;
|
|
255
|
+
|
|
256
|
+
this.#subObservers = new Map();
|
|
257
|
+
|
|
258
|
+
for (const [key, subConfig] of Object.entries(withConfig)) {
|
|
259
|
+
const subObserver = new MountObserver(subConfig as MountConfig);
|
|
260
|
+
this.#subObservers.set(key, subObserver);
|
|
261
|
+
await subObserver.observe(rootNode);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
|
|
187
266
|
|
|
188
267
|
|
|
189
268
|
async #setupMediaQuery(): Promise<void> {
|
|
@@ -267,6 +346,17 @@ export class MountObserver extends EventTarget implements IMountObserver {
|
|
|
267
346
|
return this.#abortController.signal;
|
|
268
347
|
}
|
|
269
348
|
|
|
349
|
+
get mountedElements(): Element[] {
|
|
350
|
+
const elements: Element[] = [];
|
|
351
|
+
for (const ref of this.#mountedElements.setWeak) {
|
|
352
|
+
const element = ref.deref();
|
|
353
|
+
if (element !== undefined) {
|
|
354
|
+
elements.push(element);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
return elements;
|
|
358
|
+
}
|
|
359
|
+
|
|
270
360
|
getNotifier(element: Element): EventTarget {
|
|
271
361
|
// Return cached notifier if it exists
|
|
272
362
|
let notifier = this.#elementNotifiers.get(element);
|
|
@@ -280,10 +370,29 @@ export class MountObserver extends EventTarget implements IMountObserver {
|
|
|
280
370
|
return notifier;
|
|
281
371
|
}
|
|
282
372
|
|
|
283
|
-
|
|
373
|
+
/**
|
|
374
|
+
* Begins observing elements within the provided node.
|
|
375
|
+
*
|
|
376
|
+
* @param observedNode - The node to observe for matching elements. This is the root
|
|
377
|
+
* of the observation scope where the mutation observer will be
|
|
378
|
+
* registered. All matching elements within this node (and its
|
|
379
|
+
* descendants) will trigger mount callbacks.
|
|
380
|
+
*
|
|
381
|
+
* Common values:
|
|
382
|
+
* - `document` - Observe the entire document
|
|
383
|
+
* - `element` - Observe a specific subtree
|
|
384
|
+
* - `shadowRoot` - Observe within a shadow DOM
|
|
385
|
+
*/
|
|
386
|
+
async observe(observedNode: Node): Promise<void> {
|
|
284
387
|
if (this.#rootNode) {
|
|
285
388
|
throw new Error('Already observing');
|
|
286
389
|
}
|
|
390
|
+
|
|
391
|
+
// Wait for configFrom loading to complete if it was started
|
|
392
|
+
if (this.#configFromPromise) {
|
|
393
|
+
await this.#configFromPromise;
|
|
394
|
+
}
|
|
395
|
+
|
|
287
396
|
if(this.#asgMtSource || this.#asgDisMtSource){
|
|
288
397
|
await import('assign-gingerly/object-extension.js');
|
|
289
398
|
}
|
|
@@ -292,7 +401,13 @@ export class MountObserver extends EventTarget implements IMountObserver {
|
|
|
292
401
|
this.#assignTentatively = assignTentatively;
|
|
293
402
|
}
|
|
294
403
|
|
|
295
|
-
this.#rootNode = new WeakRef(
|
|
404
|
+
this.#rootNode = new WeakRef(observedNode);
|
|
405
|
+
|
|
406
|
+
// Wait for whenDefined if specified (must be first check)
|
|
407
|
+
await this.#waitForWhenDefined(observedNode);
|
|
408
|
+
|
|
409
|
+
// Create sub-observers from `with` property
|
|
410
|
+
await this.#createSubObservers(observedNode);
|
|
296
411
|
|
|
297
412
|
// Set up media query if specified (needs rootNode to be set first)
|
|
298
413
|
if (this.#init.withMediaMatching) {
|
|
@@ -321,7 +436,7 @@ export class MountObserver extends EventTarget implements IMountObserver {
|
|
|
321
436
|
|
|
322
437
|
// Process existing elements only if all conditions match
|
|
323
438
|
if (this.#mediaMatches && this.#rootSizeMatches && this.#connectionMatches) {
|
|
324
|
-
this.#processNode(
|
|
439
|
+
this.#processNode(observedNode);
|
|
325
440
|
}
|
|
326
441
|
|
|
327
442
|
// Create mutation callback
|
|
@@ -353,12 +468,21 @@ export class MountObserver extends EventTarget implements IMountObserver {
|
|
|
353
468
|
};
|
|
354
469
|
|
|
355
470
|
// Register with shared mutation observer
|
|
356
|
-
registerSharedObserver(
|
|
471
|
+
registerSharedObserver(observedNode, this.#mutationCallback, observerConfig);
|
|
357
472
|
}
|
|
358
473
|
|
|
359
474
|
disconnect(): void {
|
|
360
475
|
const rootNode = this.#rootNode?.deref();
|
|
361
476
|
|
|
477
|
+
// Disconnect all sub-observers first (recursive)
|
|
478
|
+
if (this.#subObservers) {
|
|
479
|
+
for (const subObserver of this.#subObservers.values()) {
|
|
480
|
+
subObserver.disconnect();
|
|
481
|
+
}
|
|
482
|
+
this.#subObservers.clear();
|
|
483
|
+
this.#subObservers = undefined;
|
|
484
|
+
}
|
|
485
|
+
|
|
362
486
|
// Unregister from shared mutation observer
|
|
363
487
|
if (rootNode && this.#mutationCallback) {
|
|
364
488
|
unregisterSharedObserver(rootNode, this.#mutationCallback);
|
|
@@ -403,26 +527,6 @@ export class MountObserver extends EventTarget implements IMountObserver {
|
|
|
403
527
|
this.#modules = await loadImports(this.#init.import);
|
|
404
528
|
this.#importsLoaded = true;
|
|
405
529
|
|
|
406
|
-
// Validate referenced whereInstanceOf if reference is specified
|
|
407
|
-
if (this.#init.reference !== undefined) {
|
|
408
|
-
const references = arr(this.#init.reference);
|
|
409
|
-
|
|
410
|
-
for (const index of references) {
|
|
411
|
-
const module = this.#modules[index];
|
|
412
|
-
if (module && module.whereInstanceOf !== undefined) {
|
|
413
|
-
// Validate that it's a Constructor or array of Constructors
|
|
414
|
-
const whereInstanceOf = module.whereInstanceOf;
|
|
415
|
-
const constructors = arr(whereInstanceOf);
|
|
416
|
-
|
|
417
|
-
for (const constructor of constructors) {
|
|
418
|
-
if (typeof constructor !== 'function') {
|
|
419
|
-
throw new Error(`Referenced module at index ${index} exports invalid whereInstanceOf: must be a Constructor or array of Constructors`);
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
|
|
426
530
|
this.dispatchEvent(new LoadEvent(this.#modules, this.#init));
|
|
427
531
|
}
|
|
428
532
|
|
|
@@ -445,7 +549,8 @@ export class MountObserver extends EventTarget implements IMountObserver {
|
|
|
445
549
|
const root = node as DocumentFragment;
|
|
446
550
|
|
|
447
551
|
// Get all elements matching the CSS selector first
|
|
448
|
-
root.querySelectorAll(this.#init.matching)
|
|
552
|
+
const matches = root.querySelectorAll(this.#init.matching);
|
|
553
|
+
matches.forEach(child => {
|
|
449
554
|
// If intersection observer is active, start observing the element
|
|
450
555
|
if (this.#intersectionObserver) {
|
|
451
556
|
this.#intersectionObserver.observe(child);
|
|
@@ -468,9 +573,22 @@ export class MountObserver extends EventTarget implements IMountObserver {
|
|
|
468
573
|
return false;
|
|
469
574
|
}
|
|
470
575
|
|
|
576
|
+
// Check that element's customElementRegistry matches root node's registry
|
|
577
|
+
const rootNode = this.#rootNode?.deref();
|
|
578
|
+
if (rootNode) {
|
|
579
|
+
const registriesMatch = (rootNode as any).customElementRegistry === (element as any).customElementRegistry;
|
|
580
|
+
|
|
581
|
+
// If whereDifferentCustomElementRegistry is true, exclude matching registries
|
|
582
|
+
if (this.#init.whereDifferentCustomElementRegistry) {
|
|
583
|
+
if (registriesMatch) return false;
|
|
584
|
+
} else {
|
|
585
|
+
// Default behavior: exclude non-matching registries
|
|
586
|
+
if (!registriesMatch) return false;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
471
590
|
// Check withScopePerimeter condition if specified (donut hole scoping)
|
|
472
591
|
if (this.#init.withScopePerimeter) {
|
|
473
|
-
const rootNode = this.#rootNode?.deref();
|
|
474
592
|
if (!rootNode || !withScopePerimeter(rootNode, element, this.#init.withScopePerimeter)) {
|
|
475
593
|
return false;
|
|
476
594
|
}
|
|
@@ -493,22 +611,14 @@ export class MountObserver extends EventTarget implements IMountObserver {
|
|
|
493
611
|
}
|
|
494
612
|
}
|
|
495
613
|
|
|
496
|
-
// Check
|
|
497
|
-
if (this.#
|
|
498
|
-
const
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
// Element must be an instance of at least one constructor (OR logic within this module)
|
|
506
|
-
const matchesInstanceOf = constructors.some((constructor: Constructor) => element instanceof constructor);
|
|
507
|
-
|
|
508
|
-
if (!matchesInstanceOf) {
|
|
509
|
-
return false;
|
|
510
|
-
}
|
|
511
|
-
}
|
|
614
|
+
// Check whereLocalNameMatches condition if specified
|
|
615
|
+
if (this.#init.whereLocalNameMatches) {
|
|
616
|
+
const pattern = typeof this.#init.whereLocalNameMatches === 'string'
|
|
617
|
+
? new RegExp(this.#init.whereLocalNameMatches)
|
|
618
|
+
: this.#init.whereLocalNameMatches;
|
|
619
|
+
|
|
620
|
+
if (!pattern.test(element.localName)) {
|
|
621
|
+
return false;
|
|
512
622
|
}
|
|
513
623
|
}
|
|
514
624
|
|
|
@@ -541,12 +651,55 @@ export class MountObserver extends EventTarget implements IMountObserver {
|
|
|
541
651
|
return;
|
|
542
652
|
}
|
|
543
653
|
|
|
544
|
-
const context: MountContext = {
|
|
654
|
+
const context: MountContext<TKeys> = {
|
|
545
655
|
modules: this.#modules,
|
|
546
656
|
observer: this,
|
|
547
657
|
rootNode,
|
|
548
|
-
|
|
658
|
+
mountConfig: this.#init,
|
|
549
659
|
};
|
|
660
|
+
|
|
661
|
+
// Add withObservers if sub-observers exist
|
|
662
|
+
if (this.#subObservers && this.#subObservers.size > 0) {
|
|
663
|
+
context.withObservers = {} as {[K in TKeys]: IMountObserver};
|
|
664
|
+
for (const [key, subObserver] of this.#subObservers.entries()) {
|
|
665
|
+
(context.withObservers as any)[key] = subObserver;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
// Check shouldMount condition if specified (final gate before mounting)
|
|
670
|
+
if (this.#init.shouldMount) {
|
|
671
|
+
try {
|
|
672
|
+
const shouldMount = this.#init.shouldMount(element, context);
|
|
673
|
+
if (!shouldMount) {
|
|
674
|
+
// shouldMount returned false - don't mount this element
|
|
675
|
+
// Remove from processed set so it can be re-evaluated later
|
|
676
|
+
this.#processedDoForElement.delete(element);
|
|
677
|
+
// Remove from mounted elements tracking
|
|
678
|
+
this.#mountedElements.weakSet.delete(element);
|
|
679
|
+
for (const ref of this.#mountedElements.setWeak) {
|
|
680
|
+
if (ref.deref() === element) {
|
|
681
|
+
this.#mountedElements.setWeak.delete(ref);
|
|
682
|
+
break;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
} catch (error) {
|
|
688
|
+
// shouldMount threw an error - treat as false and log
|
|
689
|
+
console.error('shouldMount check failed:', error);
|
|
690
|
+
// Remove from processed set so it can be re-evaluated later
|
|
691
|
+
this.#processedDoForElement.delete(element);
|
|
692
|
+
// Remove from mounted elements tracking
|
|
693
|
+
this.#mountedElements.weakSet.delete(element);
|
|
694
|
+
for (const ref of this.#mountedElements.setWeak) {
|
|
695
|
+
if (ref.deref() === element) {
|
|
696
|
+
this.#mountedElements.setWeak.delete(ref);
|
|
697
|
+
break;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
550
703
|
|
|
551
704
|
// Apply assignGingerly if specified
|
|
552
705
|
if (this.#asgMtSource) {
|
|
@@ -581,18 +734,6 @@ export class MountObserver extends EventTarget implements IMountObserver {
|
|
|
581
734
|
}
|
|
582
735
|
}
|
|
583
736
|
|
|
584
|
-
// Call referenced do functions from imported modules
|
|
585
|
-
if (this.#init.reference !== undefined) {
|
|
586
|
-
const references = arr(this.#init.reference);
|
|
587
|
-
|
|
588
|
-
for (const index of references) {
|
|
589
|
-
const module = this.#modules[index];
|
|
590
|
-
if (module && typeof module.do === 'function') {
|
|
591
|
-
module.do(element, context);
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
|
|
596
737
|
// Dispatch mount event
|
|
597
738
|
const mountEvent = new MountEvent(element, this.#modules, this.#init, context);
|
|
598
739
|
this.dispatchEvent(mountEvent);
|
|
@@ -683,12 +824,20 @@ export class MountObserver extends EventTarget implements IMountObserver {
|
|
|
683
824
|
return;
|
|
684
825
|
}
|
|
685
826
|
|
|
686
|
-
const context: MountContext = {
|
|
827
|
+
const context: MountContext<TKeys> = {
|
|
687
828
|
modules: this.#modules,
|
|
688
829
|
observer: this,
|
|
689
830
|
rootNode,
|
|
690
|
-
|
|
831
|
+
mountConfig: this.#init,
|
|
691
832
|
};
|
|
833
|
+
|
|
834
|
+
// Add withObservers if sub-observers exist
|
|
835
|
+
if (this.#subObservers && this.#subObservers.size > 0) {
|
|
836
|
+
context.withObservers = {} as {[K in TKeys]: IMountObserver};
|
|
837
|
+
for (const [key, subObserver] of this.#subObservers.entries()) {
|
|
838
|
+
(context.withObservers as any)[key] = subObserver;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
692
841
|
|
|
693
842
|
|
|
694
843
|
// Dispatch dismount event
|