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.
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Coordinates MountObserver instances across multiple DOM scopes that share
3
+ * the same CustomElementRegistry. This enables "mutually assured observing"
4
+ * where all scopes with the same registry share mount observers.
5
+ */
6
+ const regObsGuid = 'iqj6MOueu0OP4CQi1a_4Sw';
7
+ /**
8
+ * Maps CustomElementRegistry -> Map<MountConfig, WeakMap<Node, ObserverEntry>>
9
+ * The MountConfig object itself is used as the key (object identity).
10
+ * The innermost WeakMap maps registry root nodes to their observer entries.
11
+ */
12
+ export function getRegistryObservers() {
13
+ if (!globalThis[regObsGuid]) {
14
+ globalThis[regObsGuid] = new WeakMap();
15
+ }
16
+ return globalThis[regObsGuid];
17
+ }
18
+ const registryScopeId = 'pt9dS-V7U0SC3Yk708_5Ww';
19
+ /**
20
+ * Tracks all registry root nodes for each CustomElementRegistry.
21
+ * Used to iterate over all scopes when a new config is added.
22
+ */
23
+ export function getRegistryScopes() {
24
+ if (!globalThis[registryScopeId]) {
25
+ globalThis[registryScopeId] = new WeakMap();
26
+ }
27
+ return globalThis[registryScopeId];
28
+ }
29
+ // const registryScopes = new WeakMap<
30
+ // CustomElementRegistry,
31
+ // WeakDual<Node>
32
+ // >();
33
+ // Note: assignGingerly.ts already has a polyfill for getOrInsertComputed.
34
+ // If this code will already have imported assignGingerly, then no need for the duplicate polyfill below.
35
+ // Polyfill for Map.prototype.getOrInsertComputed and WeakMap.prototype.getOrInsertComputed
36
+ if (typeof Map.prototype.getOrInsertComputed !== 'function') {
37
+ Map.prototype.getOrInsertComputed = function (key, insert) {
38
+ if (this.has(key))
39
+ return this.get(key);
40
+ const value = insert();
41
+ this.set(key, value);
42
+ return value;
43
+ };
44
+ }
45
+ if (typeof WeakMap.prototype.getOrInsertComputed !== 'function') {
46
+ WeakMap.prototype.getOrInsertComputed = function (key, insert) {
47
+ if (this.has(key))
48
+ return this.get(key);
49
+ const value = insert();
50
+ this.set(key, value);
51
+ return value;
52
+ };
53
+ }
54
+ /**
55
+ * Helper to create an observer entry asynchronously.
56
+ * Separated to handle async operations cleanly.
57
+ */
58
+ async function createObserverEntry(config, registryRoot) {
59
+ // Dynamically import to avoid circular dependency
60
+ const { MountObserver: MountObserverClass } = await import('./MountObserver.js');
61
+ const observer = new MountObserverClass(config);
62
+ await observer.observe(registryRoot);
63
+ return {
64
+ config,
65
+ registryRootRef: new WeakRef(registryRoot),
66
+ observer
67
+ };
68
+ }
69
+ /**
70
+ * Get or create a mount observer for a specific registry + config + registry root combination.
71
+ * This function ensures that:
72
+ * 1. The config is registered with the registry's mountConfigRegistry
73
+ * 2. An observer exists for this specific registry root
74
+ * 3. All other registry roots with the same registry get observers for this config
75
+ * 4. All other configs get observers for this registry root
76
+ *
77
+ * @returns The ObserverEntry for the requested combination
78
+ */
79
+ export async function getOrInsertObserverEntry(registry, config, registryRoot) {
80
+ // Add config to the registry's config list (if not already there)
81
+ registry.mountConfigRegistry.push(config);
82
+ // Get or create the nested map structure
83
+ const mountConfigMap = (getRegistryObservers()).getOrInsertComputed(registry, () => new Map());
84
+ const nodeToObserverMap = mountConfigMap.getOrInsertComputed(config, () => new WeakMap());
85
+ // Get or create the observer for this specific registry root
86
+ let observerEntry = nodeToObserverMap.get(registryRoot);
87
+ if (!observerEntry) {
88
+ observerEntry = await createObserverEntry(config, registryRoot);
89
+ nodeToObserverMap.set(registryRoot, observerEntry);
90
+ }
91
+ // Track this registry root in the scopes set
92
+ const scopes = getRegistryScopes().getOrInsertComputed(registry, () => ({
93
+ weakSet: new WeakSet(),
94
+ setWeak: new Set()
95
+ }));
96
+ // Add to tracking sets if not already present
97
+ if (!scopes.weakSet.has(registryRoot)) {
98
+ scopes.weakSet.add(registryRoot);
99
+ scopes.setWeak.add(new WeakRef(registryRoot));
100
+ }
101
+ // Get all configs for this registry
102
+ const configs = registry.mountConfigRegistry.items;
103
+ // Iterate over all known registry roots for this registry
104
+ const arr = Array.from(scopes.setWeak);
105
+ for (const regRootRef of arr) {
106
+ const regRoot = regRootRef.deref();
107
+ if (regRoot === undefined)
108
+ continue;
109
+ // For each config, ensure an observer exists for this registry root
110
+ for (const conf of configs) {
111
+ // Skip if this is the same config + root we just created
112
+ if (conf === config && registryRoot === regRoot)
113
+ continue;
114
+ // Get or create observer for this conf + regRoot combination
115
+ // This won't cause infinite loop because we only create if missing
116
+ const confObserverMap = mountConfigMap.getOrInsertComputed(conf, () => new WeakMap());
117
+ let existingEntry = confObserverMap.get(regRoot);
118
+ if (!existingEntry) {
119
+ existingEntry = await createObserverEntry(conf, regRoot);
120
+ confObserverMap.set(regRoot, existingEntry);
121
+ }
122
+ }
123
+ }
124
+ return observerEntry;
125
+ }
@@ -0,0 +1,181 @@
1
+ /**
2
+ * Coordinates MountObserver instances across multiple DOM scopes that share
3
+ * the same CustomElementRegistry. This enables "mutually assured observing"
4
+ * where all scopes with the same registry share mount observers.
5
+ */
6
+
7
+ import type { MountConfig, WeakDual } from './types/mount-observer/types.js';
8
+ import type { MountObserver } from './MountObserver.js';
9
+
10
+ /**
11
+ * Represents a single MountObserver observing a specific registry root.
12
+ */
13
+ type ObserverEntry = {
14
+ config: MountConfig; // Store for reference
15
+ registryRootRef: WeakRef<Node>;
16
+ observer: MountObserver;
17
+ };
18
+
19
+ const regObsGuid = 'iqj6MOueu0OP4CQi1a_4Sw';
20
+
21
+ export type CER2MC2N2OE = WeakMap<
22
+ CustomElementRegistry,
23
+ Map<
24
+ MountConfig,
25
+ WeakMap<Node, ObserverEntry>
26
+ >
27
+ >
28
+
29
+ /**
30
+ * Maps CustomElementRegistry -> Map<MountConfig, WeakMap<Node, ObserverEntry>>
31
+ * The MountConfig object itself is used as the key (object identity).
32
+ * The innermost WeakMap maps registry root nodes to their observer entries.
33
+ */
34
+ export function getRegistryObservers(): CER2MC2N2OE{
35
+ if (!(globalThis as any)[regObsGuid]) {
36
+ (globalThis as any)[regObsGuid] = new WeakMap<CustomElementRegistry,
37
+ Map<
38
+ MountConfig,
39
+ WeakMap<Node, ObserverEntry>
40
+ >
41
+ >();
42
+ }
43
+ return (globalThis as any)[regObsGuid] as CER2MC2N2OE;
44
+ }
45
+
46
+
47
+ const registryScopeId = 'pt9dS-V7U0SC3Yk708_5Ww';
48
+
49
+ export type CER2WD = WeakMap<
50
+ CustomElementRegistry,
51
+ WeakDual<Node>
52
+ >
53
+
54
+ /**
55
+ * Tracks all registry root nodes for each CustomElementRegistry.
56
+ * Used to iterate over all scopes when a new config is added.
57
+ */
58
+ export function getRegistryScopes(): CER2WD{
59
+ if (!(globalThis as any)[registryScopeId]) {
60
+ (globalThis as any)[registryScopeId] = new WeakMap<
61
+ CustomElementRegistry,
62
+ WeakDual<Node>
63
+ >();
64
+ }
65
+ return (globalThis as any)[registryScopeId] as CER2WD;
66
+ }
67
+
68
+
69
+ // const registryScopes = new WeakMap<
70
+ // CustomElementRegistry,
71
+ // WeakDual<Node>
72
+ // >();
73
+
74
+ // Note: assignGingerly.ts already has a polyfill for getOrInsertComputed.
75
+ // If this code will already have imported assignGingerly, then no need for the duplicate polyfill below.
76
+
77
+ // Polyfill for Map.prototype.getOrInsertComputed and WeakMap.prototype.getOrInsertComputed
78
+ if (typeof Map.prototype.getOrInsertComputed !== 'function') {
79
+ (Map.prototype as any).getOrInsertComputed = function(key: any, insert: () => any) {
80
+ if (this.has(key)) return this.get(key);
81
+ const value = insert();
82
+ this.set(key, value);
83
+ return value;
84
+ };
85
+ }
86
+ if (typeof WeakMap.prototype.getOrInsertComputed !== 'function') {
87
+ (WeakMap.prototype as any).getOrInsertComputed = function(key: any, insert: () => any) {
88
+ if (this.has(key)) return this.get(key);
89
+ const value = insert();
90
+ this.set(key, value);
91
+ return value;
92
+ };
93
+ }
94
+
95
+ /**
96
+ * Helper to create an observer entry asynchronously.
97
+ * Separated to handle async operations cleanly.
98
+ */
99
+ async function createObserverEntry(
100
+ config: MountConfig,
101
+ registryRoot: Node
102
+ ): Promise<ObserverEntry> {
103
+ // Dynamically import to avoid circular dependency
104
+ const { MountObserver: MountObserverClass } = await import('./MountObserver.js');
105
+ const observer = new MountObserverClass(config);
106
+ await observer.observe(registryRoot);
107
+ return {
108
+ config,
109
+ registryRootRef: new WeakRef(registryRoot),
110
+ observer
111
+ };
112
+ }
113
+
114
+ /**
115
+ * Get or create a mount observer for a specific registry + config + registry root combination.
116
+ * This function ensures that:
117
+ * 1. The config is registered with the registry's mountConfigRegistry
118
+ * 2. An observer exists for this specific registry root
119
+ * 3. All other registry roots with the same registry get observers for this config
120
+ * 4. All other configs get observers for this registry root
121
+ *
122
+ * @returns The ObserverEntry for the requested combination
123
+ */
124
+ export async function getOrInsertObserverEntry(
125
+ registry: CustomElementRegistry,
126
+ config: MountConfig,
127
+ registryRoot: Node
128
+ ): Promise<ObserverEntry> {
129
+ // Add config to the registry's config list (if not already there)
130
+ (registry as any).mountConfigRegistry.push(config);
131
+
132
+ // Get or create the nested map structure
133
+ const mountConfigMap = (getRegistryObservers()).getOrInsertComputed(registry, () => new Map());
134
+ const nodeToObserverMap = mountConfigMap.getOrInsertComputed(config, () => new WeakMap());
135
+
136
+ // Get or create the observer for this specific registry root
137
+ let observerEntry = nodeToObserverMap.get(registryRoot);
138
+ if (!observerEntry) {
139
+ observerEntry = await createObserverEntry(config, registryRoot);
140
+ nodeToObserverMap.set(registryRoot, observerEntry);
141
+ }
142
+
143
+ // Track this registry root in the scopes set
144
+ const scopes = getRegistryScopes().getOrInsertComputed(registry, () => ({
145
+ weakSet: new WeakSet<Node>(),
146
+ setWeak: new Set<WeakRef<Node>>()
147
+ }));
148
+
149
+ // Add to tracking sets if not already present
150
+ if (!scopes.weakSet.has(registryRoot)) {
151
+ scopes.weakSet.add(registryRoot);
152
+ scopes.setWeak.add(new WeakRef(registryRoot));
153
+ }
154
+
155
+ // Get all configs for this registry
156
+ const configs = (registry as any).mountConfigRegistry.items;
157
+
158
+ // Iterate over all known registry roots for this registry
159
+ const arr = Array.from(scopes.setWeak) as WeakRef<Node>[];
160
+ for (const regRootRef of arr) {
161
+ const regRoot = regRootRef.deref();
162
+ if (regRoot === undefined) continue;
163
+
164
+ // For each config, ensure an observer exists for this registry root
165
+ for (const conf of configs) {
166
+ // Skip if this is the same config + root we just created
167
+ if (conf === config && registryRoot === regRoot) continue;
168
+
169
+ // Get or create observer for this conf + regRoot combination
170
+ // This won't cause infinite loop because we only create if missing
171
+ const confObserverMap = mountConfigMap.getOrInsertComputed(conf, () => new WeakMap());
172
+ let existingEntry = confObserverMap.get(regRoot);
173
+ if (!existingEntry) {
174
+ existingEntry = await createObserverEntry(conf, regRoot);
175
+ confObserverMap.set(regRoot, existingEntry);
176
+ }
177
+ }
178
+ }
179
+
180
+ return observerEntry;
181
+ }
@@ -47,7 +47,7 @@ export function setupConnectionMonitor(init, rootNodeRef, mountedElements, modul
47
47
  modules,
48
48
  observer: observer,
49
49
  rootNode,
50
- MountConfig: init
50
+ mountConfig: init
51
51
  };
