mount-observer 0.0.5 → 0.0.6
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/MountObserver.js +64 -19
- package/RootMutObs.js +3 -0
- package/package.json +1 -1
- package/types.d.ts +13 -4
package/MountObserver.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { RootMutObs } from './RootMutObs.js';
|
|
2
2
|
const mutationObserverLookup = new WeakMap();
|
|
3
|
+
const refCount = new WeakMap();
|
|
3
4
|
export class MountObserver extends EventTarget {
|
|
4
5
|
#mountInit;
|
|
5
6
|
#rootMutObs;
|
|
@@ -44,17 +45,52 @@ export class MountObserver extends EventTarget {
|
|
|
44
45
|
this.#calculatedSelector = matches.join(',');
|
|
45
46
|
return this.#calculatedSelector;
|
|
46
47
|
}
|
|
48
|
+
unobserve(within) {
|
|
49
|
+
const nodeToMonitor = this.#isComplex ? (within instanceof ShadowRoot ? within : within.getRootNode()) : within;
|
|
50
|
+
const currentCount = refCount.get(nodeToMonitor);
|
|
51
|
+
if (currentCount !== undefined) {
|
|
52
|
+
if (currentCount <= 1) {
|
|
53
|
+
const observer = mutationObserverLookup.get(nodeToMonitor);
|
|
54
|
+
if (observer === undefined) {
|
|
55
|
+
console.warn(refCountErr);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
observer.disconnect();
|
|
59
|
+
mutationObserverLookup.delete(nodeToMonitor);
|
|
60
|
+
refCount.delete(nodeToMonitor);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
refCount.set(nodeToMonitor, currentCount + 1);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
if (mutationObserverLookup.has(nodeToMonitor)) {
|
|
69
|
+
console.warn(refCountErr);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
47
73
|
async observe(within) {
|
|
48
74
|
const nodeToMonitor = this.#isComplex ? (within instanceof ShadowRoot ? within : within.getRootNode()) : within;
|
|
49
75
|
if (!mutationObserverLookup.has(nodeToMonitor)) {
|
|
50
76
|
mutationObserverLookup.set(nodeToMonitor, new RootMutObs(nodeToMonitor));
|
|
77
|
+
refCount.set(nodeToMonitor, 1);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
const currentCount = refCount.get(nodeToMonitor);
|
|
81
|
+
if (currentCount === undefined) {
|
|
82
|
+
console.warn(refCountErr);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
refCount.set(nodeToMonitor, currentCount + 1);
|
|
86
|
+
}
|
|
51
87
|
}
|
|
52
88
|
const rootMutObs = mutationObserverLookup.get(within);
|
|
53
89
|
const { attribMatches } = this.#mountInit;
|
|
54
90
|
rootMutObs.addEventListener('mutation-event', (e) => {
|
|
55
91
|
//TODO: disconnected
|
|
56
92
|
if (this.#isComplex) {
|
|
57
|
-
this.#inspectWithin(within);
|
|
93
|
+
this.#inspectWithin(within, false);
|
|
58
94
|
return;
|
|
59
95
|
}
|
|
60
96
|
const { mutationRecords } = e;
|
|
@@ -109,9 +145,11 @@ export class MountObserver extends EventTarget {
|
|
|
109
145
|
this.dispatchEvent(new DisconnectEvent(deletedElement));
|
|
110
146
|
}
|
|
111
147
|
}
|
|
112
|
-
this.#filterAndMount(elsToInspect, true);
|
|
148
|
+
this.#filterAndMount(elsToInspect, true, false);
|
|
113
149
|
}, { signal: this.#abortController.signal });
|
|
114
|
-
|
|
150
|
+
//if(ignoreInitialMatches !== true){
|
|
151
|
+
await this.#inspectWithin(within, true);
|
|
152
|
+
//}
|
|
115
153
|
}
|
|
116
154
|
#confirmInstanceOf(el, whereInstanceOf) {
|
|
117
155
|
for (const test of whereInstanceOf) {
|
|
@@ -120,7 +158,7 @@ export class MountObserver extends EventTarget {
|
|
|
120
158
|
}
|
|
121
159
|
return false;
|
|
122
160
|
}
|
|
123
|
-
async #mount(matching) {
|
|
161
|
+
async #mount(matching, initializing) {
|
|
124
162
|
//first unmount non matching
|
|
125
163
|
const alreadyMounted = this.#filterAndDismount();
|
|
126
164
|
const onMount = this.#mountInit.do?.onMount;
|
|
@@ -141,13 +179,20 @@ export class MountObserver extends EventTarget {
|
|
|
141
179
|
}
|
|
142
180
|
break;
|
|
143
181
|
case 'function':
|
|
144
|
-
this.module = await imp(match, this,
|
|
182
|
+
this.module = await imp(match, this, {
|
|
183
|
+
stage: 'Import',
|
|
184
|
+
initializing
|
|
185
|
+
});
|
|
145
186
|
break;
|
|
146
187
|
}
|
|
147
188
|
}
|
|
148
|
-
if (onMount !== undefined)
|
|
149
|
-
onMount(match, this,
|
|
150
|
-
|
|
189
|
+
if (onMount !== undefined) {
|
|
190
|
+
onMount(match, this, {
|
|
191
|
+
stage: 'PostImport',
|
|
192
|
+
initializing
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
this.dispatchEvent(new MountEvent(match, initializing));
|
|
151
196
|
if (attribMatches !== undefined) {
|
|
152
197
|
let idx = 0;
|
|
153
198
|
for (const attribMatch of attribMatches) {
|
|
@@ -178,7 +223,7 @@ export class MountObserver extends EventTarget {
|
|
|
178
223
|
const onDismount = this.#mountInit.do?.onDismount;
|
|
179
224
|
for (const unmatch of unmatching) {
|
|
180
225
|
if (onDismount !== undefined) {
|
|
181
|
-
onDismount(unmatch, this);
|
|
226
|
+
onDismount(unmatch, this, {});
|
|
182
227
|
}
|
|
183
228
|
this.dispatchEvent(new DismountEvent(unmatch));
|
|
184
229
|
}
|
|
@@ -195,7 +240,7 @@ export class MountObserver extends EventTarget {
|
|
|
195
240
|
if (!x.matches(match))
|
|
196
241
|
return true;
|
|
197
242
|
if (whereSatisfies !== undefined) {
|
|
198
|
-
if (!whereSatisfies(x, this, 'Inspecting'))
|
|
243
|
+
if (!whereSatisfies(x, this, { stage: 'Inspecting', initializing: false }))
|
|
199
244
|
return true;
|
|
200
245
|
}
|
|
201
246
|
returnSet.add(x);
|
|
@@ -206,7 +251,7 @@ export class MountObserver extends EventTarget {
|
|
|
206
251
|
this.#mountedList = Array.from(returnSet).map(x => new WeakRef(x));
|
|
207
252
|
return returnSet;
|
|
208
253
|
}
|
|
209
|
-
async #filterAndMount(els, checkMatch) {
|
|
254
|
+
async #filterAndMount(els, checkMatch, initializing) {
|
|
210
255
|
const { whereSatisfies, whereInstanceOf } = this.#mountInit;
|
|
211
256
|
const match = this.#selector;
|
|
212
257
|
const elsToMount = els.filter(x => {
|
|
@@ -215,7 +260,7 @@ export class MountObserver extends EventTarget {
|
|
|
215
260
|
return false;
|
|
216
261
|
}
|
|
217
262
|
if (whereSatisfies !== undefined) {
|
|
218
|
-
if (!whereSatisfies(x, this, 'Inspecting'))
|
|
263
|
+
if (!whereSatisfies(x, this, { stage: 'Inspecting', initializing }))
|
|
219
264
|
return false;
|
|
220
265
|
}
|
|
221
266
|
if (whereInstanceOf !== undefined) {
|
|
@@ -224,16 +269,14 @@ export class MountObserver extends EventTarget {
|
|
|
224
269
|
}
|
|
225
270
|
return true;
|
|
226
271
|
});
|
|
227
|
-
this.#mount(elsToMount);
|
|
272
|
+
this.#mount(elsToMount, initializing);
|
|
228
273
|
}
|
|
229
|
-
async #inspectWithin(within) {
|
|
274
|
+
async #inspectWithin(within, initializing) {
|
|
230
275
|
const els = Array.from(within.querySelectorAll(this.#selector));
|
|
231
|
-
this.#filterAndMount(els, false);
|
|
232
|
-
}
|
|
233
|
-
unobserve(within) {
|
|
234
|
-
//mutationObserverLookup
|
|
276
|
+
this.#filterAndMount(els, false, initializing);
|
|
235
277
|
}
|
|
236
278
|
}
|
|
279
|
+
const refCountErr = 'mount-observer ref count mismatch';
|
|
237
280
|
// https://github.com/webcomponents-cg/community-protocols/issues/12#issuecomment-872415080
|
|
238
281
|
/**
|
|
239
282
|
* The `mutation-event` event represents something that happened.
|
|
@@ -241,10 +284,12 @@ export class MountObserver extends EventTarget {
|
|
|
241
284
|
*/
|
|
242
285
|
export class MountEvent extends Event {
|
|
243
286
|
mountedElement;
|
|
287
|
+
initializing;
|
|
244
288
|
static eventName = 'mount';
|
|
245
|
-
constructor(mountedElement) {
|
|
289
|
+
constructor(mountedElement, initializing) {
|
|
246
290
|
super(MountEvent.eventName);
|
|
247
291
|
this.mountedElement = mountedElement;
|
|
292
|
+
this.initializing = initializing;
|
|
248
293
|
}
|
|
249
294
|
}
|
|
250
295
|
export class DismountEvent extends Event {
|
package/RootMutObs.js
CHANGED
package/package.json
CHANGED
package/types.d.ts
CHANGED
|
@@ -13,7 +13,11 @@ export interface MountInit{
|
|
|
13
13
|
readonly onReconfirmed?: PipelineProcessor,
|
|
14
14
|
readonly onOutsideRootNode?: PipelineProcessor,
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
// /**
|
|
17
|
+
// * Purpose -- there are scenarios where we may only want to affect changes that occur after the initial
|
|
18
|
+
// * server rendering, so we only want to mount elements that appear
|
|
19
|
+
// */
|
|
20
|
+
// readonly ignoreInitialMatches?: boolean,
|
|
17
21
|
}
|
|
18
22
|
type CSSMatch = string;
|
|
19
23
|
type ImportString = string;
|
|
@@ -27,7 +31,7 @@ export interface AttribMatch{
|
|
|
27
31
|
// validator?: (v: any) => boolean;
|
|
28
32
|
}
|
|
29
33
|
|
|
30
|
-
export interface
|
|
34
|
+
export interface IMountObserver {
|
|
31
35
|
// readonly mountInit: MountInit,
|
|
32
36
|
// readonly mountedRefs: WeakRef<Element>[],
|
|
33
37
|
// readonly dismountedRefs: WeakRef<Element>[],
|
|
@@ -36,8 +40,13 @@ export interface MountContext {
|
|
|
36
40
|
module?: any;
|
|
37
41
|
}
|
|
38
42
|
|
|
39
|
-
|
|
40
|
-
|
|
43
|
+
export interface MountContext{
|
|
44
|
+
stage?: PipelineStage,
|
|
45
|
+
initializing?: boolean,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
type PipelineStage = 'Inspecting' | 'PreImport' | 'PostImport' | 'Import'
|
|
49
|
+
export type PipelineProcessor<ReturnType = void> = (matchingElement: Element, observer: IMountObserver, ctx: MountContext) => Promise<ReturnType>;
|
|
41
50
|
|
|
42
51
|
//#region mutation event
|
|
43
52
|
export type mutationEventName = 'mutation-event';
|