mount-observer 0.0.3 → 0.0.5

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
@@ -136,7 +136,8 @@ export class MountObserver extends EventTarget {
136
136
  break;
137
137
  case 'object':
138
138
  if (Array.isArray(imp)) {
139
- this.module = await import(imp[0], imp[1]);
139
+ throw 'NI: Firefox';
140
+ //this.module = await import(imp[0], imp[1]);
140
141
  }
141
142
  break;
142
143
  case 'function':
@@ -229,8 +230,8 @@ export class MountObserver extends EventTarget {
229
230
  const els = Array.from(within.querySelectorAll(this.#selector));
230
231
  this.#filterAndMount(els, false);
231
232
  }
232
- unobserve() {
233
- throw 'NI';
233
+ unobserve(within) {
234
+ //mutationObserverLookup
234
235
  }
235
236
  }
236
237
  // https://github.com/webcomponents-cg/community-protocols/issues/12#issuecomment-872415080
package/README.md CHANGED
@@ -1,10 +1,16 @@
1
+ [![Playwright Tests](https://github.com/bahrus/mount-observer/actions/workflows/CI.yml/badge.svg)](https://github.com/bahrus/mount-observer/actions/workflows/CI.yml)
2
+ [![NPM version](https://badge.fury.io/js/mount-observer.png)](http://badge.fury.io/js/mount-observer)
3
+ [![How big is this package in your project?](https://img.shields.io/bundlephobia/minzip/mount-observer?style=for-the-badge)](https://bundlephobia.com/result?p=mount-observer)
4
+ <img src="http://img.badgesize.io/https://cdn.jsdelivr.net/npm/mount-observer?compression=gzip">
5
+
6
+
1
7
  # The MountObserver api.
2
8
 
3
9
  Author: Bruce B. Anderson
4
10
 
5
11
  Issues / pr's / polyfill: [mount-observer](https://github.com/bahrus/mount-observer)
6
12
 
7
- Last Update: 2023-11-18
13
+ Last Update: 2023-11-23
8
14
 
9
15
  ## Benefits of this API
10
16
 
@@ -128,13 +134,16 @@ const observer = new MountObserver({
128
134
  },
129
135
  onDismount: ...,
130
136
  onDisconnect: ...,
137
+ onOutsideRootNode: ...,
131
138
  onReconnect: ...,
132
- onReconfirm: ...
139
+ onReconfirm: ...,
133
140
  onOutOfScope: ...,
134
141
  }
135
142
  })
136
143
  ```
137
144
 
145
+ Callbacks like we see above are useful for tight coupling, and probably are unmatched in terms of performance. However, since these rules may be of interest to multiple parties, it is usesful to also provide the ability for multiple parties to subscribe to these css rules. This can be done via:
146
+
138
147
  ## Subscribing
139
148
 
140
149
  Subscribing can be done via:
@@ -173,13 +182,13 @@ The moment a MountObserver instance's "observe" method is called (passing in a r
173
182
 
174
183
  If an element that is in "mounted" state according to a MountObserver instance is moved from one parent DOM element to another:
175
184
 
176
- 1) "disconnect" event is dispatched from the MountObserver instance the moment the element is disconnected from the DOM fragment.
185
+ 1) "disconnect" event is dispatched from the MountObserver instance the moment the mounted element is disconnected from the DOM fragment.
177
186
  2) If/when the element is added somewhere else in the DOM tree, the mountObserver instance will dispatch event "reconnect", regardless of where. [Note: can't polyfill this very easily]
178
- 3) If the element is added outside the rootNode being observed, the mountObserver instance will dispatch event "outside-root-node", and the MountObserver instance will relinquish any further responsibility for this element. Ideally this would also be dispatched when the platform garbage collects the element as well after all hard references are relinquished.
179
- 4) If the new place it was added remains within the original rootNode and remains either dismounted or mounted, the MountObserver instance dispatches event "reconfirmed".
180
- 5) If the element no longer satisfies the criteria of the MountObserver instance, the MountObserver instance will dispatch event "dismount". The same is done in reverse for moved elements that started out in a "dismounted" state.
187
+ 3) If the mounted element is added outside the rootNode being observed, the mountObserver instance will dispatch event "outside-root-node", and the MountObserver instance will relinquish any further responsibility for this element. Ideally this would also be dispatched when the platform garbage collects the element as well after all hard references are relinquished.
188
+ 4) If the new place it was added remains within the original rootNode and remains mounted, the MountObserver instance dispatches event "reconfirmed".
189
+ 5) If the element no longer satisfies the criteria of the MountObserver instance, the MountObserver instance will dispatch event "dismount".
181
190
 
182
- ## Special support for attributes
191
+ ## Special support for observable attributes
183
192
 
184
193
  Extra support is provided for monitoring attributes.
185
194
 
@@ -201,6 +210,14 @@ Example:
201
210
  });
202
211
  mo.addEventListener('attr-change', e => {
203
212
  console.log(e);
213
+ // {
214
+ // attrChangeInfo:{
215
+ // name: 'test-1',
216
+ // oldValue: null,
217
+ // newValue: 'hello'
218
+ // idx: 0,
219
+ // }
220
+ // }
204
221
  });
205
222
  mo.observe(div);
206
223
  setTimeout(() => {
package/package.json CHANGED
@@ -1,13 +1,22 @@
1
1
  {
2
2
  "name": "mount-observer",
3
- "version": "0.0.3",
4
- "description": "",
3
+ "version": "0.0.5",
4
+ "description": "Observe and act on css matches.",
5
5
  "main": "MountObserver.js",
6
6
  "module": "MountObserver.js",
7
7
  "devDependencies": {
8
8
  "@playwright/test": "1.39.0",
9
9
  "may-it-serve": "0.0.6"
10
10
  },
11
+ "exports": {
12
+ ".": "./MountObserver.js",
13
+ "./MountObserver.js": "./MountObserver.js"
14
+ },
15
+ "files": [
16
+ "*.js",
17
+ "types.d.ts"
18
+ ],
19
+ "types": "types.d.ts",
11
20
  "scripts": {
12
21
  "serve": "node node_modules/may-it-serve",
13
22
  "test": "playwright test",
package/types.d.ts CHANGED
@@ -7,11 +7,11 @@ export interface MountInit{
7
7
  readonly whereSatisfies?: PipelineProcessor<boolean>,
8
8
  readonly import?: ImportString | [ImportString, ImportAssertions] | PipelineProcessor,
9
9
  readonly do?: {
10
- readonly onMount: PipelineProcessor,
11
- readonly onDismount: PipelineProcessor,
12
- readonly onDisconnect: PipelineProcessor,
13
- readonly onReconfirmed: PipelineProcessor,
14
- readonly onOutsideRootNode: PipelineProcessor,
10
+ readonly onMount?: PipelineProcessor,
11
+ readonly onDismount?: PipelineProcessor,
12
+ readonly onDisconnect?: PipelineProcessor,
13
+ readonly onReconfirmed?: PipelineProcessor,
14
+ readonly onOutsideRootNode?: PipelineProcessor,
15
15
  }
16
16
 
17
17
  }
@@ -32,7 +32,7 @@ export interface MountContext {
32
32
  // readonly mountedRefs: WeakRef<Element>[],
33
33
  // readonly dismountedRefs: WeakRef<Element>[],
34
34
  observe(within: Node): void;
35
- unobserve(): void;
35
+ unobserve(within: Node): void;
36
36
  module?: any;
37
37
  }
38
38
 
@@ -1,18 +0,0 @@
1
- name: Playwright Tests
2
- on: [push]
3
- jobs:
4
- test:
5
- timeout-minutes: 10
6
- runs-on: ubuntu-latest
7
- steps:
8
- - uses: actions/checkout@v2
9
- - uses: actions/setup-node@v2
10
- with:
11
- node-version: '16.x'
12
- - name: Install dependencies
13
- run: npm ci
14
- - name: Install Playwright
15
- run: npx playwright install --with-deps
16
- - name: Run Playwright tests
17
- run: npm run test
18
-
package/MountObserver.ts DELETED
@@ -1,282 +0,0 @@
1
- import {MountInit, MountContext, AddMutationEventListener,
2
- MutationEvent, dismountEventName, mountEventName, IMountEvent, IDismountEvent,
3
- disconnectedEventName, IDisconnectEvent, IAttrChangeEvent, attrChangeEventName, AttrChangeInfo
4
- } from './types';
5
- import {RootMutObs} from './RootMutObs.js';
6
-
7
-
8
- const mutationObserverLookup = new WeakMap<Node, RootMutObs>();
9
- export class MountObserver extends EventTarget implements MountContext{
10
-
11
- #mountInit: MountInit;
12
- #rootMutObs: RootMutObs | undefined;
13
- #abortController: AbortController;
14
- #mounted: WeakSet<Element>;
15
- #mountedList: Array<WeakRef<Element>> | undefined;
16
- #disconnected: WeakSet<Element>;
17
- //#unmounted: WeakSet<Element>;
18
- #isComplex: boolean;
19
-
20
- constructor(init: MountInit){
21
- super();
22
- const {match, whereElementIntersectsWith, whereMediaMatches} = init;
23
- let isComplex = false;
24
- if(match !== undefined){
25
- const reducedMatch = match.replaceAll(':not(', '');
26
- isComplex = reducedMatch.includes(' ') || reducedMatch.includes(':');
27
- }
28
- this.#isComplex = isComplex;
29
- if(whereElementIntersectsWith || whereMediaMatches) throw 'NI'; //not implemented
30
- this.#mountInit = init;
31
- this.#abortController = new AbortController();
32
- this.#mounted = new WeakSet();
33
- this.#disconnected = new WeakSet();
34
- //this.#unmounted = new WeakSet();
35
- }
36
-
37
- #calculatedSelector: string | undefined;
38
- get #selector(){
39
- if(this.#calculatedSelector !== undefined) return this.#calculatedSelector;
40
- const {match, attribMatches} = this.#mountInit;
41
- const base = match || '*';
42
- if(attribMatches === undefined) return base;
43
- const matches: Array<string> = [];
44
- attribMatches.forEach(x => {
45
- const {names} = x;
46
- names.forEach(y => {
47
- matches.push(`${base}[${y}]`)
48
- });
49
- });
50
- this.#calculatedSelector = matches.join(',');
51
- return this.#calculatedSelector;
52
- }
53
-
54
- async observe(within: Node){
55
- const nodeToMonitor = this.#isComplex ? (within instanceof ShadowRoot ? within : within.getRootNode()) : within;
56
- if(!mutationObserverLookup.has(nodeToMonitor)){
57
- mutationObserverLookup.set(nodeToMonitor, new RootMutObs(nodeToMonitor));
58
- }
59
- const rootMutObs = mutationObserverLookup.get(within)!;
60
- const {attribMatches} = this.#mountInit;
61
- (rootMutObs as any as AddMutationEventListener).addEventListener('mutation-event', (e: MutationEvent) => {
62
- //TODO: disconnected
63
- if(this.#isComplex){
64
- this.#inspectWithin(within);
65
- return;
66
- }
67
- const {mutationRecords} = e;
68
- const elsToInspect: Array<Element> = [];
69
- //const elsToDisconnect: Array<Element> = [];
70
- const doDisconnect = this.#mountInit.do?.onDisconnect;
71
- for(const mutationRecord of mutationRecords){
72
- const {addedNodes, type, removedNodes} = mutationRecord;
73
- //console.log(mutationRecord);
74
- const addedElements = Array.from(addedNodes).filter(x => x instanceof Element) as Array<Element>;
75
- addedElements.forEach(x => elsToInspect.push(x));
76
- if(type === 'attributes'){
77
- const {target, attributeName, oldValue} = mutationRecord;
78
- if(target instanceof Element && attributeName !== null && attribMatches !== undefined && this.#mounted.has(target)){
79
- let idx = 0;
80
- for(const attrMatch of attribMatches){
81
- const {names} = attrMatch;
82
- if(names.includes(attributeName)){
83
- const newValue = target.getAttribute(attributeName);
84
- // let parsedNewValue = undefined;
85
- // switch(type){
86
- // case 'boolean':
87
- // parsedNewValue = newValue === 'true' ? true : newValue === 'false' ? false : null;
88
- // break;
89
- // case 'date':
90
- // parsedNewValue = newValue === null ? null : new Date(newValue);
91
- // break;
92
- // case ''
93
-
94
- // }
95
- const attrChangeInfo: AttrChangeInfo = {
96
- name: attributeName,
97
- oldValue,
98
- newValue,
99
- idx
100
- };
101
- this.dispatchEvent(new AttrChangeEvent(target, attrChangeInfo));
102
- }
103
- idx++;
104
- }
105
- }
106
- elsToInspect.push(target as Element);
107
- }
108
- const deletedElements = Array.from(removedNodes).filter(x => x instanceof Element) as Array<Element>;
109
- for(const deletedElement of deletedElements){
110
- // if(!this.#mounted.has(deletedElement)) continue;
111
- // this.#mounted.delete(deletedElement);
112
- // this.#mountedList = this.#mountedList?.filter(x => x.deref() !== deletedElement);
113
- this.#disconnected.add(deletedElement);
114
- if(doDisconnect !== undefined){
115
- doDisconnect(deletedElement, this);
116
- }
117
- this.dispatchEvent(new DisconnectEvent(deletedElement));
118
- }
119
-
120
- }
121
- this.#filterAndMount(elsToInspect, true);
122
- }, {signal: this.#abortController.signal});
123
- await this.#inspectWithin(within);
124
- }
125
-
126
- #confirmInstanceOf(el: Element, whereInstanceOf: Array<typeof Node>){
127
- for(const test of whereInstanceOf){
128
- if(el instanceof test) return true;
129
- }
130
- return false;
131
- }
132
-
133
- async #mount(matching: Array<Element>){
134
- //first unmount non matching
135
- const alreadyMounted = this.#filterAndDismount();
136
- const onMount = this.#mountInit.do?.onMount;
137
- const {import: imp, attribMatches} = this.#mountInit;
138
- for(const match of matching){
139
- if(alreadyMounted.has(match)) continue;
140
- this.#mounted.add(match);
141
- if(imp !== undefined){
142
- switch(typeof imp){
143
- case 'string':
144
- this.module = await import(imp);
145
- break;
146
- case 'object':
147
- if(Array.isArray(imp)){
148
- this.module = await import(imp[0], imp[1]);
149
- }
150
- break;
151
- case 'function':
152
- this.module = await imp(match, this, 'Import');
153
- break;
154
- }
155
- }
156
- if(onMount !== undefined) onMount(match, this, 'PostImport');
157
- this.dispatchEvent(new MountEvent(match));
158
- if(attribMatches !== undefined){
159
- let idx = 0;
160
- for(const attribMatch of attribMatches){
161
- let newValue = null;
162
- const {names} = attribMatch;
163
- let nonNullName = names[0];
164
- for(const name of names){
165
- const attrVal = match.getAttribute(name);
166
- if(attrVal !== null) nonNullName = name;
167
- newValue = newValue || attrVal;
168
- }
169
- const attribInfo: AttrChangeInfo = {
170
- oldValue: null,
171
- newValue,
172
- idx,
173
- name: nonNullName
174
- };
175
- this.dispatchEvent(new AttrChangeEvent(match, attribInfo));
176
- idx++;
177
- }
178
- }
179
- this.#mountedList?.push(new WeakRef(match));
180
- //if(this.#unmounted.has(match)) this.#unmounted.delete(match);
181
- }
182
- }
183
-
184
- async #dismount(unmatching: Array<Element>){
185
- const onDismount = this.#mountInit.do?.onDismount
186
- for(const unmatch of unmatching){
187
- if(onDismount !== undefined){
188
- onDismount(unmatch, this);
189
- }
190
- this.dispatchEvent(new DismountEvent(unmatch));
191
- }
192
- }
193
-
194
- #filterAndDismount(): Set<Element>{
195
- const returnSet = new Set<Element>();
196
- if(this.#mountedList !== undefined){
197
- const previouslyMounted = this.#mountedList.map(x => x.deref());
198
- const {whereSatisfies, whereInstanceOf} = this.#mountInit;
199
- const match = this.#selector;
200
- const elsToUnMount = previouslyMounted.filter(x => {
201
- if(x === undefined) return false;
202
- if(!x.matches(match)) return true;
203
- if(whereSatisfies !== undefined){
204
- if(!whereSatisfies(x, this, 'Inspecting')) return true;
205
- }
206
- returnSet.add(x);
207
- return false;
208
- }) as Array<Element>;
209
- this.#dismount(elsToUnMount);
210
- }
211
- this.#mountedList = Array.from(returnSet).map(x => new WeakRef(x));
212
- return returnSet;
213
- }
214
-
215
- async #filterAndMount(els: Array<Element>, checkMatch: boolean){
216
- const {whereSatisfies, whereInstanceOf} = this.#mountInit;
217
- const match = this.#selector;
218
- const elsToMount = els.filter(x => {
219
- if(checkMatch){
220
- if(!x.matches(match)) return false;
221
- }
222
- if(whereSatisfies !== undefined){
223
- if(!whereSatisfies(x, this, 'Inspecting')) return false;
224
- }
225
- if(whereInstanceOf !== undefined){
226
- if(!this.#confirmInstanceOf(x, whereInstanceOf)) return false;
227
- }
228
- return true;
229
- });
230
- this.#mount(elsToMount);
231
- }
232
-
233
- async #inspectWithin(within: Node){
234
- const els = Array.from((within as Element).querySelectorAll(this.#selector));
235
- this.#filterAndMount(els, false);
236
- }
237
-
238
- unobserve(){
239
- throw 'NI';
240
- }
241
-
242
- }
243
-
244
- export interface MountObserver extends MountContext{}
245
-
246
- // https://github.com/webcomponents-cg/community-protocols/issues/12#issuecomment-872415080
247
- /**
248
- * The `mutation-event` event represents something that happened.
249
- * We can document it here.
250
- */
251
- export class MountEvent extends Event implements IMountEvent {
252
- static eventName: mountEventName = 'mount';
253
-
254
- constructor(public mountedElement: Element) {
255
- super(MountEvent.eventName);
256
-
257
- }
258
- }
259
-
260
- export class DismountEvent extends Event implements IDismountEvent{
261
- static eventName: dismountEventName = 'dismount';
262
-
263
- constructor(public dismountedElement: Element){
264
- super(DismountEvent.eventName)
265
- }
266
- }
267
-
268
- export class DisconnectEvent extends Event implements IDisconnectEvent{
269
- static eventName: disconnectedEventName = 'disconnect';
270
-
271
- constructor(public disconnectedElement: Element){
272
- super(DisconnectEvent.eventName);
273
- }
274
- }
275
-
276
- export class AttrChangeEvent extends Event implements IAttrChangeEvent{
277
- static eventName: attrChangeEventName = 'attr-change';
278
- constructor(public mountedElement: Element, public attrChangeInfo: AttrChangeInfo){
279
- super(AttrChangeEvent.eventName);
280
- }
281
- }
282
-
package/RootMutObs.ts DELETED
@@ -1,37 +0,0 @@
1
- import {mutationEventName, AddMutationEventListener} from './types';
2
-
3
- export class RootMutObs extends EventTarget{
4
- constructor(rootNode: Node ){
5
- super();
6
- this.#mutationObserver = new MutationObserver(mutationRecords => {
7
- this.dispatchEvent(new MutationEvent(mutationRecords))
8
- })
9
- this.#mutationObserver.observe(rootNode, {
10
- subtree: true,
11
- childList: true,
12
- attributes: true,
13
- attributeOldValue: true,
14
- });
15
- }
16
- #mutationObserver: MutationObserver;
17
- }
18
-
19
-
20
-
21
- // https://github.com/webcomponents-cg/community-protocols/issues/12#issuecomment-872415080
22
-
23
- /**
24
- * The `mutation-event` event represents something that happened.
25
- * We can document it here.
26
- */
27
- export class MutationEvent extends Event implements MutationEvent {
28
- static eventName: mutationEventName = 'mutation-event';
29
-
30
- constructor(public mutationRecords: Array<MutationRecord>) {
31
- // Since these are hard-coded, dispatchers can't get them wrong
32
- super(MutationEvent.eventName);
33
- }
34
- }
35
-
36
-
37
-
package/demo/test1.html DELETED
@@ -1,28 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Document</title>
7
- </head>
8
- <body>
9
- <div id=div>
10
- <span id=span></span>
11
- </div>
12
- <script type=module>
13
- import {MountObserver} from '../MountObserver.js';
14
- const mo = new MountObserver({
15
- match: '#span',
16
- do:{
17
- onMount: (el, ctx) => {
18
- console.log({el, ctx});
19
- }
20
- }
21
- });
22
- mo.addEventListener('mount', e => {
23
- console.log(e);
24
- });
25
- mo.observe(div);
26
- </script>
27
- </body>
28
- </html>
@@ -1,29 +0,0 @@
1
- // playwright.config.ts
2
- import { PlaywrightTestConfig, devices } from '@playwright/test';
3
- const config: PlaywrightTestConfig = {
4
- webServer: {
5
- command: 'npm run serve',
6
- url: 'http://localhost:3030/',
7
- timeout: 120 * 1000,
8
- reuseExistingServer: !process.env.CI,
9
- },
10
- use: {
11
- baseURL: 'http://localhost:3030/',
12
- },
13
- projects: [
14
- {
15
- name: 'chromium',
16
- use: { ...devices['Desktop Chrome'] },
17
- },
18
- //firefox lacks support for import assertions
19
- // {
20
- // name: 'firefox',
21
- // use: { ...devices['Desktop Firefox'] },
22
- // },
23
- {
24
- name: 'webkit',
25
- use: { ...devices['Desktop Safari'] },
26
- },
27
- ],
28
- };
29
- export default config;
package/tests/test1.html DELETED
@@ -1,30 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Document</title>
7
- </head>
8
- <body>
9
- <div id=div>
10
- <span id=span></span>
11
- </div>
12
- <div id=target></div>
13
- <script type=module>
14
- import {MountObserver} from '../MountObserver.js';
15
- const mo = new MountObserver({
16
- match: '#span',
17
- do:{
18
- onMount: (el, ctx) => {
19
- console.log({el, ctx});
20
- target.setAttribute('mark', 'good');
21
- }
22
- }
23
- });
24
- mo.addEventListener('mount', e => {
25
- console.log(e);
26
- });
27
- mo.observe(div);
28
- </script>
29
- </body>
30
- </html>
@@ -1,8 +0,0 @@
1
- import { test, expect } from '@playwright/test';
2
- test('test1', async ({ page }) => {
3
- await page.goto('./tests/test1.html');
4
- // wait for 1 second
5
- await page.waitForTimeout(1000);
6
- const editor = page.locator('#target');
7
- await expect(editor).toHaveAttribute('mark', 'good');
8
- });
package/tests/test2.html DELETED
@@ -1,34 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Document</title>
7
- </head>
8
- <body>
9
- <div id=div>
10
- </div>
11
- <div id=target></div>
12
- <script type=module>
13
- import {MountObserver} from '../MountObserver.js';
14
- const mo = new MountObserver({
15
- match: '#span',
16
- do:{
17
- onMount: (el, ctx) => {
18
- console.log({el, ctx});
19
- target.setAttribute('mark', 'good');
20
- }
21
- }
22
- });
23
- mo.addEventListener('mount', e => {
24
- console.log(e);
25
- });
26
- mo.observe(div);
27
- setTimeout(() => {
28
- const span = document.createElement('span');
29
- span.id = 'span';
30
- div.appendChild(span);
31
- }, 500);
32
- </script>
33
- </body>
34
- </html>
@@ -1,8 +0,0 @@
1
- import { test, expect } from '@playwright/test';
2
- test('test1', async ({ page }) => {
3
- await page.goto('./tests/test2.html');
4
- // wait for 1 second
5
- await page.waitForTimeout(1000);
6
- const editor = page.locator('#target');
7
- await expect(editor).toHaveAttribute('mark', 'good');
8
- });
package/tests/test3.html DELETED
@@ -1,34 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Document</title>
7
- </head>
8
- <body>
9
- <div id=div>
10
- <span></span>
11
- </div>
12
- <div id=target></div>
13
- <script type=module>
14
- import {MountObserver} from '../MountObserver.js';
15
- const mo = new MountObserver({
16
- match: '#span',
17
- do:{
18
- onMount: (el, ctx) => {
19
- console.log({el, ctx});
20
- target.setAttribute('mark', 'good');
21
- }
22
- }
23
- });
24
- mo.addEventListener('mount', e => {
25
- console.log(e);
26
- });
27
- mo.observe(div);
28
- setTimeout(() => {
29
- const span = div.querySelector('span');
30
- span.id = 'span';
31
- }, 500);
32
- </script>
33
- </body>
34
- </html>
@@ -1,8 +0,0 @@
1
- import { test, expect } from '@playwright/test';
2
- test('test1', async ({ page }) => {
3
- await page.goto('./tests/test3.html');
4
- // wait for 1 second
5
- await page.waitForTimeout(1000);
6
- const editor = page.locator('#target');
7
- await expect(editor).toHaveAttribute('mark', 'good');
8
- });
package/tests/test4.html DELETED
@@ -1,31 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Document</title>
7
- </head>
8
- <body>
9
- <div id=div>
10
- <span id=span></span>
11
- </div>
12
- <div id=target></div>
13
- <script type=module>
14
- import {MountObserver} from '../MountObserver.js';
15
- const mo = new MountObserver({
16
- match: '#span',
17
- do:{
18
- onMount: (el, ctx) => {
19
- console.log({el, ctx});
20
-
21
- }
22
- }
23
- });
24
- mo.addEventListener('mount', e => {
25
- console.log(e);
26
- target.setAttribute('mark', 'good');
27
- });
28
- mo.observe(div);
29
- </script>
30
- </body>
31
- </html>
@@ -1,8 +0,0 @@
1
- import { test, expect } from '@playwright/test';
2
- test('test1', async ({ page }) => {
3
- await page.goto('./tests/test4.html');
4
- // wait for 1 second
5
- await page.waitForTimeout(1000);
6
- const editor = page.locator('#target');
7
- await expect(editor).toHaveAttribute('mark', 'good');
8
- });
package/tests/test5.html DELETED
@@ -1,34 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Document</title>
7
- </head>
8
- <body>
9
- <div id=div>
10
- <span id=span></span>
11
- </div>
12
- <div id=target></div>
13
- <script type=module>
14
- import {MountObserver} from '../MountObserver.js';
15
- const mo = new MountObserver({
16
- match: '#span',
17
- do:{
18
- onDisconnect: (el, ctx) => {
19
- console.log({el, ctx});
20
-
21
- }
22
- }
23
- });
24
- mo.addEventListener('disconnect', e => {
25
- console.log(e);
26
- target.setAttribute('mark', 'good');
27
- });
28
- mo.observe(div);
29
- setTimeout(() => {
30
- span.remove();
31
- }, 1000);
32
- </script>
33
- </body>
34
- </html>
@@ -1,8 +0,0 @@
1
- import { test, expect } from '@playwright/test';
2
- test('test1', async ({ page }) => {
3
- await page.goto('./tests/test5.html');
4
- // wait for 1 second
5
- await page.waitForTimeout(1000);
6
- const editor = page.locator('#target');
7
- await expect(editor).toHaveAttribute('mark', 'good');
8
- });
package/tests/test6.html DELETED
@@ -1,33 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Document</title>
7
- </head>
8
- <body>
9
- <div id=div>
10
- <span id=span></span>
11
- </div>
12
- <div id=target></div>
13
- <script type=module>
14
- import {MountObserver} from '../MountObserver.js';
15
- const mo = new MountObserver({
16
- match: '#span',
17
- attribMatches:[
18
- {
19
- names: ['test-1']
20
- }
21
- ]
22
- });
23
- mo.addEventListener('attr-change', e => {
24
- console.log(e);
25
- target.setAttribute('mark', 'good');
26
- });
27
- mo.observe(div);
28
- setTimeout(() => {
29
- span.setAttribute('test-1', 'hello')
30
- }, 1000);
31
- </script>
32
- </body>
33
- </html>
@@ -1,8 +0,0 @@
1
- import { test, expect } from '@playwright/test';
2
- test('test1', async ({ page }) => {
3
- await page.goto('./tests/test6.html');
4
- // wait for 1 second
5
- await page.waitForTimeout(1000);
6
- const editor = page.locator('#target');
7
- await expect(editor).toHaveAttribute('mark', 'good');
8
- });
package/tsconfig.json DELETED
@@ -1,17 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ESNext",
4
- "module": "ESNext",
5
- "sourceMap": false,
6
- "experimentalDecorators": false,
7
- "newLine": "LF",
8
- "strict": true,
9
- },
10
- "files": [
11
- "MountObserver.ts",
12
- ],
13
- "exclude":[
14
- "node_modules"
15
- ]
16
-
17
- }