52
52
  // Get all mounted elements from the WeakDual setWeak
53
53
  const mountedElementsList = [];
@@ -82,7 +82,7 @@ export function setupConnectionMonitor(
82
82
  modules,
83
83
  observer: observer as any,
84
84
  rootNode,
85
- MountConfig: init
85
+ mountConfig: init
86
86
  };
87
87
 
88
88
  // Get all mounted elements from the WeakDual setWeak
@@ -6,7 +6,7 @@
6
6
  * @param node - The starting node to check
7
7
  * @returns The highest node with matching customElementRegistry, or null if node is invalid
8
8
  */
9
- export function getRootRegistryContainer(node) {
9
+ export function getRegistryRoot(node) {
10
10
  if (!node) {
11
11
  return null;
12
12
  }
@@ -6,7 +6,7 @@
6
6
  * @param node - The starting node to check
7
7
  * @returns The highest node with matching customElementRegistry, or null if node is invalid
8
8
  */
9
- export function getRootRegistryContainer(node: Node): Node | null {
9
+ export function getRegistryRoot(node: Node): Node | null {
10
10
  if (!node) {
11
11
  return null;
12
12
  }
package/index.js CHANGED
@@ -4,15 +4,20 @@ export { withScopePerimeter } from './withScopePerimeter.js';
4
4
  export { emitMountedElementEvents } from './emitEvents.js';
5
5
  export { arr } from './arr.js';
6
6
  export { EvtRt } from './EvtRt.js';
7
- export { DefineCustomElementHandler } from './DefineCustomElementHandler.js';
8
- export { EnhanceMountedElementHandler } from './EnhanceMountedElementHandler.js';
7
+ export { DefineCustomElementHandler, DefineScopedCustomElementHandler } from './handlers/DefineCustomElement.js';
8
+ export { EnhanceMountedElementHandler } from './handlers/EnhanceMountedElement.js';
9
+ export { ScriptExportHandler } from './handlers/ScriptExport.js';
10
+ export { MountObserverScriptHandler } from './handlers/MountObserverScript.js';
11
+ export { HoistTemplateHandler } from './handlers/HoistTemplate.js';
12
+ export { HTMLIncludeHandler } from './handlers/HTMLInclude.js';
13
+ export { upShadowSearch } from './upShadowSearch.js';
9
14
  export { mountEventName, dismountEventName, disconnectEventName, loadEventName, mediamatchEventName, mediaunmatchEventName } from './Events.js';
10
15
  // Register built-in handlers
11
- import { MountObserver } from './MountObserver.js';
12
- import { EvtRt } from './EvtRt.js';
13
- import { DefineCustomElementHandler, DefineScopedCustomElementHandler } from './DefineCustomElementHandler.js';
14
- import { EnhanceMountedElementHandler } from './EnhanceMountedElementHandler.js';
15
- MountObserver.define('builtIns.logToConsole', EvtRt);
16
- MountObserver.define('builtIns.defineCustomElement', DefineCustomElementHandler);
17
- MountObserver.define('buildIns.defineScopedCustomElement', DefineScopedCustomElementHandler);
18
- MountObserver.define('builtIns.enhanceMountedElement', EnhanceMountedElementHandler);
16
+ import './EvtRt.js';
17
+ import './handlers/DefineCustomElement.js';
18
+ import './handlers/EnhanceMountedElement.js';
19
+ import './handlers/GenIds.js'; // Temporarily disabled due to missing dependency
20
+ import './handlers/ScriptExport.js';
21
+ import './handlers/MountObserverScript.js';
22
+ import './handlers/HoistTemplate.js';
23
+ import './handlers/HTMLInclude.js';
package/index.ts CHANGED
@@ -4,8 +4,13 @@ export { withScopePerimeter } from './withScopePerimeter.js';
4
4
  export { emitMountedElementEvents } from './emitEvents.js';
5
5
  export { arr } from './arr.js';
6
6
  export { EvtRt } from './EvtRt.js';
7
- export { DefineCustomElementHandler } from './DefineCustomElementHandler.js';
8
- export { EnhanceMountedElementHandler } from './EnhanceMountedElementHandler.js';
7
+ export { DefineCustomElementHandler, DefineScopedCustomElementHandler } from './handlers/DefineCustomElement.js';
8
+ export { EnhanceMountedElementHandler } from './handlers/EnhanceMountedElement.js';
9
+ export { ScriptExportHandler } from './handlers/ScriptExport.js';
10
+ export { MountObserverScriptHandler } from './handlers/MountObserverScript.js';
11
+ export { HoistTemplateHandler } from './handlers/HoistTemplate.js';
12
+ export { HTMLIncludeHandler } from './handlers/HTMLInclude.js';
13
+ export { upShadowSearch } from './upShadowSearch.js';
9
14
  export type {
10
15
  MountConfig,
11
16
  MountObserverOptions,
@@ -26,12 +31,12 @@ export {
26
31
  } from './Events.js';
27
32
 
28
33
  // Register built-in handlers
29
- import { MountObserver } from './MountObserver.js';
30
- import { EvtRt } from './EvtRt.js';
31
- import { DefineCustomElementHandler, DefineScopedCustomElementHandler } from './DefineCustomElementHandler.js';
32
- import { EnhanceMountedElementHandler } from './EnhanceMountedElementHandler.js';
34
+ import './EvtRt.js';
35
+ import './handlers/DefineCustomElement.js';
36
+ import './handlers/EnhanceMountedElement.js';
37
+ import './handlers/GenIds.js'; // Temporarily disabled due to missing dependency
38
+ import './handlers/ScriptExport.js';
39
+ import './handlers/MountObserverScript.js';
40
+ import './handlers/HoistTemplate.js';
41
+ import './handlers/HTMLInclude.js';
33
42
 
34
- MountObserver.define('builtIns.logToConsole', EvtRt);
35
- MountObserver.define('builtIns.defineCustomElement', DefineCustomElementHandler);
36
- MountObserver.define('buildIns.defineScopedCustomElement', DefineScopedCustomElementHandler);
37
- MountObserver.define('builtIns.enhanceMountedElement', EnhanceMountedElementHandler);
package/mediaQuery.js CHANGED
@@ -49,7 +49,7 @@ export function setupMediaQuery(init, rootNodeRef, mountedElements, modules, obs
49
49
  modules,
50
50
  observer: observer,
51
51
  rootNode,
52
- MountConfig: init
52
+ mountConfig: init
53
53
  };
54
54
  // Get all mounted elements from the WeakDual setWeak
55
55
  const mountedElementsList = [];
package/mediaQuery.ts CHANGED
@@ -70,7 +70,7 @@ export function setupMediaQuery(
70
70
  modules,
71
71
  observer: observer as any,
72
72
  rootNode,
73
- MountConfig: init
73
+ mountConfig: init
74
74
  };
75
75
 
76
76
  // Get all mounted elements from the WeakDual setWeak
@@ -1,87 +1,87 @@
1
- import { DismountEvent } from './Events.js';
2
- export function setupObservedRootHas(init, rootNodeRef, mountedElements, modules, observer, processNode) {
3
- const { whereObservedRootHas } = init;
4
- if (!whereObservedRootHas) {
5
- throw new Error('whereObservedRootHas is required');
6
- }
7
- const rootNode = rootNodeRef.deref();
8
- if (!rootNode) {
9
- throw new Error('Root node has been garbage collected');
10
- }
11
- // Get the element to query against
12
- const rootElement = rootNode instanceof Element
13
- ? rootNode
14
- : rootNode.documentElement || rootNode.host;
15
- if (!rootElement) {
16
- throw new Error('Could not determine root element for whereObservedRootHas');
17
- }
18
- // Track current state
19
- let conditionMatches = !!rootElement.querySelector(whereObservedRootHas);
20
- // Set up mutation observer to watch for changes
21
- const mutationObserver = new MutationObserver(() => {
22
- const previousMatches = conditionMatches;
23
- conditionMatches = !!rootElement.querySelector(whereObservedRootHas);
24
- if (conditionMatches && !previousMatches) {
25
- // Condition now matches - process elements
26
- handleConditionMatch();
27
- }
28
- else if (!conditionMatches && previousMatches) {
29
- // Condition no longer matches - dismount all elements
30
- handleConditionUnmatch();
31
- }
32
- });
33
- function handleConditionMatch() {
34
- // Process all elements in the observed node
35
- const rootNode = rootNodeRef.deref();
36
- if (rootNode) {
37
- processNode(rootNode);
38
- }
39
- }
40
- function handleConditionUnmatch() {
41
- // Dismount all currently mounted elements
42
- const rootNode = rootNodeRef.deref();
43
- if (!rootNode) {
44
- return;
45
- }
46
- const context = {
47
- modules,
48
- observer: observer,
49
- rootNode,
50
- MountConfig: init
51
- };
52
- // Get all mounted elements from the WeakDual setWeak
53
- const mountedElementsList = [];
54
- for (const ref of mountedElements.setWeak) {
55
- const element = ref.deref();
56
- if (element) {
57
- mountedElementsList.push(element);
58
- }
59
- }
60
- // Dismount each element
61
- for (const element of mountedElementsList) {
62
- // Remove from both structures
63
- mountedElements.weakSet.delete(element);
64
- for (const ref of mountedElements.setWeak) {
65
- if (ref.deref() === element) {
66
- mountedElements.setWeak.delete(ref);
67
- break;
68
- }
69
- }
70
- // Dispatch dismount event with reason
71
- observer.dispatchEvent(new DismountEvent(element, 'observed-root-has-failed', init));
72
- }
73
- }
74
- // Observe the root element for changes
75
- mutationObserver.observe(rootElement, {
76
- childList: true,
77
- subtree: true,
78
- attributes: true,
79
- attributeOldValue: false
80
- });
81
- return {
82
- conditionMatches,
83
- cleanup: () => {
84
- mutationObserver.disconnect();
85
- }
86
- };
87
- }
1
+ import { DismountEvent } from './Events.js';
2
+ export function setupObservedRootHas(init, rootNodeRef, mountedElements, modules, observer, processNode) {
3
+ const { whereObservedRootHas } = init;
4
+ if (!whereObservedRootHas) {
5
+ throw new Error('whereObservedRootHas is required');
6
+ }
7
+ const rootNode = rootNodeRef.deref();
8
+ if (!rootNode) {
9
+ throw new Error('Root node has been garbage collected');
10
+ }
11
+ // Get the element to query against
12
+ const rootElement = rootNode instanceof Element
13
+ ? rootNode
14
+ : rootNode.documentElement || rootNode.host;
15
+ if (!rootElement) {
16
+ throw new Error('Could not determine root element for whereObservedRootHas');
17
+ }
18
+ // Track current state
19
+ let conditionMatches = !!rootElement.querySelector(whereObservedRootHas);
20
+ // Set up mutation observer to watch for changes
21
+ const mutationObserver = new MutationObserver(() => {
22
+ const previousMatches = conditionMatches;
23
+ conditionMatches = !!rootElement.querySelector(whereObservedRootHas);
24
+ if (conditionMatches && !previousMatches) {
25
+ // Condition now matches - process elements
26
+ handleConditionMatch();
27
+ }
28
+ else if (!conditionMatches && previousMatches) {
29
+ // Condition no longer matches - dismount all elements
30
+ handleConditionUnmatch();
31
+ }
32
+ });
33
+ function handleConditionMatch() {
34
+ // Process all elements in the observed node
35
+ const rootNode = rootNodeRef.deref();
36
+ if (rootNode) {
37
+ processNode(rootNode);
38
+ }
39
+ }
40
+ function handleConditionUnmatch() {
41
+ // Dismount all currently mounted elements
42
+ const rootNode = rootNodeRef.deref();
43
+ if (!rootNode) {
44
+ return;
45
+ }
46
+ const context = {
47
+ modules,
48
+ observer: observer,
49
+ rootNode,
50
+ MountConfig: init
51
+ };
52
+ // Get all mounted elements from the WeakDual setWeak
53
+ const mountedElementsList = [];
54
+ for (const ref of mountedElements.setWeak) {
55
+ const element = ref.deref();
56
+ if (element) {
57
+ mountedElementsList.push(element);
58
+ }
59
+ }
60
+ // Dismount each element
61
+ for (const element of mountedElementsList) {
62
+ // Remove from both structures
63
+ mountedElements.weakSet.delete(element);
64
+ for (const ref of mountedElements.setWeak) {
65
+ if (ref.deref() === element) {
66
+ mountedElements.setWeak.delete(ref);
67
+ break;
68
+ }
69
+ }
70
+ // Dispatch dismount event with reason
71
+ observer.dispatchEvent(new DismountEvent(element, 'observed-root-has-failed', init));
72
+ }
73
+ }
74
+ // Observe the root element for changes
75
+ mutationObserver.observe(rootElement, {
76
+ childList: true,
77
+ subtree: true,
78
+ attributes: true,
79
+ attributeOldValue: false
80
+ });
81
+ return {
82
+ conditionMatches,
83
+ cleanup: () => {
84
+ mutationObserver.disconnect();
85
+ }
86
+ };
87
+ }