@dooboostore/simple-web-component 1.0.49 → 1.0.51
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 +790 -337
- package/dist/cjs/SwcAppEngine.js.map +2 -2
- package/dist/cjs/decorators/addEventListener.js +1925 -22
- package/dist/cjs/decorators/addEventListener.js.map +2 -2
- package/dist/cjs/decorators/applyAttribute.js +41 -47
- package/dist/cjs/decorators/applyAttribute.js.map +2 -2
- package/dist/cjs/decorators/applyClass.js +14 -11
- package/dist/cjs/decorators/applyClass.js.map +2 -2
- package/dist/cjs/decorators/applyNode.js +19 -21
- package/dist/cjs/decorators/applyNode.js.map +2 -2
- package/dist/cjs/decorators/applyProperty.js +24 -48
- package/dist/cjs/decorators/applyProperty.js.map +2 -2
- package/dist/cjs/decorators/applySlot.js +9 -8
- package/dist/cjs/decorators/applySlot.js.map +2 -2
- package/dist/cjs/decorators/applyStyle.js +14 -11
- package/dist/cjs/decorators/applyStyle.js.map +2 -2
- package/dist/cjs/decorators/around.js +124 -0
- package/dist/cjs/decorators/around.js.map +7 -0
- package/dist/cjs/decorators/changedAttribute.js +61 -24
- package/dist/cjs/decorators/changedAttribute.js.map +2 -2
- package/dist/cjs/decorators/elementDefine.js +240 -196
- package/dist/cjs/decorators/elementDefine.js.map +3 -3
- package/dist/cjs/decorators/emitCustomEvent.js +14 -12
- package/dist/cjs/decorators/emitCustomEvent.js.map +2 -2
- package/dist/cjs/decorators/eventMedia.js +112 -0
- package/dist/cjs/decorators/eventMedia.js.map +7 -0
- package/dist/cjs/decorators/fetch.js +278 -0
- package/dist/cjs/decorators/fetch.js.map +7 -0
- package/dist/cjs/decorators/index.js +8 -2
- package/dist/cjs/decorators/index.js.map +2 -2
- package/dist/cjs/decorators/intersectionObserver.js +76 -65
- package/dist/cjs/decorators/intersectionObserver.js.map +2 -2
- package/dist/cjs/decorators/lifecycles.js +11 -11
- package/dist/cjs/decorators/lifecycles.js.map +2 -2
- package/dist/cjs/decorators/mutationObserver.js +97 -90
- package/dist/cjs/decorators/mutationObserver.js.map +3 -3
- package/dist/cjs/decorators/parameter.js +156 -0
- package/dist/cjs/decorators/parameter.js.map +7 -0
- package/dist/cjs/decorators/publishSwcAppMessage.js +2 -2
- package/dist/cjs/decorators/publishSwcAppMessage.js.map +2 -2
- package/dist/cjs/decorators/query.js +11 -5
- package/dist/cjs/decorators/query.js.map +2 -2
- package/dist/cjs/decorators/requestAnimationFrame.js +115 -0
- package/dist/cjs/decorators/requestAnimationFrame.js.map +7 -0
- package/dist/cjs/decorators/resizeObserver.js +84 -69
- package/dist/cjs/decorators/resizeObserver.js.map +3 -3
- package/dist/cjs/decorators/setInterval.js +65 -22
- package/dist/cjs/decorators/setInterval.js.map +2 -2
- package/dist/cjs/decorators/setTimeout.js +68 -22
- package/dist/cjs/decorators/setTimeout.js.map +2 -2
- package/dist/cjs/decorators/state.js +13 -10
- package/dist/cjs/decorators/state.js.map +2 -2
- package/dist/cjs/decorators/{subscribeSwcAppMessageWhileConnected.js → subscribeSwcAppMessage.js} +20 -21
- package/dist/cjs/decorators/subscribeSwcAppMessage.js.map +7 -0
- package/dist/cjs/decorators/{subscribeSwcAppRouteChangeWhileConnected.js → subscribeSwcAppRouteChange.js} +23 -19
- package/dist/cjs/decorators/subscribeSwcAppRouteChange.js.map +7 -0
- package/dist/cjs/decorators/swcAppRoute.js +149 -0
- package/dist/cjs/decorators/swcAppRoute.js.map +7 -0
- package/dist/cjs/elements/SwcApp.js +70 -0
- package/dist/cjs/elements/SwcApp.js.map +2 -2
- package/dist/cjs/elements/SwcAppMixin.js +256 -67
- package/dist/cjs/elements/SwcAppMixin.js.map +3 -3
- package/dist/cjs/types/index.js +5 -1
- package/dist/cjs/types/index.js.map +2 -2
- package/dist/cjs/types/window.d.js.map +1 -1
- package/dist/cjs/utils/Utils.js +36 -15
- package/dist/cjs/utils/Utils.js.map +2 -2
- package/dist/esm/SwcAppEngine.js.map +2 -2
- package/dist/esm/decorators/addEventListener.js +1925 -22
- package/dist/esm/decorators/addEventListener.js.map +2 -2
- package/dist/esm/decorators/applyAttribute.js +41 -47
- package/dist/esm/decorators/applyAttribute.js.map +2 -2
- package/dist/esm/decorators/applyClass.js +14 -11
- package/dist/esm/decorators/applyClass.js.map +2 -2
- package/dist/esm/decorators/applyNode.js +20 -22
- package/dist/esm/decorators/applyNode.js.map +2 -2
- package/dist/esm/decorators/applyProperty.js +24 -48
- package/dist/esm/decorators/applyProperty.js.map +2 -2
- package/dist/esm/decorators/applySlot.js +9 -8
- package/dist/esm/decorators/applySlot.js.map +2 -2
- package/dist/esm/decorators/applyStyle.js +14 -11
- package/dist/esm/decorators/applyStyle.js.map +2 -2
- package/dist/esm/decorators/around.js +105 -0
- package/dist/esm/decorators/around.js.map +7 -0
- package/dist/esm/decorators/changedAttribute.js +61 -24
- package/dist/esm/decorators/changedAttribute.js.map +2 -2
- package/dist/esm/decorators/elementDefine.js +238 -194
- package/dist/esm/decorators/elementDefine.js.map +3 -3
- package/dist/esm/decorators/emitCustomEvent.js +15 -13
- package/dist/esm/decorators/emitCustomEvent.js.map +2 -2
- package/dist/esm/decorators/eventMedia.js +94 -0
- package/dist/esm/decorators/eventMedia.js.map +7 -0
- package/dist/esm/decorators/fetch.js +259 -0
- package/dist/esm/decorators/fetch.js.map +7 -0
- package/dist/esm/decorators/index.js +8 -2
- package/dist/esm/decorators/index.js.map +2 -2
- package/dist/esm/decorators/intersectionObserver.js +76 -65
- package/dist/esm/decorators/intersectionObserver.js.map +2 -2
- package/dist/esm/decorators/lifecycles.js +11 -11
- package/dist/esm/decorators/lifecycles.js.map +2 -2
- package/dist/esm/decorators/mutationObserver.js +97 -90
- package/dist/esm/decorators/mutationObserver.js.map +3 -3
- package/dist/esm/decorators/parameter.js +137 -0
- package/dist/esm/decorators/parameter.js.map +7 -0
- package/dist/esm/decorators/publishSwcAppMessage.js +2 -2
- package/dist/esm/decorators/publishSwcAppMessage.js.map +2 -2
- package/dist/esm/decorators/query.js +11 -5
- package/dist/esm/decorators/query.js.map +2 -2
- package/dist/esm/decorators/requestAnimationFrame.js +96 -0
- package/dist/esm/decorators/requestAnimationFrame.js.map +7 -0
- package/dist/esm/decorators/resizeObserver.js +84 -69
- package/dist/esm/decorators/resizeObserver.js.map +2 -2
- package/dist/esm/decorators/setInterval.js +65 -23
- package/dist/esm/decorators/setInterval.js.map +2 -2
- package/dist/esm/decorators/setTimeout.js +68 -23
- package/dist/esm/decorators/setTimeout.js.map +2 -2
- package/dist/esm/decorators/state.js +13 -10
- package/dist/esm/decorators/state.js.map +2 -2
- package/dist/esm/decorators/subscribeSwcAppMessage.js +53 -0
- package/dist/esm/decorators/subscribeSwcAppMessage.js.map +7 -0
- package/dist/esm/decorators/{subscribeSwcAppRouteChangeWhileConnected.js → subscribeSwcAppRouteChange.js} +20 -16
- package/dist/esm/decorators/subscribeSwcAppRouteChange.js.map +7 -0
- package/dist/esm/decorators/swcAppRoute.js +130 -0
- package/dist/esm/decorators/swcAppRoute.js.map +7 -0
- package/dist/esm/elements/SwcApp.js +70 -0
- package/dist/esm/elements/SwcApp.js.map +2 -2
- package/dist/esm/elements/SwcAppMixin.js +258 -69
- package/dist/esm/elements/SwcAppMixin.js.map +3 -3
- package/dist/esm/types/index.js +5 -1
- package/dist/esm/types/index.js.map +2 -2
- package/dist/esm/utils/Utils.js +36 -15
- package/dist/esm/utils/Utils.js.map +2 -2
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +4395 -1266
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
- package/dist/types/SwcAppEngine.d.ts +1 -0
- package/dist/types/SwcAppEngine.d.ts.map +1 -1
- package/dist/types/decorators/addEventListener.d.ts +936 -11
- package/dist/types/decorators/addEventListener.d.ts.map +1 -1
- package/dist/types/decorators/applyAttribute.d.ts +27 -37
- package/dist/types/decorators/applyAttribute.d.ts.map +1 -1
- package/dist/types/decorators/applyClass.d.ts +2 -2
- package/dist/types/decorators/applyClass.d.ts.map +1 -1
- package/dist/types/decorators/applyNode.d.ts +16 -16
- package/dist/types/decorators/applyNode.d.ts.map +1 -1
- package/dist/types/decorators/applyProperty.d.ts +28 -44
- package/dist/types/decorators/applyProperty.d.ts.map +1 -1
- package/dist/types/decorators/applySlot.d.ts.map +1 -1
- package/dist/types/decorators/applyStyle.d.ts +2 -2
- package/dist/types/decorators/applyStyle.d.ts.map +1 -1
- package/dist/types/decorators/around.d.ts +87 -0
- package/dist/types/decorators/around.d.ts.map +1 -0
- package/dist/types/decorators/changedAttribute.d.ts +22 -4
- package/dist/types/decorators/changedAttribute.d.ts.map +1 -1
- package/dist/types/decorators/elementDefine.d.ts.map +1 -1
- package/dist/types/decorators/emitCustomEvent.d.ts +0 -1
- package/dist/types/decorators/emitCustomEvent.d.ts.map +1 -1
- package/dist/types/decorators/eventMedia.d.ts +48 -0
- package/dist/types/decorators/eventMedia.d.ts.map +1 -0
- package/dist/types/decorators/fetch.d.ts +139 -0
- package/dist/types/decorators/fetch.d.ts.map +1 -0
- package/dist/types/decorators/index.d.ts +8 -2
- package/dist/types/decorators/index.d.ts.map +1 -1
- package/dist/types/decorators/intersectionObserver.d.ts +32 -10
- package/dist/types/decorators/intersectionObserver.d.ts.map +1 -1
- package/dist/types/decorators/lifecycles.d.ts +8 -7
- package/dist/types/decorators/lifecycles.d.ts.map +1 -1
- package/dist/types/decorators/mutationObserver.d.ts +34 -12
- package/dist/types/decorators/mutationObserver.d.ts.map +1 -1
- package/dist/types/decorators/parameter.d.ts +113 -0
- package/dist/types/decorators/parameter.d.ts.map +1 -0
- package/dist/types/decorators/publishSwcAppMessage.d.ts +0 -1
- package/dist/types/decorators/publishSwcAppMessage.d.ts.map +1 -1
- package/dist/types/decorators/query.d.ts +7 -7
- package/dist/types/decorators/query.d.ts.map +1 -1
- package/dist/types/decorators/requestAnimationFrame.d.ts +47 -0
- package/dist/types/decorators/requestAnimationFrame.d.ts.map +1 -0
- package/dist/types/decorators/resizeObserver.d.ts +34 -12
- package/dist/types/decorators/resizeObserver.d.ts.map +1 -1
- package/dist/types/decorators/setInterval.d.ts +27 -5
- package/dist/types/decorators/setInterval.d.ts.map +1 -1
- package/dist/types/decorators/setTimeout.d.ts +27 -5
- package/dist/types/decorators/setTimeout.d.ts.map +1 -1
- package/dist/types/decorators/state.d.ts.map +1 -1
- package/dist/types/decorators/subscribeSwcAppMessage.d.ts +44 -0
- package/dist/types/decorators/subscribeSwcAppMessage.d.ts.map +1 -0
- package/dist/types/decorators/subscribeSwcAppRouteChange.d.ts +60 -0
- package/dist/types/decorators/subscribeSwcAppRouteChange.d.ts.map +1 -0
- package/dist/types/decorators/swcAppRoute.d.ts +94 -0
- package/dist/types/decorators/swcAppRoute.d.ts.map +1 -0
- package/dist/types/elements/SwcApp.d.ts.map +1 -1
- package/dist/types/elements/SwcAppMixin.d.ts +423 -388
- package/dist/types/elements/SwcAppMixin.d.ts.map +1 -1
- package/dist/types/types/index.d.ts +43 -4
- package/dist/types/types/index.d.ts.map +1 -1
- package/dist/types/utils/Utils.d.ts +15 -5
- package/dist/types/utils/Utils.d.ts.map +1 -1
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +4395 -1266
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
- package/package.json +8 -6
- package/src/SwcAppEngine.ts +1 -0
- package/src/decorators/addEventListener.ts +1086 -28
- package/src/decorators/applyAttribute.ts +82 -134
- package/src/decorators/applyClass.ts +14 -10
- package/src/decorators/applyNode.ts +39 -37
- package/src/decorators/applyProperty.ts +72 -100
- package/src/decorators/applySlot.ts +9 -8
- package/src/decorators/applyStyle.ts +14 -10
- package/src/decorators/around.ts +196 -0
- package/src/decorators/changedAttribute.ts +65 -26
- package/src/decorators/elementDefine.ts +298 -220
- package/src/decorators/emitCustomEvent.ts +17 -13
- package/src/decorators/eventMedia.ts +119 -0
- package/src/decorators/fetch.ts +454 -0
- package/src/decorators/index.ts +8 -2
- package/src/decorators/intersectionObserver.ts +108 -78
- package/src/decorators/lifecycles.ts +24 -22
- package/src/decorators/mutationObserver.ts +140 -104
- package/src/decorators/parameter.ts +212 -0
- package/src/decorators/publishSwcAppMessage.ts +3 -4
- package/src/decorators/query.ts +22 -14
- package/src/decorators/requestAnimationFrame.ts +149 -0
- package/src/decorators/resizeObserver.ts +119 -82
- package/src/decorators/setInterval.ts +90 -23
- package/src/decorators/setTimeout.ts +93 -23
- package/src/decorators/state.ts +19 -13
- package/src/decorators/subscribeSwcAppMessage.ts +106 -0
- package/src/decorators/subscribeSwcAppRouteChange.ts +131 -0
- package/src/decorators/swcAppRoute.ts +231 -0
- package/src/elements/SwcApp.ts +40 -10
- package/src/elements/SwcAppMixin.ts +329 -85
- package/src/types/index.ts +38 -5
- package/src/types/window.d.ts +2 -18
- package/src/utils/Utils.ts +50 -18
- package/dist/cjs/decorators/subscribeSwcAppMessageWhileConnected.js.map +0 -7
- package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +0 -7
- package/dist/cjs/examples/RxJSOperatorsExample.js +0 -285
- package/dist/cjs/examples/RxJSOperatorsExample.js.map +0 -7
- package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js +0 -54
- package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js.map +0 -7
- package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +0 -7
- package/dist/esm/examples/RxJSOperatorsExample.js +0 -266
- package/dist/esm/examples/RxJSOperatorsExample.js.map +0 -7
- package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts +0 -23
- package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts.map +0 -1
- package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts +0 -31
- package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts.map +0 -1
- package/dist/types/examples/RxJSOperatorsExample.d.ts +0 -94
- package/dist/types/examples/RxJSOperatorsExample.d.ts.map +0 -1
- package/src/decorators/subscribeSwcAppMessageWhileConnected.ts +0 -91
- package/src/decorators/subscribeSwcAppRouteChangeWhileConnected.ts +0 -107
- package/src/examples/RxJSOperatorsExample.ts +0 -279
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { ReflectUtils } from '@dooboostore/core';
|
|
2
2
|
import { SpecialSelector, SwcQueryOptions, SwcSelector, SwcFnSelector, HelperHostSet } from '../types';
|
|
3
|
+
import { buildSwcParameterArgs } from './parameter';
|
|
3
4
|
|
|
4
5
|
// 공통 옵션 — root·delegate 없음 (MutationObserverInit + filter/removeObserver)
|
|
5
6
|
export interface MutationObserverBaseOptions extends MutationObserverInit {
|
|
6
|
-
|
|
7
|
+
/** 매칭 시 핸들러 실행 여부 게이트. Promise<boolean>도 되어 async 판정 가능. false면 스킵. */
|
|
8
|
+
filter?: (matchedEls: HTMLElement[], meta: { currentThis: any, helper: HelperHostSet }) => boolean | Promise<boolean>;
|
|
9
|
+
/** filter 통과 후 핸들러 직전 훅. await되고, 리턴값은 @mutationObserverBeforeReturn 으로 핸들러에 주입된다. */
|
|
10
|
+
before?: (matchedEls: HTMLElement[], meta: { currentThis: any, helper: HelperHostSet }) => any | Promise<any>;
|
|
11
|
+
/** 핸들러가 성공/실패해도 항상 실행되는 정리 훅. ctx로 결과/에러를 받는다. 에러는 로깅됨. */
|
|
12
|
+
finally?: (matchedEls: HTMLElement[], meta: { currentThis: any, helper: HelperHostSet }, ctx: { args: any[]; result?: any; error?: any }) => any | Promise<any>;
|
|
7
13
|
// observer 해제(disconnected) 시 호출되는 콜백. 첫 번째 인자는 observe된 target element, 두 번째는 사용자 옵션 객체.
|
|
8
14
|
removeObserver?: (target: Element, optionValue: MutationObserverQueryOptions) => void;
|
|
9
15
|
}
|
|
@@ -24,112 +30,124 @@ export interface MutationObserverMetadata {
|
|
|
24
30
|
|
|
25
31
|
export const MUTATION_OBSERVER_METADATA_KEY = Symbol.for('simple-web-component:mutation-observer');
|
|
26
32
|
|
|
33
|
+
const applyMutationObserver = (selector: SwcSelector, options: MutationObserverQueryOptions, targetObj: Object, propertyKey: string | symbol): void => {
|
|
34
|
+
const constructor = targetObj.constructor;
|
|
35
|
+
let observers = ReflectUtils.getOwnMetadata(MUTATION_OBSERVER_METADATA_KEY, constructor) as MutationObserverMetadata[] | undefined;
|
|
36
|
+
if (!observers) {
|
|
37
|
+
observers = [];
|
|
38
|
+
ReflectUtils.defineMetadata(MUTATION_OBSERVER_METADATA_KEY, observers, constructor);
|
|
39
|
+
}
|
|
40
|
+
observers.push({ propertyKey, selector, options });
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const resolveMutationObserverArgs = (
|
|
44
|
+
selectorOrOptions: SwcSelector | MutationObserverQueryOptions | undefined,
|
|
45
|
+
maybeOptions: MutationObserverQueryOptions | undefined,
|
|
46
|
+
extra: Partial<MutationObserverQueryOptions>
|
|
47
|
+
): { selector: SwcSelector; options: MutationObserverQueryOptions } => {
|
|
48
|
+
if (typeof selectorOrOptions === 'string' || typeof selectorOrOptions === 'function') {
|
|
49
|
+
return { selector: selectorOrOptions, options: { ...(maybeOptions ?? {}), ...extra } };
|
|
50
|
+
}
|
|
51
|
+
return { selector: '$this', options: { ...(selectorOrOptions ?? {}), ...extra } };
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* selectorOrOptionsOrTarget/maybeOptionsOrPropertyKey/descriptor을 받아 bare(@decorator)와
|
|
56
|
+
* factory(@decorator(...), 빈 괄호는 타입에서 막음) 호출을 모두 처리하는 공통 디스패처.
|
|
57
|
+
* extra는 Light/Shadow/All/Delegate 변형이 강제로 덧씌우는 옵션(root, delegate 등)이다.
|
|
58
|
+
*/
|
|
59
|
+
const dispatchMutationObserver = (
|
|
60
|
+
selectorOrOptionsOrTarget: SwcSelector | MutationObserverQueryOptions | Object | undefined,
|
|
61
|
+
maybeOptionsOrPropertyKey: MutationObserverQueryOptions | string | symbol | undefined,
|
|
62
|
+
descriptor: PropertyDescriptor | undefined,
|
|
63
|
+
extra: Partial<MutationObserverQueryOptions>
|
|
64
|
+
): MethodDecorator | void => {
|
|
65
|
+
if ((typeof maybeOptionsOrPropertyKey === 'string' || typeof maybeOptionsOrPropertyKey === 'symbol') && descriptor !== undefined) {
|
|
66
|
+
// 옵션 없이: @decorator — 자기 자신의 하위 전체(childList + subtree)를 본다. 범위를 좁히려면 옵션을 명시.
|
|
67
|
+
applyMutationObserver('$this', { subtree: true, ...extra }, selectorOrOptionsOrTarget as Object, maybeOptionsOrPropertyKey);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
// 옵션과 함께: @decorator(selector, options) / @decorator(options)
|
|
71
|
+
const { selector, options } = resolveMutationObserverArgs(
|
|
72
|
+
selectorOrOptionsOrTarget as SwcSelector | MutationObserverQueryOptions | undefined,
|
|
73
|
+
maybeOptionsOrPropertyKey as MutationObserverQueryOptions | undefined,
|
|
74
|
+
extra
|
|
75
|
+
);
|
|
76
|
+
return (targetObj: Object, propertyKey: string | symbol) => {
|
|
77
|
+
applyMutationObserver(selector, options, targetObj, propertyKey);
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
|
|
27
81
|
export function mutationObserver(target: SpecialSelector, options?: MutationObserverQueryOptions): MethodDecorator;
|
|
28
82
|
export function mutationObserver(selector: string, options?: MutationObserverQueryOptions): MethodDecorator;
|
|
29
83
|
export function mutationObserver(selector: SwcFnSelector, options?: MutationObserverNonQueryOptions): MethodDecorator;
|
|
30
|
-
export function mutationObserver(options
|
|
84
|
+
export function mutationObserver(options: MutationObserverQueryOptions): MethodDecorator;
|
|
85
|
+
export function mutationObserver(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
|
|
31
86
|
/**
|
|
32
87
|
* @mutationObserver decorator to observe DOM mutations.
|
|
88
|
+
* 옵션 없이 `@mutationObserver` 그대로 붙여도 되고, `@mutationObserver(...)`처럼 셀렉터/옵션을 줄 수도 있다.
|
|
33
89
|
*/
|
|
34
|
-
export function mutationObserver(
|
|
35
|
-
return (
|
|
36
|
-
let selector: SwcSelector = '$this';
|
|
37
|
-
let options: MutationObserverQueryOptions = {};
|
|
38
|
-
|
|
39
|
-
if (typeof selectorOrOptions === 'string' || typeof selectorOrOptions === 'function') {
|
|
40
|
-
selector = selectorOrOptions;
|
|
41
|
-
options = maybeOptions ?? {};
|
|
42
|
-
} else {
|
|
43
|
-
selector = '$this';
|
|
44
|
-
options = selectorOrOptions ?? {};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const constructor = targetObj.constructor;
|
|
48
|
-
|
|
49
|
-
let observers = ReflectUtils.getMetadata<MutationObserverMetadata[]>(MUTATION_OBSERVER_METADATA_KEY, constructor);
|
|
50
|
-
if (!observers) {
|
|
51
|
-
observers = [];
|
|
52
|
-
ReflectUtils.defineMetadata(MUTATION_OBSERVER_METADATA_KEY, observers, constructor);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
observers.push({ propertyKey, selector, options });
|
|
56
|
-
};
|
|
90
|
+
export function mutationObserver(selectorOrOptionsOrTarget?: SwcSelector | MutationObserverQueryOptions | Object, maybeOptionsOrPropertyKey?: MutationObserverQueryOptions | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
|
|
91
|
+
return dispatchMutationObserver(selectorOrOptionsOrTarget, maybeOptionsOrPropertyKey, descriptor, {});
|
|
57
92
|
}
|
|
58
93
|
|
|
59
|
-
export function mutationObserverThis<TEvent extends Event = Event>(options?: MutationObserverQueryOptions): MethodDecorator {
|
|
60
|
-
return mutationObserver('$this', options);
|
|
61
|
-
}
|
|
62
94
|
|
|
63
95
|
// ─── root별 delegate 헬퍼 (addEventListener와 동일 패턴) ───
|
|
64
96
|
|
|
65
97
|
export function mutationObserverDelegateLight(selector: string, options?: MutationObserverBaseOptions): MethodDecorator;
|
|
66
|
-
export function mutationObserverDelegateLight(options
|
|
67
|
-
export function mutationObserverDelegateLight(
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
return mutationObserver({...selectorOrOptions ?? {}, root: 'light', delegate: true});
|
|
98
|
+
export function mutationObserverDelegateLight(options: MutationObserverBaseOptions): MethodDecorator;
|
|
99
|
+
export function mutationObserverDelegateLight(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
|
|
100
|
+
export function mutationObserverDelegateLight(selectorOrOptionsOrTarget?: string | Omit<MutationObserverQueryOptions, 'root'> | Object, maybeOptionsOrPropertyKey?: Omit<MutationObserverQueryOptions, 'root'> | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
|
|
101
|
+
return dispatchMutationObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'light', delegate: true });
|
|
72
102
|
}
|
|
73
103
|
|
|
74
104
|
export function mutationObserverDelegateShadow(selector: string, options?: MutationObserverBaseOptions): MethodDecorator;
|
|
75
|
-
export function mutationObserverDelegateShadow(options
|
|
76
|
-
export function mutationObserverDelegateShadow(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
return mutationObserver({...selectorOrOptions ?? {}, root: 'shadow', delegate: true});
|
|
105
|
+
export function mutationObserverDelegateShadow(options: MutationObserverBaseOptions): MethodDecorator;
|
|
106
|
+
export function mutationObserverDelegateShadow(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
|
|
107
|
+
export function mutationObserverDelegateShadow(selectorOrOptionsOrTarget?: string | Omit<MutationObserverQueryOptions, 'root'> | Object, maybeOptionsOrPropertyKey?: Omit<MutationObserverQueryOptions, 'root'> | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
|
|
108
|
+
return dispatchMutationObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'shadow', delegate: true });
|
|
81
109
|
}
|
|
82
110
|
|
|
83
111
|
export function mutationObserverDelegateAll(selector: string, options?: MutationObserverBaseOptions): MethodDecorator;
|
|
84
|
-
export function mutationObserverDelegateAll(options
|
|
85
|
-
export function mutationObserverDelegateAll(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
return mutationObserver({...selectorOrOptions ?? {}, root: 'all', delegate: true});
|
|
112
|
+
export function mutationObserverDelegateAll(options: MutationObserverBaseOptions): MethodDecorator;
|
|
113
|
+
export function mutationObserverDelegateAll(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
|
|
114
|
+
export function mutationObserverDelegateAll(selectorOrOptionsOrTarget?: string | Omit<MutationObserverQueryOptions, 'root'> | Object, maybeOptionsOrPropertyKey?: Omit<MutationObserverQueryOptions, 'root'> | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
|
|
115
|
+
return dispatchMutationObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'all', delegate: true });
|
|
90
116
|
}
|
|
91
117
|
|
|
92
118
|
export function mutationObserverDelegate(selector: string, options?: MutationObserverBaseOptions): MethodDecorator;
|
|
93
|
-
export function mutationObserverDelegate(options
|
|
94
|
-
export function mutationObserverDelegate(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
return mutationObserver({...selectorOrOptions ?? {}, root: 'auto', delegate: true});
|
|
119
|
+
export function mutationObserverDelegate(options: MutationObserverBaseOptions): MethodDecorator;
|
|
120
|
+
export function mutationObserverDelegate(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
|
|
121
|
+
export function mutationObserverDelegate(selectorOrOptionsOrTarget?: string | Omit<MutationObserverQueryOptions, 'root'> | Object, maybeOptionsOrPropertyKey?: Omit<MutationObserverQueryOptions, 'root'> | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
|
|
122
|
+
return dispatchMutationObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'auto', delegate: true });
|
|
99
123
|
}
|
|
100
124
|
|
|
101
125
|
// ─── root별 일반 헬퍼 (delegate 없이, 셀렉터 생략 시 $this) ───
|
|
102
126
|
|
|
103
127
|
export function mutationObserverLight(selector: string, options?: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator;
|
|
104
|
-
export function mutationObserverLight(options
|
|
105
|
-
export function mutationObserverLight(
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
return mutationObserver({...selectorOrOptions ?? {}, root: 'light'});
|
|
128
|
+
export function mutationObserverLight(options: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator;
|
|
129
|
+
export function mutationObserverLight(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
|
|
130
|
+
export function mutationObserverLight(selectorOrOptionsOrTarget?: string | Omit<MutationObserverQueryOptions, 'root'> | Object, maybeOptionsOrPropertyKey?: Omit<MutationObserverQueryOptions, 'root'> | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
|
|
131
|
+
return dispatchMutationObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'light' });
|
|
110
132
|
}
|
|
111
133
|
|
|
112
134
|
export function mutationObserverShadow(selector: string, options?: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator;
|
|
113
|
-
export function mutationObserverShadow(options
|
|
114
|
-
export function mutationObserverShadow(
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
return mutationObserver({...selectorOrOptions ?? {}, root: 'shadow'});
|
|
135
|
+
export function mutationObserverShadow(options: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator;
|
|
136
|
+
export function mutationObserverShadow(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
|
|
137
|
+
export function mutationObserverShadow(selectorOrOptionsOrTarget?: string | Omit<MutationObserverQueryOptions, 'root'> | Object, maybeOptionsOrPropertyKey?: Omit<MutationObserverQueryOptions, 'root'> | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
|
|
138
|
+
return dispatchMutationObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'shadow' });
|
|
119
139
|
}
|
|
120
140
|
|
|
121
141
|
export function mutationObserverAll(selector: string, options?: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator;
|
|
122
|
-
export function mutationObserverAll(options
|
|
123
|
-
export function mutationObserverAll(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
return mutationObserver({...selectorOrOptions ?? {}, root: 'all'});
|
|
142
|
+
export function mutationObserverAll(options: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator;
|
|
143
|
+
export function mutationObserverAll(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
|
|
144
|
+
export function mutationObserverAll(selectorOrOptionsOrTarget?: string | Omit<MutationObserverQueryOptions, 'root'> | Object, maybeOptionsOrPropertyKey?: Omit<MutationObserverQueryOptions, 'root'> | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
|
|
145
|
+
return dispatchMutationObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'all' });
|
|
128
146
|
}
|
|
129
147
|
|
|
130
148
|
export function getMutationObserverMetadata(target: any): MutationObserverMetadata[] | undefined {
|
|
131
|
-
const constructor = target
|
|
132
|
-
return ReflectUtils.
|
|
149
|
+
const constructor = typeof target === 'function' ? target : target.constructor;
|
|
150
|
+
return ReflectUtils.findAllMetadata<any[]>(MUTATION_OBSERVER_METADATA_KEY, constructor).flat();
|
|
133
151
|
}
|
|
134
152
|
|
|
135
153
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -137,20 +155,21 @@ export function getMutationObserverMetadata(target: any): MutationObserverMetada
|
|
|
137
155
|
// observer 를 직접 생성하지 않고 OnConnectedResult 를 반환한다.
|
|
138
156
|
// elementDefine 이 수집된 MutationObserverSet 으로 observer 를 생성한다.
|
|
139
157
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
140
|
-
import { ElementDefineLifeCycler, MutationObserverSet, MutationObserverSetEntry, ObserverObserveTarget, OnConnectedResult } from '../types';
|
|
158
|
+
import { ElementDefineLifeCycler, inObserverScope, MutationObserverSet, MutationObserverSetEntry, ObserverObserveTarget, ObserverScope, OnConnectedResult, ResizeObserverSet } from '../types';
|
|
141
159
|
import { SwcUtils } from '../utils/Utils';
|
|
142
160
|
|
|
143
161
|
export class MutationObserverLifeCycler implements ElementDefineLifeCycler {
|
|
144
162
|
private readonly removeObserverCallbacksMap = new WeakMap<Element, Array<{ fn: (target: Element, opts: unknown) => void; target: any; opts: unknown }>>();
|
|
145
163
|
|
|
146
|
-
onConnected(helperHostSet: HelperHostSet): OnConnectedResult | void {
|
|
164
|
+
onConnected(helperHostSet: HelperHostSet, _set?: ResizeObserverSet, scope?: ObserverScope): OnConnectedResult | void {
|
|
147
165
|
const inst = helperHostSet.$this;
|
|
148
166
|
const currentWin = helperHostSet.$w;
|
|
149
167
|
|
|
150
|
-
|
|
168
|
+
// 'rest' 는 같은 connect 의 'self' 뒤에 오므로 이어 붙이고, 그 외(새 connect)는 새로 시작한다.
|
|
169
|
+
const removeObserverCallbacks = (scope === 'rest' && this.removeObserverCallbacksMap.get(inst)) || [];
|
|
151
170
|
this.removeObserverCallbacksMap.set(inst, removeObserverCallbacks);
|
|
152
171
|
|
|
153
|
-
const allMeta = getMutationObserverMetadata(inst) ?? [];
|
|
172
|
+
const allMeta = (getMutationObserverMetadata(inst) ?? []).filter(m => inObserverScope(m, scope));
|
|
154
173
|
// 처리할 메타가 없으면 observer 불필요
|
|
155
174
|
if (allMeta.length === 0) return;
|
|
156
175
|
|
|
@@ -180,13 +199,19 @@ export class MutationObserverLifeCycler implements ElementDefineLifeCycler {
|
|
|
180
199
|
return init;
|
|
181
200
|
};
|
|
182
201
|
|
|
183
|
-
|
|
202
|
+
// non-delegate 메타별 observe 대상. MO 는 인스턴스당 1개를 모든 메타가 공유하므로(옵션도 합집합),
|
|
203
|
+
// 메타는 자기 대상(subtree 면 그 하위)에서 온 레코드만 받는다.
|
|
204
|
+
const observedNodes = new Map<MutationObserverMetadata, Node[]>();
|
|
205
|
+
const owns = (meta: MutationObserverMetadata, m: MutationRecord): boolean =>
|
|
206
|
+
(observedNodes.get(meta) ?? []).some(o => o === m.target || (!!meta.options.subtree && o.contains(m.target)));
|
|
184
207
|
|
|
185
208
|
const callback = (mutations: MutationRecord[], obs: MutationObserver) => {
|
|
186
209
|
// ── MutationObserver 메타 콜백 ──
|
|
187
210
|
for (const meta of metas) {
|
|
188
211
|
const { selector, options } = meta;
|
|
189
212
|
let matchedEls: HTMLElement[] = [];
|
|
213
|
+
// 핸들러에 넘길 레코드 — non-delegate 는 자기 대상 레코드만 (옵저버는 공유라 배치에 다른 대상 레코드가 섞인다)
|
|
214
|
+
let records = mutations;
|
|
190
215
|
|
|
191
216
|
const typeMatches = (m: MutationRecord): boolean => {
|
|
192
217
|
const has = !!(options.childList || options.attributes || options.characterData);
|
|
@@ -196,8 +221,8 @@ export class MutationObserverLifeCycler implements ElementDefineLifeCycler {
|
|
|
196
221
|
return true;
|
|
197
222
|
};
|
|
198
223
|
|
|
199
|
-
const collect = (matchesSel: (n: any) => boolean) =>
|
|
200
|
-
|
|
224
|
+
const collect = (matchesSel: (n: any) => boolean, records: MutationRecord[] = mutations) =>
|
|
225
|
+
records.flatMap(m => {
|
|
201
226
|
if (!typeMatches(m)) return [];
|
|
202
227
|
const els: HTMLElement[] = [];
|
|
203
228
|
if (matchesSel(m.target)) els.push(m.target as HTMLElement);
|
|
@@ -206,26 +231,27 @@ export class MutationObserverLifeCycler implements ElementDefineLifeCycler {
|
|
|
206
231
|
return els;
|
|
207
232
|
});
|
|
208
233
|
|
|
209
|
-
if (
|
|
210
|
-
|
|
234
|
+
if (typeof selector === 'string' && (selector === '$this' || selector === '')) {
|
|
235
|
+
// 자기 자신을 볼 때는 바뀐/추가된 노드가 아니라 자기 자신 하나 — 해당 종류의 변화가 있었으면 [inst]
|
|
236
|
+
records = mutations.filter(m => typeMatches(m) && owns(meta, m));
|
|
237
|
+
matchedEls = records.length ? [inst as HTMLElement] : [];
|
|
238
|
+
} else if (options.delegate && typeof selector === 'string') {
|
|
211
239
|
matchedEls = collect(n => {
|
|
212
240
|
if (!n || n.nodeType !== 1) return false;
|
|
213
|
-
if (isThis) return true;
|
|
214
241
|
const el = n as HTMLElement;
|
|
215
242
|
return el.matches?.(selector) || !!el.closest?.(selector);
|
|
216
243
|
});
|
|
217
244
|
} else if (typeof selector === 'string') {
|
|
218
|
-
|
|
219
|
-
matchedEls = collect(n => {
|
|
245
|
+
records = mutations.filter(m => owns(meta, m));
|
|
246
|
+
matchedEls = records.length ? collect(n => {
|
|
220
247
|
if (!n || n.nodeType !== 1) return false;
|
|
221
|
-
if (isThis) return true;
|
|
222
248
|
return (n as HTMLElement).matches?.(selector);
|
|
223
|
-
});
|
|
249
|
+
}, records) : [];
|
|
224
250
|
} else if (typeof selector === 'function') {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
.
|
|
251
|
+
// 레코드가 속한 observe 대상 요소 (subtree 면 하위 변경도 그 대상으로 묶는다)
|
|
252
|
+
records = mutations.filter(m => typeMatches(m) && owns(meta, m));
|
|
253
|
+
matchedEls = (observedNodes.get(meta) ?? []).filter(o =>
|
|
254
|
+
records.some(m => o === m.target || (!!options.subtree && o.contains(m.target)))) as HTMLElement[];
|
|
229
255
|
} else {
|
|
230
256
|
matchedEls = mutations.filter(m => typeMatches(m))
|
|
231
257
|
.map(m => m.target as HTMLElement)
|
|
@@ -233,11 +259,24 @@ export class MutationObserverLifeCycler implements ElementDefineLifeCycler {
|
|
|
233
259
|
}
|
|
234
260
|
|
|
235
261
|
if (matchedEls.length === 0) continue;
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
262
|
+
// fire-and-forget async 러너 — filter(async)/before/finally + @mutationObserverBeforeReturn 주입.
|
|
263
|
+
void (async () => {
|
|
264
|
+
const helper = SwcUtils.getHelperAndHostSet(inst);
|
|
265
|
+
if (options.filter && !(await options.filter(matchedEls, { currentThis: inst, helper }))) return;
|
|
266
|
+
const hostSet = SwcUtils.getHostSet(inst);
|
|
267
|
+
const helperSet = SwcUtils.getHelperSet(helperHostSet.$w);
|
|
268
|
+
const legacyArgs = [matchedEls, records, obs, { ...hostSet, $root: root }];
|
|
269
|
+
const buildArgs = (beforeReturn: any) => buildSwcParameterArgs(inst, meta.propertyKey, {
|
|
270
|
+
hostSet, helperHostSet: helper, helperSet, mutationObserverBeforeReturn: beforeReturn
|
|
271
|
+
}, [...legacyArgs, beforeReturn]);
|
|
272
|
+
let args = buildArgs(undefined);
|
|
273
|
+
if (options.before) { const br = await options.before(matchedEls, { currentThis: inst, helper }); args = buildArgs(br); }
|
|
274
|
+
let result: any, error: any;
|
|
275
|
+
try { result = await inst[meta.propertyKey](...args); }
|
|
276
|
+
catch (e) { error = e; }
|
|
277
|
+
finally { if (options.finally) await options.finally(matchedEls, { currentThis: inst, helper }, { args, result, error }); }
|
|
278
|
+
if (error) throw error;
|
|
279
|
+
})().catch(e => console.error('[SWC] mutationObserver handler error:', e));
|
|
241
280
|
}
|
|
242
281
|
|
|
243
282
|
};
|
|
@@ -255,20 +294,17 @@ export class MutationObserverLifeCycler implements ElementDefineLifeCycler {
|
|
|
255
294
|
const { selector, options } = m;
|
|
256
295
|
const mInit = initFrom(options);
|
|
257
296
|
if (typeof selector === 'string') {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
root.querySelectorAll(selector).forEach(el => observeTargets.push({ target: el as Element, options: mInit }));
|
|
262
|
-
}
|
|
297
|
+
const nodes: Node[] = selector === '$this' || selector === '' ? [root] : Array.from(root.querySelectorAll(selector));
|
|
298
|
+
for (const n of nodes) observeTargets.push({ target: n as Element, options: mInit });
|
|
299
|
+
observedNodes.set(m, nodes);
|
|
263
300
|
} else if (typeof selector === 'function') {
|
|
264
301
|
const res = (selector as any)(inst, helperHostSet);
|
|
265
302
|
let targets: HTMLElement[] = [];
|
|
266
303
|
if (res instanceof currentWin.HTMLElement) targets = [res as HTMLElement];
|
|
267
304
|
else if (res instanceof currentWin.NodeList) targets = Array.from(res as NodeList).filter((e: any) => e instanceof currentWin.HTMLElement) as HTMLElement[];
|
|
268
305
|
else if (Array.isArray(res)) targets = res.filter((e: any) => e instanceof currentWin.HTMLElement) as HTMLElement[];
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
fnObservedSets.set(m, set);
|
|
306
|
+
for (const el of targets) observeTargets.push({ target: el, options: mInit });
|
|
307
|
+
observedNodes.set(m, targets);
|
|
272
308
|
}
|
|
273
309
|
}
|
|
274
310
|
|
|
@@ -301,4 +337,4 @@ export class MutationObserverLifeCycler implements ElementDefineLifeCycler {
|
|
|
301
337
|
}
|
|
302
338
|
this.removeObserverCallbacksMap.delete(inst);
|
|
303
339
|
}
|
|
304
|
-
}
|
|
340
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { ReflectUtils } from '@dooboostore/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @eventObject/@matchedElement/@hostSet/@helperHostSet/@helperSet/@swcAppRouterEvent/@appMessage/@eventBeforeReturn —
|
|
5
|
+
* @event/lifecycle/subscribeSwcAppRouteChange/subscribeSwcAppMessage
|
|
6
|
+
* 계열 핸들러의 파라미터를 순서 무관하게 선언할 수 있게 해주는 파라미터 데코레이터.
|
|
7
|
+
* @dooboostore/simple-boot의 @Inject와 동일한 인덱스 기반 메타데이터 패턴을 따른다:
|
|
8
|
+
* 데코레이터가 실행되는 순서가 아니라 실제 parameterIndex로 슬롯을 매칭하므로,
|
|
9
|
+
* 사용자가 파라미터 선언 순서를 자유롭게 바꿔도 된다.
|
|
10
|
+
*/
|
|
11
|
+
export type SwcParamKind = 'eventObject' | 'matchedElement' | 'hostSet' | 'helperHostSet' | 'helperSet' | 'swcAppRouterEvent' | 'appMessage' | 'eventBeforeReturn' | 'appMessageBeforeReturn' | 'routeChangeBeforeReturn' | 'eventMediaBeforeReturn' | 'mutationObserverBeforeReturn' | 'intersectionObserverBeforeReturn' | 'resizeObserverBeforeReturn' | 'changedAttributeBeforeReturn' | 'setTimeoutBeforeReturn' | 'setIntervalBeforeReturn' | 'fetchSettled'
|
|
12
|
+
| SwcRouteParamKind;
|
|
13
|
+
|
|
14
|
+
/** 라우트 핸들러 전용 (subscribeSwcAppRouteChange 가 채움). kind 이름 = 데코레이터 이름 */
|
|
15
|
+
export type SwcRouteParamKind =
|
|
16
|
+
| 'swcAppRouteQueryParam' | 'swcAppRouteFirstQueryParam' | 'swcAppRouteLastQueryParam' | 'swcAppRouteQueryParams'
|
|
17
|
+
| 'swcAppRouteQueryParamObject' | 'swcAppRouteFirstQueryParamObject' | 'swcAppRouteLastQueryParamObject' | 'swcAppRouteQueryParamsObject'
|
|
18
|
+
| 'swcAppRouteURLSearchParams'
|
|
19
|
+
| 'swcAppRoutePathVariable' | 'swcAppRouteFirstPathVariable' | 'swcAppRouteLastPathVariable' | 'swcAppRoutePathVariables'
|
|
20
|
+
| 'swcAppRoutePathVariableObject' | 'swcAppRouteFirstPathVariableObject' | 'swcAppRouteLastPathVariableObject' | 'swcAppRoutePathVariablesObject';
|
|
21
|
+
|
|
22
|
+
const SWC_PARAMETER_METADATA_KEY = Symbol.for('simple-web-component:parameter');
|
|
23
|
+
|
|
24
|
+
/** key: @swcAppRouteQueryParam('q') 처럼 키를 받는 파라미터 데코레이터의 키 */
|
|
25
|
+
type SaveParamConfig = { index: number; kind: SwcParamKind; key?: string };
|
|
26
|
+
|
|
27
|
+
const registerParam = (kind: SwcParamKind, target: Object, propertyKey: string | symbol | undefined, parameterIndex: number, key?: string) => {
|
|
28
|
+
if (!propertyKey) return;
|
|
29
|
+
const constructor = target.constructor;
|
|
30
|
+
const saves = (ReflectUtils.getOwnMetadata(SWC_PARAMETER_METADATA_KEY, constructor, propertyKey) ?? []) as SaveParamConfig[];
|
|
31
|
+
saves.push(key === undefined ? { index: parameterIndex, kind } : { index: parameterIndex, kind, key });
|
|
32
|
+
ReflectUtils.defineMetadata(SWC_PARAMETER_METADATA_KEY, saves, constructor, propertyKey);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/** 이벤트 핸들러의 원본 Event 객체를 주입한다. */
|
|
36
|
+
export function eventObject(target: Object, propertyKey: string | symbol, parameterIndex: number): void {
|
|
37
|
+
registerParam('eventObject', target, propertyKey, parameterIndex);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** delegate로 매칭된 실제 엘리먼트($matchedElement)를 주입한다. */
|
|
41
|
+
export function matchedElement(target: Object, propertyKey: string | symbol, parameterIndex: number): void {
|
|
42
|
+
registerParam('matchedElement', target, propertyKey, parameterIndex);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** HostSet(호스트 트리 정보 — $host/$hosts/$firstHost/$appHost 등)을 주입한다. */
|
|
46
|
+
export function hostSet(target: Object, propertyKey: string | symbol, parameterIndex: number): void {
|
|
47
|
+
registerParam('hostSet', target, propertyKey, parameterIndex);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** HelperHostSet(HelperSet + HostSet + $this 전체 묶음)을 주입한다. */
|
|
51
|
+
export function helperHostSet(target: Object, propertyKey: string | symbol, parameterIndex: number): void {
|
|
52
|
+
registerParam('helperHostSet', target, propertyKey, parameterIndex);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** HelperSet($d/$w/$q/$qa/$qi 등 순수 DOM/window 헬퍼, 호스트 트리 정보 없음)을 주입한다. */
|
|
56
|
+
export function helperSet(target: Object, propertyKey: string | symbol, parameterIndex: number): void {
|
|
57
|
+
registerParam('helperSet', target, propertyKey, parameterIndex);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** @subscribeSwcAppRouteChange 핸들러의 라우트 변경 이벤트({...RouterEventType, pathData})를 주입한다. */
|
|
61
|
+
export function swcAppRouterEvent(target: Object, propertyKey: string | symbol, parameterIndex: number): void {
|
|
62
|
+
registerParam('swcAppRouterEvent', target, propertyKey, parameterIndex);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** @subscribeSwcAppMessage 핸들러의 SwcAppMessage 페이로드를 주입한다. */
|
|
66
|
+
export function appMessage(target: Object, propertyKey: string | symbol, parameterIndex: number): void {
|
|
67
|
+
registerParam('appMessage', target, propertyKey, parameterIndex);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @event 계열의 before 훅이 이번 호출에 리턴한 값을 주입한다.
|
|
72
|
+
* (before에서 async로 준비한 데이터를 핸들러가 받는 용도. before 없으면 undefined)
|
|
73
|
+
* 예: @eventClick({ before: () => loadUser() }) onClick(@eventBeforeReturn user) { ... }
|
|
74
|
+
*/
|
|
75
|
+
export function eventBeforeReturn(target: Object, propertyKey: string | symbol, parameterIndex: number): void {
|
|
76
|
+
registerParam('eventBeforeReturn', target, propertyKey, parameterIndex);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @subscribeSwcAppMessage 의 before 훅이 이번 호출에 리턴한 값을 주입한다.
|
|
81
|
+
* (before에서 async로 준비한 데이터를 핸들러가 받는 용도. 없으면 undefined)
|
|
82
|
+
* 예: onMsg(@appMessage m, @appMessageBeforeReturn prepared) { ... }
|
|
83
|
+
*/
|
|
84
|
+
export function appMessageBeforeReturn(target: Object, propertyKey: string | symbol, parameterIndex: number): void {
|
|
85
|
+
registerParam('appMessageBeforeReturn', target, propertyKey, parameterIndex);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* @subscribeSwcAppRouteChange 의 before 훅이 이번 호출에 리턴한 값을 주입한다.
|
|
90
|
+
* (before에서 async 가드/준비한 데이터를 핸들러가 받는 용도. 없으면 undefined)
|
|
91
|
+
* 예: routeChanged(@swcAppRouterEvent e, @routeChangeBeforeReturn guard) { ... }
|
|
92
|
+
*/
|
|
93
|
+
export function routeChangeBeforeReturn(target: Object, propertyKey: string | symbol, parameterIndex: number): void {
|
|
94
|
+
registerParam('routeChangeBeforeReturn', target, propertyKey, parameterIndex);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @eventMedia 의 before 훅이 이번 호출에 리턴한 값을 주입한다. (before 없으면 undefined)
|
|
99
|
+
* 예: @eventMediaChange('(max-width:600px)', { before: () => ... }) onMobile(@eventMediaBeforeReturn v) { ... }
|
|
100
|
+
*/
|
|
101
|
+
export function eventMediaBeforeReturn(target: Object, propertyKey: string | symbol, parameterIndex: number): void {
|
|
102
|
+
registerParam('eventMediaBeforeReturn', target, propertyKey, parameterIndex);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** @mutationObserver 의 before 훅이 이번 호출에 리턴한 값을 주입한다. (before 없으면 undefined) */
|
|
106
|
+
export function mutationObserverBeforeReturn(target: Object, propertyKey: string | symbol, parameterIndex: number): void {
|
|
107
|
+
registerParam('mutationObserverBeforeReturn', target, propertyKey, parameterIndex);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** @intersectionObserver 의 before 훅이 이번 호출에 리턴한 값을 주입한다. (before 없으면 undefined) */
|
|
111
|
+
export function intersectionObserverBeforeReturn(target: Object, propertyKey: string | symbol, parameterIndex: number): void {
|
|
112
|
+
registerParam('intersectionObserverBeforeReturn', target, propertyKey, parameterIndex);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** @resizeObserver 의 before 훅이 이번 호출에 리턴한 값을 주입한다. (before 없으면 undefined) */
|
|
116
|
+
export function resizeObserverBeforeReturn(target: Object, propertyKey: string | symbol, parameterIndex: number): void {
|
|
117
|
+
registerParam('resizeObserverBeforeReturn', target, propertyKey, parameterIndex);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** @changedAttribute 의 before 훅이 이번 호출에 리턴한 값을 주입한다. (before 없으면 undefined) */
|
|
121
|
+
export function changedAttributeBeforeReturn(target: Object, propertyKey: string | symbol, parameterIndex: number): void {
|
|
122
|
+
registerParam('changedAttributeBeforeReturn', target, propertyKey, parameterIndex);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** @setTimeout(type:'onConnected') 의 before 훅이 이번 호출에 리턴한 값을 주입한다. (before 없으면 undefined) */
|
|
126
|
+
export function setTimeoutBeforeReturn(target: Object, propertyKey: string | symbol, parameterIndex: number): void {
|
|
127
|
+
registerParam('setTimeoutBeforeReturn', target, propertyKey, parameterIndex);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** @setInterval(type:'onConnected') 의 before 훅이 이번 호출에 리턴한 값을 주입한다. (before 없으면 undefined) */
|
|
131
|
+
export function setIntervalBeforeReturn(target: Object, propertyKey: string | symbol, parameterIndex: number): void {
|
|
132
|
+
registerParam('setIntervalBeforeReturn', target, propertyKey, parameterIndex);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* @fetch(trigger:'before') 의 fetch settled 결과(PromiseSettledResult)를 주입한다.
|
|
137
|
+
* 예: save(@fetchSettled settled) { ... }
|
|
138
|
+
*/
|
|
139
|
+
export function fetchSettled(target: Object, propertyKey: string | symbol, parameterIndex: number): void {
|
|
140
|
+
registerParam('fetchSettled', target, propertyKey, parameterIndex);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export const getParameterMetadata = (target: any, propertyKey: string | symbol): SaveParamConfig[] => {
|
|
144
|
+
const constructor = typeof target === 'function' ? target : target.constructor;
|
|
145
|
+
return ReflectUtils.getMetadata(SWC_PARAMETER_METADATA_KEY, constructor, propertyKey) ?? [];
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* 위 파라미터 데코레이터 메타데이터가 하나라도 있으면 kind별 값을 index 순서에 맞게
|
|
150
|
+
* 배열로 조립하고, 하나도 없으면 기존 위치 인자(legacyArgs)를 그대로 반환한다 — 완전 하위호환.
|
|
151
|
+
*/
|
|
152
|
+
export const buildSwcParameterArgs = (
|
|
153
|
+
target: any,
|
|
154
|
+
propertyKey: string | symbol,
|
|
155
|
+
kindValues: Partial<Record<SwcParamKind, any>>,
|
|
156
|
+
legacyArgs: any[]
|
|
157
|
+
): any[] => {
|
|
158
|
+
const saves = getParameterMetadata(target, propertyKey);
|
|
159
|
+
if (saves.length === 0) return legacyArgs;
|
|
160
|
+
const maxIndex = Math.max(...saves.map(s => s.index));
|
|
161
|
+
const args: any[] = new Array(maxIndex + 1);
|
|
162
|
+
for (const s of saves) {
|
|
163
|
+
const value = kindValues[s.kind];
|
|
164
|
+
// 키를 받는 kind 는 kindValues 에 (key) => 값 resolver 가 들어 있다
|
|
165
|
+
args[s.index] = s.key !== undefined && typeof value === 'function' ? value(s.key) : value;
|
|
166
|
+
}
|
|
167
|
+
return args;
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
// ─── 라우트 파라미터 (@subscribeSwcAppRouteChange 핸들러) ───
|
|
171
|
+
// 규칙: 접두어 없음 = First, First/Last = 같은 키가 여러 번일 때 첫/마지막 값, 복수형 = 모든 값 배열.
|
|
172
|
+
|
|
173
|
+
const keyedRouteParam = (kind: SwcRouteParamKind) => (key: string): ParameterDecorator =>
|
|
174
|
+
(target, propertyKey, parameterIndex) => registerParam(kind, target, propertyKey, parameterIndex, key);
|
|
175
|
+
const routeParam = (kind: SwcRouteParamKind): ParameterDecorator =>
|
|
176
|
+
(target, propertyKey, parameterIndex) => registerParam(kind, target, propertyKey, parameterIndex);
|
|
177
|
+
|
|
178
|
+
/** ?tag=a&tag=b → @swcAppRouteQueryParam('tag') = 'a' (없으면 null) */
|
|
179
|
+
export const swcAppRouteQueryParam = keyedRouteParam('swcAppRouteQueryParam');
|
|
180
|
+
/** = swcAppRouteQueryParam */
|
|
181
|
+
export const swcAppRouteFirstQueryParam = keyedRouteParam('swcAppRouteFirstQueryParam');
|
|
182
|
+
/** ?tag=a&tag=b → 'b' */
|
|
183
|
+
export const swcAppRouteLastQueryParam = keyedRouteParam('swcAppRouteLastQueryParam');
|
|
184
|
+
/** ?tag=a&tag=b → ['a', 'b'] */
|
|
185
|
+
export const swcAppRouteQueryParams = keyedRouteParam('swcAppRouteQueryParams');
|
|
186
|
+
/** ?tag=a&tag=b → { tag: 'a' } */
|
|
187
|
+
export const swcAppRouteQueryParamObject = routeParam('swcAppRouteQueryParamObject');
|
|
188
|
+
/** = swcAppRouteQueryParamObject */
|
|
189
|
+
export const swcAppRouteFirstQueryParamObject = routeParam('swcAppRouteFirstQueryParamObject');
|
|
190
|
+
/** ?tag=a&tag=b → { tag: 'b' } */
|
|
191
|
+
export const swcAppRouteLastQueryParamObject = routeParam('swcAppRouteLastQueryParamObject');
|
|
192
|
+
/** ?tag=a&tag=b → { tag: ['a', 'b'] } */
|
|
193
|
+
export const swcAppRouteQueryParamsObject = routeParam('swcAppRouteQueryParamsObject');
|
|
194
|
+
/** URLSearchParams 그대로 */
|
|
195
|
+
export const swcAppRouteURLSearchParams = routeParam('swcAppRouteURLSearchParams');
|
|
196
|
+
|
|
197
|
+
/** '/a/{id}/b/{id}' ← '/a/1/b/2' → @swcAppRoutePathVariable('id') = '1' */
|
|
198
|
+
export const swcAppRoutePathVariable = keyedRouteParam('swcAppRoutePathVariable');
|
|
199
|
+
/** = swcAppRoutePathVariable */
|
|
200
|
+
export const swcAppRouteFirstPathVariable = keyedRouteParam('swcAppRouteFirstPathVariable');
|
|
201
|
+
/** → '2' */
|
|
202
|
+
export const swcAppRouteLastPathVariable = keyedRouteParam('swcAppRouteLastPathVariable');
|
|
203
|
+
/** → ['1', '2'] */
|
|
204
|
+
export const swcAppRoutePathVariables = keyedRouteParam('swcAppRoutePathVariables');
|
|
205
|
+
/** → { id: '1' } */
|
|
206
|
+
export const swcAppRoutePathVariableObject = routeParam('swcAppRoutePathVariableObject');
|
|
207
|
+
/** = swcAppRoutePathVariableObject */
|
|
208
|
+
export const swcAppRouteFirstPathVariableObject = routeParam('swcAppRouteFirstPathVariableObject');
|
|
209
|
+
/** → { id: '2' } */
|
|
210
|
+
export const swcAppRouteLastPathVariableObject = routeParam('swcAppRouteLastPathVariableObject');
|
|
211
|
+
/** → { id: ['1', '2'] } */
|
|
212
|
+
export const swcAppRoutePathVariablesObject = routeParam('swcAppRoutePathVariablesObject');
|
|
@@ -100,7 +100,6 @@ function createPublishSwcAppMessage(messageType?: string, options?: PublishSwcAp
|
|
|
100
100
|
// 오버로드 시그니처 - 직접 사용 (괄호 없음)
|
|
101
101
|
export function publishSwcAppMessage(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
|
|
102
102
|
// 오버로드 시그니처 - 함수 호출 (괄호 있음)
|
|
103
|
-
export function publishSwcAppMessage(): MethodDecorator;
|
|
104
103
|
export function publishSwcAppMessage(messageType: string): MethodDecorator;
|
|
105
104
|
export function publishSwcAppMessage(messageType: string, options: PublishSwcAppMessageOptions): MethodDecorator;
|
|
106
105
|
export function publishSwcAppMessage(options: PublishSwcAppMessageOptions): MethodDecorator;
|
|
@@ -114,7 +113,7 @@ export function publishSwcAppMessage(targetOrMessageTypeOrOptions?: any, propert
|
|
|
114
113
|
return createPublishSwcAppMessage()(target, propertyKeyOrOptions, descriptor);
|
|
115
114
|
}
|
|
116
115
|
|
|
117
|
-
// 함수로 호출된 경우 (
|
|
116
|
+
// 함수로 호출된 경우 (인자 있음): @publishSwcAppMessage('messageType') / @publishSwcAppMessage({...})
|
|
118
117
|
let messageType: string | undefined;
|
|
119
118
|
let options: PublishSwcAppMessageOptions | undefined;
|
|
120
119
|
|
|
@@ -138,6 +137,6 @@ export const publishMessage = publishSwcAppMessage;
|
|
|
138
137
|
|
|
139
138
|
// Helper function to retrieve publish message metadata
|
|
140
139
|
export const getPublishSwcAppMessageMetadata = (target: any): PublishSwcAppMessageMetadata[] | undefined => {
|
|
141
|
-
const constructor = target
|
|
142
|
-
return ReflectUtils.
|
|
140
|
+
const constructor = typeof target === 'function' ? target : target.constructor;
|
|
141
|
+
return ReflectUtils.findAllMetadata<any[]>(PUBLISH_SWC_APP_MESSAGE_METADATA_KEY, constructor).flat();
|
|
143
142
|
};
|