mount-observer 0.1.1 → 0.1.3
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/DefineCustomElementHandler.js +64 -0
- package/DefineCustomElementHandler.ts +77 -0
- package/Events.js +11 -9
- package/Events.ts +9 -4
- package/EvtRt.js +34 -0
- package/EvtRt.ts +42 -0
- package/MountObserver.js +275 -106
- package/MountObserver.ts +328 -118
- package/README.md +857 -203
- package/SharedMutationObserver.js +9 -6
- package/SharedMutationObserver.ts +11 -8
- package/arr.js +13 -0
- package/arr.ts +13 -0
- package/attrChanges.js +70 -0
- package/attrChanges.ts +90 -0
- package/emitEvents.js +103 -0
- package/emitEvents.ts +126 -0
- package/index.js +13 -1
- package/index.ts +14 -1
- package/loadImports.js +2 -1
- package/loadImports.ts +2 -1
- package/mediaQuery.js +15 -17
- package/mediaQuery.ts +18 -20
- package/package.json +27 -3
- package/types.d.ts +38 -15
- package/whereOutside.js +19 -0
- package/whereOutside.ts +25 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { EvtRt } from './EvtRt.js';
|
|
2
|
+
export class DefineCustomElementHandler extends EvtRt {
|
|
3
|
+
mount(mountedElement, mountInit, context) {
|
|
4
|
+
// Check if modules are specified
|
|
5
|
+
if (!context.modules || context.modules.length === 0) {
|
|
6
|
+
throw new Error('Must specify an ES Module');
|
|
7
|
+
}
|
|
8
|
+
const module = context.modules[0];
|
|
9
|
+
const tagName = mountedElement.localName;
|
|
10
|
+
// Check if already defined
|
|
11
|
+
if (customElements.get(tagName)) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
// Find suitable class
|
|
15
|
+
const ElementClass = this.findSuitableClass(module);
|
|
16
|
+
// Validate that ElementClass is a constructor
|
|
17
|
+
if (typeof ElementClass !== 'function') {
|
|
18
|
+
throw new Error(`Found class is not a constructor: ${typeof ElementClass}`);
|
|
19
|
+
}
|
|
20
|
+
// Create wrapper class to allow reuse
|
|
21
|
+
// Use anonymous class expression which works across all browsers
|
|
22
|
+
const WrapperClass = class extends ElementClass {
|
|
23
|
+
};
|
|
24
|
+
// Define the custom element
|
|
25
|
+
customElements.define(tagName, WrapperClass);
|
|
26
|
+
}
|
|
27
|
+
findSuitableClass(module) {
|
|
28
|
+
// Check default export first
|
|
29
|
+
const defaultExport = module.default;
|
|
30
|
+
if (defaultExport && this.extendsHTMLElement(defaultExport)) {
|
|
31
|
+
return defaultExport;
|
|
32
|
+
}
|
|
33
|
+
// Find all exports that extend HTMLElement
|
|
34
|
+
const htmlElementClasses = Object.values(module)
|
|
35
|
+
.filter(exp => typeof exp === 'function' && this.extendsHTMLElement(exp));
|
|
36
|
+
if (htmlElementClasses.length === 0) {
|
|
37
|
+
throw new Error('No suitable class found in module');
|
|
38
|
+
}
|
|
39
|
+
if (htmlElementClasses.length > 1) {
|
|
40
|
+
throw new Error('More than one class found in module');
|
|
41
|
+
}
|
|
42
|
+
return htmlElementClasses[0];
|
|
43
|
+
}
|
|
44
|
+
extendsHTMLElement(cls) {
|
|
45
|
+
try {
|
|
46
|
+
// Must be a function
|
|
47
|
+
if (typeof cls !== 'function') {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
// Handle direct HTMLElement export
|
|
51
|
+
if (cls === HTMLElement) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
// Check if it has a prototype and extends HTMLElement
|
|
55
|
+
if (cls.prototype && cls.prototype instanceof HTMLElement) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { EvtRt } from './EvtRt.js';
|
|
2
|
+
import { MountInit, MountContext } from './types.js';
|
|
3
|
+
|
|
4
|
+
export class DefineCustomElementHandler extends EvtRt {
|
|
5
|
+
mount(mountedElement: Element, mountInit: MountInit, context: MountContext): void {
|
|
6
|
+
// Check if modules are specified
|
|
7
|
+
if (!context.modules || context.modules.length === 0) {
|
|
8
|
+
throw new Error('Must specify an ES Module');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const module = context.modules[0];
|
|
12
|
+
const tagName = mountedElement.localName;
|
|
13
|
+
|
|
14
|
+
// Check if already defined
|
|
15
|
+
if (customElements.get(tagName)) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Find suitable class
|
|
20
|
+
const ElementClass = this.findSuitableClass(module);
|
|
21
|
+
|
|
22
|
+
// Validate that ElementClass is a constructor
|
|
23
|
+
if (typeof ElementClass !== 'function') {
|
|
24
|
+
throw new Error(`Found class is not a constructor: ${typeof ElementClass}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Create wrapper class to allow reuse
|
|
28
|
+
// Use anonymous class expression which works across all browsers
|
|
29
|
+
const WrapperClass = class extends ElementClass {};
|
|
30
|
+
|
|
31
|
+
// Define the custom element
|
|
32
|
+
customElements.define(tagName, WrapperClass);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private findSuitableClass(module: any): typeof HTMLElement {
|
|
36
|
+
// Check default export first
|
|
37
|
+
const defaultExport = module.default;
|
|
38
|
+
|
|
39
|
+
if (defaultExport && this.extendsHTMLElement(defaultExport)) {
|
|
40
|
+
return defaultExport;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Find all exports that extend HTMLElement
|
|
44
|
+
const htmlElementClasses = Object.values(module)
|
|
45
|
+
.filter(exp => typeof exp === 'function' && this.extendsHTMLElement(exp));
|
|
46
|
+
|
|
47
|
+
if (htmlElementClasses.length === 0) {
|
|
48
|
+
throw new Error('No suitable class found in module');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (htmlElementClasses.length > 1) {
|
|
52
|
+
throw new Error('More than one class found in module');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return htmlElementClasses[0] as typeof HTMLElement;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private extendsHTMLElement(cls: any): boolean {
|
|
59
|
+
try {
|
|
60
|
+
// Must be a function
|
|
61
|
+
if (typeof cls !== 'function') {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
// Handle direct HTMLElement export
|
|
65
|
+
if (cls === HTMLElement) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
// Check if it has a prototype and extends HTMLElement
|
|
69
|
+
if (cls.prototype && cls.prototype instanceof HTMLElement) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
return false;
|
|
73
|
+
} catch {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
package/Events.js
CHANGED
|
@@ -7,36 +7,38 @@ export const attrchangeEventName = 'attrchange';
|
|
|
7
7
|
export const mediamatchEventName = 'mediamatch';
|
|
8
8
|
export const mediaunmatchEventName = 'mediaunmatch';
|
|
9
9
|
export class MountEvent extends Event {
|
|
10
|
-
|
|
10
|
+
mountedElement;
|
|
11
11
|
modules;
|
|
12
12
|
mountInit;
|
|
13
|
+
mountContext;
|
|
13
14
|
static eventName = mountEventName;
|
|
14
|
-
constructor(
|
|
15
|
+
constructor(mountedElement, modules, mountInit, mountContext) {
|
|
15
16
|
super(MountEvent.eventName);
|
|
16
|
-
this.
|
|
17
|
+
this.mountedElement = mountedElement;
|
|
17
18
|
this.modules = modules;
|
|
18
19
|
this.mountInit = mountInit;
|
|
20
|
+
this.mountContext = mountContext;
|
|
19
21
|
}
|
|
20
22
|
}
|
|
21
23
|
export class DismountEvent extends Event {
|
|
22
|
-
|
|
24
|
+
mountedElement;
|
|
23
25
|
reason;
|
|
24
26
|
mountInit;
|
|
25
27
|
static eventName = dismountEventName;
|
|
26
|
-
constructor(
|
|
28
|
+
constructor(mountedElement, reason, mountInit) {
|
|
27
29
|
super(DismountEvent.eventName);
|
|
28
|
-
this.
|
|
30
|
+
this.mountedElement = mountedElement;
|
|
29
31
|
this.reason = reason;
|
|
30
32
|
this.mountInit = mountInit;
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
35
|
export class DisconnectEvent extends Event {
|
|
34
|
-
|
|
36
|
+
mountedElement;
|
|
35
37
|
mountInit;
|
|
36
38
|
static eventName = disconnectEventName;
|
|
37
|
-
constructor(
|
|
39
|
+
constructor(mountedElement, mountInit) {
|
|
38
40
|
super(DisconnectEvent.eventName);
|
|
39
|
-
this.
|
|
41
|
+
this.mountedElement = mountedElement;
|
|
40
42
|
this.mountInit = mountInit;
|
|
41
43
|
}
|
|
42
44
|
}
|
package/Events.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Event classes for MountObserver
|
|
2
|
-
import type { IMountEvent, IDismountEvent, IAttrChangeEvent, AttrChange, MountInit, DismountReason } from './types.js';
|
|
2
|
+
import type { IMountEvent, IDismountEvent, IAttrChangeEvent, AttrChange, MountInit, DismountReason, MountContext } from './types.js';
|
|
3
3
|
|
|
4
4
|
// Event name constants
|
|
5
5
|
export const loadEventName = 'load';
|
|
@@ -13,7 +13,12 @@ export const mediaunmatchEventName = 'mediaunmatch';
|
|
|
13
13
|
export class MountEvent extends Event implements IMountEvent {
|
|
14
14
|
static eventName: typeof mountEventName = mountEventName;
|
|
15
15
|
|
|
16
|
-
constructor(
|
|
16
|
+
constructor(
|
|
17
|
+
public mountedElement: Element,
|
|
18
|
+
public modules: any[],
|
|
19
|
+
public mountInit: MountInit,
|
|
20
|
+
public mountContext: MountContext
|
|
21
|
+
) {
|
|
17
22
|
super(MountEvent.eventName);
|
|
18
23
|
}
|
|
19
24
|
}
|
|
@@ -21,7 +26,7 @@ export class MountEvent extends Event implements IMountEvent {
|
|
|
21
26
|
export class DismountEvent extends Event implements IDismountEvent {
|
|
22
27
|
static eventName: typeof dismountEventName = dismountEventName;
|
|
23
28
|
|
|
24
|
-
constructor(public
|
|
29
|
+
constructor(public mountedElement: Element, public reason: DismountReason, public mountInit: MountInit) {
|
|
25
30
|
super(DismountEvent.eventName);
|
|
26
31
|
}
|
|
27
32
|
}
|
|
@@ -29,7 +34,7 @@ export class DismountEvent extends Event implements IDismountEvent {
|
|
|
29
34
|
export class DisconnectEvent extends Event {
|
|
30
35
|
static eventName: typeof disconnectEventName = disconnectEventName;
|
|
31
36
|
|
|
32
|
-
constructor(public
|
|
37
|
+
constructor(public mountedElement: Element, public mountInit: MountInit) {
|
|
33
38
|
super(DisconnectEvent.eventName);
|
|
34
39
|
}
|
|
35
40
|
}
|
package/EvtRt.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { DismountEvent, MountEvent, DisconnectEvent, dismountEventName, disconnectEventName, mountEventName } from './Events.js';
|
|
2
|
+
export class EvtRt {
|
|
3
|
+
constructor(mountedElement, ctx) {
|
|
4
|
+
const { observer, mountInit } = ctx;
|
|
5
|
+
const et = observer.getNotifier(mountedElement);
|
|
6
|
+
et.addEventListener(mountEventName, this);
|
|
7
|
+
et.addEventListener(disconnectEventName, this);
|
|
8
|
+
et.addEventListener(dismountEventName, this);
|
|
9
|
+
this.mount(mountedElement, mountInit, ctx);
|
|
10
|
+
}
|
|
11
|
+
mount(mountedElement, mountInit, context) {
|
|
12
|
+
console.log({ mountedElement, mountInit, context });
|
|
13
|
+
}
|
|
14
|
+
disconnect(mountedElement, mountInit) {
|
|
15
|
+
console.log({ mountedElement, mountInit });
|
|
16
|
+
}
|
|
17
|
+
dismount(mountedElement, mountInit) {
|
|
18
|
+
console.log({ mountedElement, mountInit });
|
|
19
|
+
}
|
|
20
|
+
handleEvent(evt) {
|
|
21
|
+
if (evt instanceof MountEvent) {
|
|
22
|
+
const { mountedElement, mountContext, mountInit } = evt;
|
|
23
|
+
this.mount(mountedElement, mountInit, mountContext);
|
|
24
|
+
}
|
|
25
|
+
else if (evt instanceof DismountEvent) {
|
|
26
|
+
const { mountedElement, mountInit } = evt;
|
|
27
|
+
this.dismount(mountedElement, mountInit);
|
|
28
|
+
}
|
|
29
|
+
else if (evt instanceof DisconnectEvent) {
|
|
30
|
+
const { mountedElement, mountInit } = evt;
|
|
31
|
+
this.disconnect(mountedElement, mountInit);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
package/EvtRt.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import {MountContext, MountInit} from './types.js';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
DismountEvent, MountEvent, DisconnectEvent,
|
|
5
|
+
dismountEventName, disconnectEventName, mountEventName
|
|
6
|
+
} from './Events.js';
|
|
7
|
+
export class EvtRt implements EventListenerObject{
|
|
8
|
+
constructor(mountedElement: Element, ctx: MountContext ){
|
|
9
|
+
const {observer, mountInit} = ctx;
|
|
10
|
+
const et = observer.getNotifier(mountedElement);
|
|
11
|
+
et.addEventListener(mountEventName, this);
|
|
12
|
+
et.addEventListener(disconnectEventName, this);
|
|
13
|
+
et.addEventListener(dismountEventName, this);
|
|
14
|
+
this.mount(mountedElement, mountInit, ctx);
|
|
15
|
+
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
mount(mountedElement: Element, mountInit: MountInit, context: MountContext){
|
|
19
|
+
console.log({mountedElement, mountInit, context});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
disconnect(mountedElement: Element, mountInit: MountInit){
|
|
23
|
+
console.log({mountedElement, mountInit});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
dismount(mountedElement: Element, mountInit: MountInit){
|
|
27
|
+
console.log({mountedElement, mountInit});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
handleEvent(evt: Event): void {
|
|
31
|
+
if(evt instanceof MountEvent){
|
|
32
|
+
const {mountedElement, mountContext, mountInit} = evt;
|
|
33
|
+
this.mount(mountedElement, mountInit, mountContext);
|
|
34
|
+
}else if(evt instanceof DismountEvent){
|
|
35
|
+
const {mountedElement, mountInit} = evt;
|
|
36
|
+
this.dismount(mountedElement, mountInit);
|
|
37
|
+
}else if(evt instanceof DisconnectEvent){
|
|
38
|
+
const {mountedElement, mountInit} = evt;
|
|
39
|
+
this.disconnect(mountedElement, mountInit);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|