mount-observer 0.0.3 → 0.0.4

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':
package/README.md CHANGED
@@ -1,3 +1,8 @@
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
+
1
6
  # The MountObserver api.
2
7
 
3
8
  Author: Bruce B. Anderson
@@ -179,7 +184,7 @@ If an element that is in "mounted" state according to a MountObserver instance i
179
184
  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
185
  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.
181
186
 
182
- ## Special support for attributes
187
+ ## Special support for observable attributes
183
188
 
184
189
  Extra support is provided for monitoring attributes.
185
190
 
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.4",
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",
@@ -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
- }