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 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
- await this.#inspectWithin(within);
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, 'Import');
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, 'PostImport');
150
- this.dispatchEvent(new MountEvent(match));
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
@@ -12,6 +12,9 @@ export class RootMutObs extends EventTarget {
12
12
  });
13
13
  }
14
14
  #mutationObserver;
15
+ disconnect() {
16
+ this.#mutationObserver.disconnect();
17
+ }
15
18
  }
16
19
  // https://github.com/webcomponents-cg/community-protocols/issues/12#issuecomment-872415080
17
20
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mount-observer",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "Observe and act on css matches.",
5
5
  "main": "MountObserver.js",
6
6
  "module": "MountObserver.js",
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 MountContext {
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
- type PipelineStage = 'Inspecting' | 'PreImport' | 'PostImport' | 'Import'
40
- export type PipelineProcessor<ReturnType = void> = (matchingElement: Element, ctx: MountContext, stage?: PipelineStage) => Promise<ReturnType>;
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';