@dooboostore/simple-web-component 1.0.48 → 1.0.49
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/README.md +117 -19
- package/dist/cjs/config/config.js +1 -1
- package/dist/cjs/config/config.js.map +2 -2
- package/dist/cjs/decorators/addEventListener.js +387 -29
- package/dist/cjs/decorators/addEventListener.js.map +3 -3
- package/dist/cjs/decorators/applyAttribute.js +25 -0
- package/dist/cjs/decorators/applyAttribute.js.map +2 -2
- package/dist/cjs/decorators/applyClass.js +49 -18
- package/dist/cjs/decorators/applyClass.js.map +3 -3
- package/dist/cjs/decorators/applyNode.js +67 -1
- package/dist/cjs/decorators/applyNode.js.map +3 -3
- package/dist/cjs/decorators/applyProperty.js +101 -3
- package/dist/cjs/decorators/applyProperty.js.map +2 -2
- package/dist/cjs/decorators/applyStyle.js +36 -5
- package/dist/cjs/decorators/applyStyle.js.map +2 -2
- package/dist/cjs/decorators/changedAttribute.js +39 -0
- package/dist/cjs/decorators/changedAttribute.js.map +2 -2
- package/dist/cjs/decorators/elementDefine.js +237 -437
- package/dist/cjs/decorators/elementDefine.js.map +3 -3
- package/dist/cjs/decorators/emitCustomEvent.js +55 -0
- package/dist/cjs/decorators/emitCustomEvent.js.map +2 -2
- package/dist/cjs/decorators/index.js +3 -1
- package/dist/cjs/decorators/index.js.map +2 -2
- package/dist/cjs/decorators/intersectionObserver.js +209 -0
- package/dist/cjs/decorators/intersectionObserver.js.map +7 -0
- package/dist/cjs/decorators/mutationObserver.js +140 -0
- package/dist/cjs/decorators/mutationObserver.js.map +3 -3
- package/dist/cjs/decorators/query.js +117 -102
- package/dist/cjs/decorators/query.js.map +2 -2
- package/dist/cjs/decorators/resizeObserver.js +87 -0
- package/dist/cjs/decorators/resizeObserver.js.map +2 -2
- package/dist/cjs/decorators/setInterval.js +82 -0
- package/dist/cjs/decorators/setInterval.js.map +7 -0
- package/dist/cjs/decorators/setTimeout.js +82 -0
- package/dist/cjs/decorators/setTimeout.js.map +7 -0
- package/dist/cjs/decorators/subscribeSwcAppMessageWhileConnected.js +9 -0
- package/dist/cjs/decorators/subscribeSwcAppMessageWhileConnected.js.map +2 -2
- package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js +9 -0
- package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +2 -2
- package/dist/cjs/types/index.js.map +1 -1
- package/dist/esm/config/config.js +1 -1
- package/dist/esm/config/config.js.map +2 -2
- package/dist/esm/decorators/addEventListener.js +388 -29
- package/dist/esm/decorators/addEventListener.js.map +3 -3
- package/dist/esm/decorators/applyAttribute.js +25 -0
- package/dist/esm/decorators/applyAttribute.js.map +2 -2
- package/dist/esm/decorators/applyClass.js +49 -18
- package/dist/esm/decorators/applyClass.js.map +3 -3
- package/dist/esm/decorators/applyNode.js +67 -1
- package/dist/esm/decorators/applyNode.js.map +3 -3
- package/dist/esm/decorators/applyProperty.js +101 -3
- package/dist/esm/decorators/applyProperty.js.map +2 -2
- package/dist/esm/decorators/applyStyle.js +36 -5
- package/dist/esm/decorators/applyStyle.js.map +2 -2
- package/dist/esm/decorators/changedAttribute.js +40 -0
- package/dist/esm/decorators/changedAttribute.js.map +2 -2
- package/dist/esm/decorators/elementDefine.js +244 -444
- package/dist/esm/decorators/elementDefine.js.map +3 -3
- package/dist/esm/decorators/emitCustomEvent.js +55 -0
- package/dist/esm/decorators/emitCustomEvent.js.map +2 -2
- package/dist/esm/decorators/index.js +3 -1
- package/dist/esm/decorators/index.js.map +2 -2
- package/dist/esm/decorators/intersectionObserver.js +191 -0
- package/dist/esm/decorators/intersectionObserver.js.map +7 -0
- package/dist/esm/decorators/mutationObserver.js +141 -0
- package/dist/esm/decorators/mutationObserver.js.map +3 -3
- package/dist/esm/decorators/query.js +117 -102
- package/dist/esm/decorators/query.js.map +2 -2
- package/dist/esm/decorators/resizeObserver.js +88 -0
- package/dist/esm/decorators/resizeObserver.js.map +2 -2
- package/dist/esm/decorators/setInterval.js +64 -0
- package/dist/esm/decorators/setInterval.js.map +7 -0
- package/dist/esm/decorators/setTimeout.js +64 -0
- package/dist/esm/decorators/setTimeout.js.map +7 -0
- package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js +9 -0
- package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js.map +2 -2
- package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js +9 -0
- package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +2 -2
- package/dist/esm/types/index.js.map +1 -1
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +2565 -1474
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
- package/dist/types/config/config.d.ts.map +1 -1
- package/dist/types/decorators/addEventListener.d.ts +84 -33
- package/dist/types/decorators/addEventListener.d.ts.map +1 -1
- package/dist/types/decorators/applyAttribute.d.ts +22 -34
- package/dist/types/decorators/applyAttribute.d.ts.map +1 -1
- package/dist/types/decorators/applyClass.d.ts +34 -34
- package/dist/types/decorators/applyClass.d.ts.map +1 -1
- package/dist/types/decorators/applyNode.d.ts +30 -20
- package/dist/types/decorators/applyNode.d.ts.map +1 -1
- package/dist/types/decorators/applyProperty.d.ts +57 -34
- package/dist/types/decorators/applyProperty.d.ts.map +1 -1
- package/dist/types/decorators/applyStyle.d.ts +25 -12
- package/dist/types/decorators/applyStyle.d.ts.map +1 -1
- package/dist/types/decorators/changedAttribute.d.ts +11 -0
- package/dist/types/decorators/changedAttribute.d.ts.map +1 -1
- package/dist/types/decorators/elementDefine.d.ts +0 -14
- package/dist/types/decorators/elementDefine.d.ts.map +1 -1
- package/dist/types/decorators/emitCustomEvent.d.ts +28 -4
- package/dist/types/decorators/emitCustomEvent.d.ts.map +1 -1
- package/dist/types/decorators/index.d.ts +3 -1
- package/dist/types/decorators/index.d.ts.map +1 -1
- package/dist/types/decorators/intersectionObserver.d.ts +49 -0
- package/dist/types/decorators/intersectionObserver.d.ts.map +1 -0
- package/dist/types/decorators/mutationObserver.d.ts +35 -25
- package/dist/types/decorators/mutationObserver.d.ts.map +1 -1
- package/dist/types/decorators/query.d.ts +57 -14
- package/dist/types/decorators/query.d.ts.map +1 -1
- package/dist/types/decorators/resizeObserver.d.ts +34 -23
- package/dist/types/decorators/resizeObserver.d.ts.map +1 -1
- package/dist/types/decorators/setInterval.d.ts +29 -0
- package/dist/types/decorators/setInterval.d.ts.map +1 -0
- package/dist/types/decorators/setTimeout.d.ts +29 -0
- package/dist/types/decorators/setTimeout.d.ts.map +1 -0
- package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts +7 -1
- package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts.map +1 -1
- package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts +6 -0
- package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts.map +1 -1
- package/dist/types/types/index.d.ts +104 -0
- package/dist/types/types/index.d.ts.map +1 -1
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +2565 -1474
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
- package/package.json +7 -5
- package/src/config/config.ts +1 -1
- package/src/decorators/addEventListener.ts +394 -34
- package/src/decorators/applyAttribute.ts +50 -36
- package/src/decorators/applyClass.ts +76 -26
- package/src/decorators/applyNode.ts +114 -36
- package/src/decorators/applyProperty.ts +152 -40
- package/src/decorators/applyStyle.ts +64 -17
- package/src/decorators/changedAttribute.ts +46 -0
- package/src/decorators/elementDefine.ts +281 -580
- package/src/decorators/emitCustomEvent.ts +73 -5
- package/src/decorators/index.ts +3 -1
- package/src/decorators/intersectionObserver.ts +259 -0
- package/src/decorators/mutationObserver.ts +215 -39
- package/src/decorators/query.ts +168 -126
- package/src/decorators/resizeObserver.ts +152 -46
- package/src/decorators/setInterval.ts +80 -0
- package/src/decorators/setTimeout.ts +80 -0
- package/src/decorators/subscribeSwcAppMessageWhileConnected.ts +17 -0
- package/src/decorators/subscribeSwcAppRouteChangeWhileConnected.ts +19 -0
- package/src/types/index.ts +141 -0
- package/dist/cjs/decorators/queryAll.js +0 -181
- package/dist/cjs/decorators/queryAll.js.map +0 -7
- package/dist/esm/decorators/queryAll.js +0 -162
- package/dist/esm/decorators/queryAll.js.map +0 -7
- package/dist/types/decorators/queryAll.d.ts +0 -22
- package/dist/types/decorators/queryAll.d.ts.map +0 -1
- package/src/decorators/queryAll.ts +0 -186
|
@@ -1,35 +1,40 @@
|
|
|
1
1
|
import { ReflectUtils } from '@dooboostore/core';
|
|
2
|
-
import { SpecialSelector, SwcQueryOptions, HelperHostSet } from '../types';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export interface MutationObserverBaseOptions extends MutationObserverInit
|
|
6
|
-
// observe 대상 셀렉터. 기본값 $this (컴포넌트 자신)
|
|
7
|
-
// delegate: true 인 경우 root에 observer를 걸고 셀렉터 매칭 대상의 mutation만 콜백
|
|
8
|
-
// 셀렉터로 직접 지정한 경우 해당 요소들을 각각 observe
|
|
9
|
-
delegate?: boolean;
|
|
2
|
+
import { SpecialSelector, SwcQueryOptions, SwcSelector, SwcFnSelector, HelperHostSet } from '../types';
|
|
3
|
+
|
|
4
|
+
// 공통 옵션 — root·delegate 없음 (MutationObserverInit + filter/removeObserver)
|
|
5
|
+
export interface MutationObserverBaseOptions extends MutationObserverInit {
|
|
10
6
|
filter?: (matchedEls: HTMLElement[], meta: { currentThis: any, helper: HelperHostSet }) => boolean;
|
|
11
7
|
// observer 해제(disconnected) 시 호출되는 콜백. 첫 번째 인자는 observe된 target element, 두 번째는 사용자 옵션 객체.
|
|
12
|
-
removeObserver?: (target: Element, optionValue:
|
|
8
|
+
removeObserver?: (target: Element, optionValue: MutationObserverQueryOptions) => void;
|
|
13
9
|
}
|
|
14
10
|
|
|
11
|
+
// 문자열 셀렉터 전용 — root·delegate 허용 (셀렉터로 탐색/델리게이션)
|
|
12
|
+
export type MutationObserverQueryOptions = MutationObserverBaseOptions & SwcQueryOptions & { delegate?: boolean };
|
|
13
|
+
// 함수 셀렉터 전용 — root·delegate 금지 (이미 요소를 직접 반환)
|
|
14
|
+
export type MutationObserverNonQueryOptions = MutationObserverBaseOptions;
|
|
15
|
+
|
|
16
|
+
// 셀렉터 종류에 따라 옵션 타입 분기
|
|
17
|
+
export type MutationObserverOptionsOf<S extends SwcSelector> = S extends string ? MutationObserverQueryOptions : MutationObserverNonQueryOptions;
|
|
18
|
+
|
|
15
19
|
export interface MutationObserverMetadata {
|
|
16
20
|
propertyKey: string | symbol;
|
|
17
|
-
selector:
|
|
18
|
-
options:
|
|
21
|
+
selector: SwcSelector;
|
|
22
|
+
options: MutationObserverQueryOptions;
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
export const MUTATION_OBSERVER_METADATA_KEY = Symbol.for('simple-web-component:mutation-observer');
|
|
22
26
|
|
|
23
|
-
export function mutationObserver(target: SpecialSelector, options?:
|
|
24
|
-
export function mutationObserver(selector:
|
|
25
|
-
export function mutationObserver(options?:
|
|
27
|
+
export function mutationObserver(target: SpecialSelector, options?: MutationObserverQueryOptions): MethodDecorator;
|
|
28
|
+
export function mutationObserver(selector: string, options?: MutationObserverQueryOptions): MethodDecorator;
|
|
29
|
+
export function mutationObserver(selector: SwcFnSelector, options?: MutationObserverNonQueryOptions): MethodDecorator;
|
|
30
|
+
export function mutationObserver(options?: MutationObserverQueryOptions): MethodDecorator;
|
|
26
31
|
/**
|
|
27
32
|
* @mutationObserver decorator to observe DOM mutations.
|
|
28
33
|
*/
|
|
29
|
-
export function mutationObserver(selectorOrOptions?:
|
|
34
|
+
export function mutationObserver(selectorOrOptions?: SwcSelector | MutationObserverQueryOptions, maybeOptions?: MutationObserverQueryOptions): MethodDecorator {
|
|
30
35
|
return (targetObj: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
|
|
31
|
-
let selector:
|
|
32
|
-
let options:
|
|
36
|
+
let selector: SwcSelector = '$this';
|
|
37
|
+
let options: MutationObserverQueryOptions = {};
|
|
33
38
|
|
|
34
39
|
if (typeof selectorOrOptions === 'string' || typeof selectorOrOptions === 'function') {
|
|
35
40
|
selector = selectorOrOptions;
|
|
@@ -51,42 +56,42 @@ export function mutationObserver(selectorOrOptions?: EventListenerSelector | Mut
|
|
|
51
56
|
};
|
|
52
57
|
}
|
|
53
58
|
|
|
54
|
-
export function mutationObserverThis<TEvent extends Event = Event>(options?:
|
|
59
|
+
export function mutationObserverThis<TEvent extends Event = Event>(options?: MutationObserverQueryOptions): MethodDecorator {
|
|
55
60
|
return mutationObserver('$this', options);
|
|
56
61
|
}
|
|
57
62
|
|
|
58
63
|
// ─── root별 delegate 헬퍼 (addEventListener와 동일 패턴) ───
|
|
59
64
|
|
|
60
|
-
export function mutationObserverDelegateLight(selector:
|
|
61
|
-
export function mutationObserverDelegateLight(options?:
|
|
62
|
-
export function mutationObserverDelegateLight(selectorOrOptions?:
|
|
65
|
+
export function mutationObserverDelegateLight(selector: string, options?: MutationObserverBaseOptions): MethodDecorator;
|
|
66
|
+
export function mutationObserverDelegateLight(options?: MutationObserverBaseOptions): MethodDecorator;
|
|
67
|
+
export function mutationObserverDelegateLight(selectorOrOptions?: string | Omit<MutationObserverQueryOptions, 'root'>, maybeOptions?: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator {
|
|
63
68
|
if (typeof selectorOrOptions === 'string' || typeof selectorOrOptions === 'function') {
|
|
64
69
|
return mutationObserver(selectorOrOptions, {...maybeOptions ?? {}, root: 'light', delegate: true});
|
|
65
70
|
}
|
|
66
71
|
return mutationObserver({...selectorOrOptions ?? {}, root: 'light', delegate: true});
|
|
67
72
|
}
|
|
68
73
|
|
|
69
|
-
export function mutationObserverDelegateShadow(selector:
|
|
70
|
-
export function mutationObserverDelegateShadow(options?:
|
|
71
|
-
export function mutationObserverDelegateShadow(selectorOrOptions?:
|
|
74
|
+
export function mutationObserverDelegateShadow(selector: string, options?: MutationObserverBaseOptions): MethodDecorator;
|
|
75
|
+
export function mutationObserverDelegateShadow(options?: MutationObserverBaseOptions): MethodDecorator;
|
|
76
|
+
export function mutationObserverDelegateShadow(selectorOrOptions?: string | Omit<MutationObserverQueryOptions, 'root'>, maybeOptions?: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator {
|
|
72
77
|
if (typeof selectorOrOptions === 'string' || typeof selectorOrOptions === 'function') {
|
|
73
78
|
return mutationObserver(selectorOrOptions, {...maybeOptions ?? {}, root: 'shadow', delegate: true});
|
|
74
79
|
}
|
|
75
80
|
return mutationObserver({...selectorOrOptions ?? {}, root: 'shadow', delegate: true});
|
|
76
81
|
}
|
|
77
82
|
|
|
78
|
-
export function mutationObserverDelegateAll(selector:
|
|
79
|
-
export function mutationObserverDelegateAll(options?:
|
|
80
|
-
export function mutationObserverDelegateAll(selectorOrOptions?:
|
|
83
|
+
export function mutationObserverDelegateAll(selector: string, options?: MutationObserverBaseOptions): MethodDecorator;
|
|
84
|
+
export function mutationObserverDelegateAll(options?: MutationObserverBaseOptions): MethodDecorator;
|
|
85
|
+
export function mutationObserverDelegateAll(selectorOrOptions?: string | Omit<MutationObserverQueryOptions, 'root'>, maybeOptions?: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator {
|
|
81
86
|
if (typeof selectorOrOptions === 'string' || typeof selectorOrOptions === 'function') {
|
|
82
87
|
return mutationObserver(selectorOrOptions, {...maybeOptions ?? {}, root: 'all', delegate: true});
|
|
83
88
|
}
|
|
84
89
|
return mutationObserver({...selectorOrOptions ?? {}, root: 'all', delegate: true});
|
|
85
90
|
}
|
|
86
91
|
|
|
87
|
-
export function mutationObserverDelegate(selector:
|
|
88
|
-
export function mutationObserverDelegate(options?:
|
|
89
|
-
export function mutationObserverDelegate(selectorOrOptions?:
|
|
92
|
+
export function mutationObserverDelegate(selector: string, options?: MutationObserverBaseOptions): MethodDecorator;
|
|
93
|
+
export function mutationObserverDelegate(options?: MutationObserverBaseOptions): MethodDecorator;
|
|
94
|
+
export function mutationObserverDelegate(selectorOrOptions?: string | Omit<MutationObserverQueryOptions, 'root'>, maybeOptions?: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator {
|
|
90
95
|
if (typeof selectorOrOptions === 'string' || typeof selectorOrOptions === 'function') {
|
|
91
96
|
return mutationObserver(selectorOrOptions, {...maybeOptions ?? {}, root: 'auto', delegate: true});
|
|
92
97
|
}
|
|
@@ -95,27 +100,27 @@ export function mutationObserverDelegate(selectorOrOptions?: EventListenerSelect
|
|
|
95
100
|
|
|
96
101
|
// ─── root별 일반 헬퍼 (delegate 없이, 셀렉터 생략 시 $this) ───
|
|
97
102
|
|
|
98
|
-
export function mutationObserverLight(selector:
|
|
99
|
-
export function mutationObserverLight(options?:
|
|
100
|
-
export function mutationObserverLight(selectorOrOptions?:
|
|
103
|
+
export function mutationObserverLight(selector: string, options?: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator;
|
|
104
|
+
export function mutationObserverLight(options?: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator;
|
|
105
|
+
export function mutationObserverLight(selectorOrOptions?: string | Omit<MutationObserverQueryOptions, 'root'>, maybeOptions?: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator {
|
|
101
106
|
if (typeof selectorOrOptions === 'string' || typeof selectorOrOptions === 'function') {
|
|
102
107
|
return mutationObserver(selectorOrOptions, {...maybeOptions ?? {}, root: 'light'});
|
|
103
108
|
}
|
|
104
109
|
return mutationObserver({...selectorOrOptions ?? {}, root: 'light'});
|
|
105
110
|
}
|
|
106
111
|
|
|
107
|
-
export function mutationObserverShadow(selector:
|
|
108
|
-
export function mutationObserverShadow(options?:
|
|
109
|
-
export function mutationObserverShadow(selectorOrOptions?:
|
|
112
|
+
export function mutationObserverShadow(selector: string, options?: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator;
|
|
113
|
+
export function mutationObserverShadow(options?: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator;
|
|
114
|
+
export function mutationObserverShadow(selectorOrOptions?: string | Omit<MutationObserverQueryOptions, 'root'>, maybeOptions?: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator {
|
|
110
115
|
if (typeof selectorOrOptions === 'string' || typeof selectorOrOptions === 'function') {
|
|
111
116
|
return mutationObserver(selectorOrOptions, {...maybeOptions ?? {}, root: 'shadow'});
|
|
112
117
|
}
|
|
113
118
|
return mutationObserver({...selectorOrOptions ?? {}, root: 'shadow'});
|
|
114
119
|
}
|
|
115
120
|
|
|
116
|
-
export function mutationObserverAll(selector:
|
|
117
|
-
export function mutationObserverAll(options?:
|
|
118
|
-
export function mutationObserverAll(selectorOrOptions?:
|
|
121
|
+
export function mutationObserverAll(selector: string, options?: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator;
|
|
122
|
+
export function mutationObserverAll(options?: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator;
|
|
123
|
+
export function mutationObserverAll(selectorOrOptions?: string | Omit<MutationObserverQueryOptions, 'root'>, maybeOptions?: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator {
|
|
119
124
|
if (typeof selectorOrOptions === 'string' || typeof selectorOrOptions === 'function') {
|
|
120
125
|
return mutationObserver(selectorOrOptions, {...maybeOptions ?? {}, root: 'all'});
|
|
121
126
|
}
|
|
@@ -125,4 +130,175 @@ export function mutationObserverAll(selectorOrOptions?: EventListenerSelector |
|
|
|
125
130
|
export function getMutationObserverMetadata(target: any): MutationObserverMetadata[] | undefined {
|
|
126
131
|
const constructor = target instanceof Function ? target : target.constructor;
|
|
127
132
|
return ReflectUtils.getMetadata(MUTATION_OBSERVER_METADATA_KEY, constructor);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
136
|
+
// MutationObserverLifeCycler
|
|
137
|
+
// observer 를 직접 생성하지 않고 OnConnectedResult 를 반환한다.
|
|
138
|
+
// elementDefine 이 수집된 MutationObserverSet 으로 observer 를 생성한다.
|
|
139
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
140
|
+
import { ElementDefineLifeCycler, MutationObserverSet, MutationObserverSetEntry, ObserverObserveTarget, OnConnectedResult } from '../types';
|
|
141
|
+
import { SwcUtils } from '../utils/Utils';
|
|
142
|
+
|
|
143
|
+
export class MutationObserverLifeCycler implements ElementDefineLifeCycler {
|
|
144
|
+
private readonly removeObserverCallbacksMap = new WeakMap<Element, Array<{ fn: (target: Element, opts: unknown) => void; target: any; opts: unknown }>>();
|
|
145
|
+
|
|
146
|
+
onConnected(helperHostSet: HelperHostSet): OnConnectedResult | void {
|
|
147
|
+
const inst = helperHostSet.$this;
|
|
148
|
+
const currentWin = helperHostSet.$w;
|
|
149
|
+
|
|
150
|
+
const removeObserverCallbacks: Array<{ fn: (target: Element, opts: unknown) => void; target: any; opts: unknown }> = [];
|
|
151
|
+
this.removeObserverCallbacksMap.set(inst, removeObserverCallbacks);
|
|
152
|
+
|
|
153
|
+
const allMeta = getMutationObserverMetadata(inst) ?? [];
|
|
154
|
+
// 처리할 메타가 없으면 observer 불필요
|
|
155
|
+
if (allMeta.length === 0) return;
|
|
156
|
+
|
|
157
|
+
// ── shadow / light 루트별 분류 ──
|
|
158
|
+
const shadowMetas = allMeta.filter(m => {
|
|
159
|
+
const r = m.options.root || 'auto';
|
|
160
|
+
return inst.shadowRoot && (r === 'shadow' || r === 'all' || r === 'auto');
|
|
161
|
+
});
|
|
162
|
+
const lightMetas = allMeta.filter(m => {
|
|
163
|
+
const r = m.options.root || 'auto';
|
|
164
|
+
return r === 'light' || r === 'all' || (!inst.shadowRoot && r === 'auto');
|
|
165
|
+
});
|
|
166
|
+
// ── MutationObserverSet 생성 헬퍼 (루트별) ──
|
|
167
|
+
const buildSet = (
|
|
168
|
+
root: HTMLElement | ShadowRoot,
|
|
169
|
+
metas: MutationObserverMetadata[],
|
|
170
|
+
): { callback: MutationObserverSetEntry['callback']; observeTargets: ObserverObserveTarget<MutationObserverInit>[] } | null => {
|
|
171
|
+
if (metas.length === 0) return null;
|
|
172
|
+
|
|
173
|
+
const initFrom = (o: MutationObserverBaseOptions): MutationObserverInit => {
|
|
174
|
+
const init: MutationObserverInit = {
|
|
175
|
+
childList: o.childList, attributes: o.attributes, characterData: o.characterData,
|
|
176
|
+
subtree: o.subtree, attributeFilter: o.attributeFilter,
|
|
177
|
+
attributeOldValue: o.attributeOldValue, characterDataOldValue: o.characterDataOldValue,
|
|
178
|
+
};
|
|
179
|
+
if (!init.childList && !init.attributes && !init.characterData) init.childList = true;
|
|
180
|
+
return init;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const fnObservedSets = new Map<MutationObserverMetadata, WeakSet<Element>>();
|
|
184
|
+
|
|
185
|
+
const callback = (mutations: MutationRecord[], obs: MutationObserver) => {
|
|
186
|
+
// ── MutationObserver 메타 콜백 ──
|
|
187
|
+
for (const meta of metas) {
|
|
188
|
+
const { selector, options } = meta;
|
|
189
|
+
let matchedEls: HTMLElement[] = [];
|
|
190
|
+
|
|
191
|
+
const typeMatches = (m: MutationRecord): boolean => {
|
|
192
|
+
const has = !!(options.childList || options.attributes || options.characterData);
|
|
193
|
+
if (m.type === 'childList') return has ? !!options.childList : true;
|
|
194
|
+
if (m.type === 'attributes') return !!options.attributes;
|
|
195
|
+
if (m.type === 'characterData') return !!options.characterData;
|
|
196
|
+
return true;
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const collect = (matchesSel: (n: any) => boolean) =>
|
|
200
|
+
mutations.flatMap(m => {
|
|
201
|
+
if (!typeMatches(m)) return [];
|
|
202
|
+
const els: HTMLElement[] = [];
|
|
203
|
+
if (matchesSel(m.target)) els.push(m.target as HTMLElement);
|
|
204
|
+
Array.from(m.addedNodes || []).filter(matchesSel).forEach(n => els.push(n as HTMLElement));
|
|
205
|
+
Array.from(m.removedNodes || []).filter(matchesSel).forEach(n => els.push(n as HTMLElement));
|
|
206
|
+
return els;
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
if (options.delegate && typeof selector === 'string') {
|
|
210
|
+
const isThis = selector === '$this' || selector === '';
|
|
211
|
+
matchedEls = collect(n => {
|
|
212
|
+
if (!n || n.nodeType !== 1) return false;
|
|
213
|
+
if (isThis) return true;
|
|
214
|
+
const el = n as HTMLElement;
|
|
215
|
+
return el.matches?.(selector) || !!el.closest?.(selector);
|
|
216
|
+
});
|
|
217
|
+
} else if (typeof selector === 'string') {
|
|
218
|
+
const isThis = selector === '$this' || selector === '';
|
|
219
|
+
matchedEls = collect(n => {
|
|
220
|
+
if (!n || n.nodeType !== 1) return false;
|
|
221
|
+
if (isThis) return true;
|
|
222
|
+
return (n as HTMLElement).matches?.(selector);
|
|
223
|
+
});
|
|
224
|
+
} else if (typeof selector === 'function') {
|
|
225
|
+
const set = fnObservedSets.get(meta);
|
|
226
|
+
matchedEls = mutations.filter(m => typeMatches(m))
|
|
227
|
+
.map(m => m.target as HTMLElement)
|
|
228
|
+
.filter(t => t && t.nodeType === 1 && (set ? set.has(t) : false));
|
|
229
|
+
} else {
|
|
230
|
+
matchedEls = mutations.filter(m => typeMatches(m))
|
|
231
|
+
.map(m => m.target as HTMLElement)
|
|
232
|
+
.filter(t => t && t.nodeType === 1);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (matchedEls.length === 0) continue;
|
|
236
|
+
if (options.filter) {
|
|
237
|
+
if (!options.filter(matchedEls, { currentThis: inst, helper: helperHostSet })) continue;
|
|
238
|
+
}
|
|
239
|
+
const hostSet = SwcUtils.getHostSet(inst);
|
|
240
|
+
inst[meta.propertyKey](matchedEls, mutations, obs, { ...hostSet, $root: root });
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
// ── observe 대상 목록 구성 ──
|
|
246
|
+
const observeTargets: ObserverObserveTarget<MutationObserverInit>[] = [];
|
|
247
|
+
|
|
248
|
+
// delegate 있으면 루트 전체 subtree observe
|
|
249
|
+
if (metas.some(m => m.options.delegate)) {
|
|
250
|
+
observeTargets.push({ target: root, options: { childList: true, subtree: true } });
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// non-delegate: 셀렉터 매칭 요소 직접 observe
|
|
254
|
+
for (const m of metas.filter(m => !m.options.delegate)) {
|
|
255
|
+
const { selector, options } = m;
|
|
256
|
+
const mInit = initFrom(options);
|
|
257
|
+
if (typeof selector === 'string') {
|
|
258
|
+
if (selector === '$this' || selector === '') {
|
|
259
|
+
observeTargets.push({ target: root, options: mInit });
|
|
260
|
+
} else {
|
|
261
|
+
root.querySelectorAll(selector).forEach(el => observeTargets.push({ target: el as Element, options: mInit }));
|
|
262
|
+
}
|
|
263
|
+
} else if (typeof selector === 'function') {
|
|
264
|
+
const res = (selector as any)(inst, helperHostSet);
|
|
265
|
+
let targets: HTMLElement[] = [];
|
|
266
|
+
if (res instanceof currentWin.HTMLElement) targets = [res as HTMLElement];
|
|
267
|
+
else if (res instanceof currentWin.NodeList) targets = Array.from(res as NodeList).filter((e: any) => e instanceof currentWin.HTMLElement) as HTMLElement[];
|
|
268
|
+
else if (Array.isArray(res)) targets = res.filter((e: any) => e instanceof currentWin.HTMLElement) as HTMLElement[];
|
|
269
|
+
const set = new WeakSet<Element>();
|
|
270
|
+
for (const el of targets) { set.add(el); observeTargets.push({ target: el, options: mInit }); }
|
|
271
|
+
fnObservedSets.set(m, set);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// removeObserver 콜백 수집
|
|
276
|
+
for (const m of metas) {
|
|
277
|
+
if (m.options.removeObserver) removeObserverCallbacks.push({ fn: m.options.removeObserver, target: root, opts: m.options });
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return { callback, observeTargets };
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
const shadowSet = inst.shadowRoot ? buildSet(inst.shadowRoot, shadowMetas) : null;
|
|
284
|
+
const lightSet = buildSet(inst as any, lightMetas);
|
|
285
|
+
|
|
286
|
+
// 두 루트의 observe 대상 + 콜백을 엔트리 배열(MutationObserverSet)로 병합
|
|
287
|
+
// 같은 루트의 여러 대상은 같은 callback 을 공유한다.
|
|
288
|
+
const mutationObserverSet: MutationObserverSet = [
|
|
289
|
+
...(shadowSet?.observeTargets ?? []).map(t => ({ ...t, callback: shadowSet!.callback })),
|
|
290
|
+
...(lightSet?.observeTargets ?? []).map(t => ({ ...t, callback: lightSet!.callback })),
|
|
291
|
+
];
|
|
292
|
+
if (mutationObserverSet.length === 0) return;
|
|
293
|
+
|
|
294
|
+
return { mutationObserverSet };
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
onDisconnected(helperHostSet: HelperHostSet): void {
|
|
298
|
+
const inst = helperHostSet.$this;
|
|
299
|
+
for (const cb of this.removeObserverCallbacksMap.get(inst) ?? []) {
|
|
300
|
+
try { cb.fn(cb.target, cb.opts); } catch (e) { console.error('[SWC] removeObserver error:', e); }
|
|
301
|
+
}
|
|
302
|
+
this.removeObserverCallbacksMap.delete(inst);
|
|
303
|
+
}
|
|
128
304
|
}
|