@dooboostore/simple-web-component 1.0.50 → 1.0.52

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.
Files changed (241) hide show
  1. package/README.md +735 -354
  2. package/dist/cjs/SwcAppEngine.js.map +2 -2
  3. package/dist/cjs/decorators/addEventListener.js +64 -146
  4. package/dist/cjs/decorators/addEventListener.js.map +2 -2
  5. package/dist/cjs/decorators/applyAttribute.js +36 -48
  6. package/dist/cjs/decorators/applyAttribute.js.map +2 -2
  7. package/dist/cjs/decorators/applyClass.js +9 -12
  8. package/dist/cjs/decorators/applyClass.js.map +2 -2
  9. package/dist/cjs/decorators/applyNode.js +14 -22
  10. package/dist/cjs/decorators/applyNode.js.map +2 -2
  11. package/dist/cjs/decorators/applyProperty.js +12 -42
  12. package/dist/cjs/decorators/applyProperty.js.map +2 -2
  13. package/dist/cjs/decorators/applySlot.js +3 -3
  14. package/dist/cjs/decorators/applySlot.js.map +2 -2
  15. package/dist/cjs/decorators/applyStyle.js +9 -12
  16. package/dist/cjs/decorators/applyStyle.js.map +2 -2
  17. package/dist/cjs/decorators/around.js +124 -0
  18. package/dist/cjs/decorators/around.js.map +7 -0
  19. package/dist/cjs/decorators/changedAttribute.js +40 -12
  20. package/dist/cjs/decorators/changedAttribute.js.map +2 -2
  21. package/dist/cjs/decorators/elementDefine.js +224 -195
  22. package/dist/cjs/decorators/elementDefine.js.map +3 -3
  23. package/dist/cjs/decorators/emitCustomEvent.js +14 -12
  24. package/dist/cjs/decorators/emitCustomEvent.js.map +2 -2
  25. package/dist/cjs/decorators/eventMedia.js +36 -8
  26. package/dist/cjs/decorators/eventMedia.js.map +2 -2
  27. package/dist/cjs/decorators/fetch.js +278 -0
  28. package/dist/cjs/decorators/fetch.js.map +7 -0
  29. package/dist/cjs/decorators/index.js +5 -2
  30. package/dist/cjs/decorators/index.js.map +2 -2
  31. package/dist/cjs/decorators/intersectionObserver.js +33 -13
  32. package/dist/cjs/decorators/intersectionObserver.js.map +2 -2
  33. package/dist/cjs/decorators/lifecycles.js +11 -11
  34. package/dist/cjs/decorators/lifecycles.js.map +2 -2
  35. package/dist/cjs/decorators/mutationObserver.js +55 -39
  36. package/dist/cjs/decorators/mutationObserver.js.map +3 -3
  37. package/dist/cjs/decorators/parameter.js +92 -9
  38. package/dist/cjs/decorators/parameter.js.map +2 -2
  39. package/dist/cjs/decorators/publishSwcAppMessage.js +2 -2
  40. package/dist/cjs/decorators/publishSwcAppMessage.js.map +2 -2
  41. package/dist/cjs/decorators/query.js +11 -5
  42. package/dist/cjs/decorators/query.js.map +2 -2
  43. package/dist/cjs/decorators/requestAnimationFrame.js +7 -16
  44. package/dist/cjs/decorators/requestAnimationFrame.js.map +2 -2
  45. package/dist/cjs/decorators/resizeObserver.js +41 -17
  46. package/dist/cjs/decorators/resizeObserver.js.map +3 -3
  47. package/dist/cjs/decorators/setInterval.js +36 -25
  48. package/dist/cjs/decorators/setInterval.js.map +2 -2
  49. package/dist/cjs/decorators/setTimeout.js +36 -25
  50. package/dist/cjs/decorators/setTimeout.js.map +2 -2
  51. package/dist/cjs/decorators/state.js +13 -10
  52. package/dist/cjs/decorators/state.js.map +2 -2
  53. package/dist/cjs/decorators/{subscribeSwcAppMessageWhileConnected.js → subscribeSwcAppMessage.js} +20 -21
  54. package/dist/cjs/decorators/subscribeSwcAppMessage.js.map +7 -0
  55. package/dist/cjs/decorators/{subscribeSwcAppRouteChangeWhileConnected.js → subscribeSwcAppRouteChange.js} +23 -19
  56. package/dist/cjs/decorators/subscribeSwcAppRouteChange.js.map +7 -0
  57. package/dist/cjs/decorators/swcAppRoute.js +149 -0
  58. package/dist/cjs/decorators/swcAppRoute.js.map +7 -0
  59. package/dist/cjs/elements/SwcApp.js +70 -0
  60. package/dist/cjs/elements/SwcApp.js.map +2 -2
  61. package/dist/cjs/elements/SwcAppMixin.js +262 -83
  62. package/dist/cjs/elements/SwcAppMixin.js.map +3 -3
  63. package/dist/cjs/types/index.js +5 -1
  64. package/dist/cjs/types/index.js.map +2 -2
  65. package/dist/cjs/utils/Utils.js +36 -15
  66. package/dist/cjs/utils/Utils.js.map +2 -2
  67. package/dist/esm/SwcAppEngine.js.map +2 -2
  68. package/dist/esm/decorators/addEventListener.js +64 -146
  69. package/dist/esm/decorators/addEventListener.js.map +2 -2
  70. package/dist/esm/decorators/applyAttribute.js +36 -48
  71. package/dist/esm/decorators/applyAttribute.js.map +2 -2
  72. package/dist/esm/decorators/applyClass.js +9 -12
  73. package/dist/esm/decorators/applyClass.js.map +2 -2
  74. package/dist/esm/decorators/applyNode.js +15 -23
  75. package/dist/esm/decorators/applyNode.js.map +2 -2
  76. package/dist/esm/decorators/applyProperty.js +12 -42
  77. package/dist/esm/decorators/applyProperty.js.map +2 -2
  78. package/dist/esm/decorators/applySlot.js +3 -3
  79. package/dist/esm/decorators/applySlot.js.map +2 -2
  80. package/dist/esm/decorators/applyStyle.js +9 -12
  81. package/dist/esm/decorators/applyStyle.js.map +2 -2
  82. package/dist/esm/decorators/around.js +105 -0
  83. package/dist/esm/decorators/around.js.map +7 -0
  84. package/dist/esm/decorators/changedAttribute.js +40 -12
  85. package/dist/esm/decorators/changedAttribute.js.map +2 -2
  86. package/dist/esm/decorators/elementDefine.js +222 -193
  87. package/dist/esm/decorators/elementDefine.js.map +3 -3
  88. package/dist/esm/decorators/emitCustomEvent.js +15 -13
  89. package/dist/esm/decorators/emitCustomEvent.js.map +2 -2
  90. package/dist/esm/decorators/eventMedia.js +36 -8
  91. package/dist/esm/decorators/eventMedia.js.map +2 -2
  92. package/dist/esm/decorators/fetch.js +259 -0
  93. package/dist/esm/decorators/fetch.js.map +7 -0
  94. package/dist/esm/decorators/index.js +5 -2
  95. package/dist/esm/decorators/index.js.map +2 -2
  96. package/dist/esm/decorators/intersectionObserver.js +33 -13
  97. package/dist/esm/decorators/intersectionObserver.js.map +2 -2
  98. package/dist/esm/decorators/lifecycles.js +11 -11
  99. package/dist/esm/decorators/lifecycles.js.map +2 -2
  100. package/dist/esm/decorators/mutationObserver.js +55 -39
  101. package/dist/esm/decorators/mutationObserver.js.map +3 -3
  102. package/dist/esm/decorators/parameter.js +92 -9
  103. package/dist/esm/decorators/parameter.js.map +2 -2
  104. package/dist/esm/decorators/publishSwcAppMessage.js +2 -2
  105. package/dist/esm/decorators/publishSwcAppMessage.js.map +2 -2
  106. package/dist/esm/decorators/query.js +11 -5
  107. package/dist/esm/decorators/query.js.map +2 -2
  108. package/dist/esm/decorators/requestAnimationFrame.js +8 -17
  109. package/dist/esm/decorators/requestAnimationFrame.js.map +2 -2
  110. package/dist/esm/decorators/resizeObserver.js +41 -17
  111. package/dist/esm/decorators/resizeObserver.js.map +2 -2
  112. package/dist/esm/decorators/setInterval.js +37 -26
  113. package/dist/esm/decorators/setInterval.js.map +2 -2
  114. package/dist/esm/decorators/setTimeout.js +37 -26
  115. package/dist/esm/decorators/setTimeout.js.map +2 -2
  116. package/dist/esm/decorators/state.js +13 -10
  117. package/dist/esm/decorators/state.js.map +2 -2
  118. package/dist/esm/decorators/subscribeSwcAppMessage.js +53 -0
  119. package/dist/esm/decorators/subscribeSwcAppMessage.js.map +7 -0
  120. package/dist/esm/decorators/{subscribeSwcAppRouteChangeWhileConnected.js → subscribeSwcAppRouteChange.js} +20 -16
  121. package/dist/esm/decorators/subscribeSwcAppRouteChange.js.map +7 -0
  122. package/dist/esm/decorators/swcAppRoute.js +130 -0
  123. package/dist/esm/decorators/swcAppRoute.js.map +7 -0
  124. package/dist/esm/elements/SwcApp.js +70 -0
  125. package/dist/esm/elements/SwcApp.js.map +2 -2
  126. package/dist/esm/elements/SwcAppMixin.js +264 -85
  127. package/dist/esm/elements/SwcAppMixin.js.map +3 -3
  128. package/dist/esm/types/index.js +5 -1
  129. package/dist/esm/types/index.js.map +2 -2
  130. package/dist/esm/utils/Utils.js +36 -15
  131. package/dist/esm/utils/Utils.js.map +2 -2
  132. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +1893 -1000
  133. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
  134. package/dist/types/SwcAppEngine.d.ts +1 -0
  135. package/dist/types/SwcAppEngine.d.ts.map +1 -1
  136. package/dist/types/decorators/addEventListener.d.ts +923 -960
  137. package/dist/types/decorators/addEventListener.d.ts.map +1 -1
  138. package/dist/types/decorators/applyAttribute.d.ts +26 -38
  139. package/dist/types/decorators/applyAttribute.d.ts.map +1 -1
  140. package/dist/types/decorators/applyClass.d.ts +1 -3
  141. package/dist/types/decorators/applyClass.d.ts.map +1 -1
  142. package/dist/types/decorators/applyNode.d.ts +15 -17
  143. package/dist/types/decorators/applyNode.d.ts.map +1 -1
  144. package/dist/types/decorators/applyProperty.d.ts +25 -45
  145. package/dist/types/decorators/applyProperty.d.ts.map +1 -1
  146. package/dist/types/decorators/applyStyle.d.ts +1 -3
  147. package/dist/types/decorators/applyStyle.d.ts.map +1 -1
  148. package/dist/types/decorators/around.d.ts +87 -0
  149. package/dist/types/decorators/around.d.ts.map +1 -0
  150. package/dist/types/decorators/changedAttribute.d.ts +21 -1
  151. package/dist/types/decorators/changedAttribute.d.ts.map +1 -1
  152. package/dist/types/decorators/elementDefine.d.ts.map +1 -1
  153. package/dist/types/decorators/emitCustomEvent.d.ts +0 -1
  154. package/dist/types/decorators/emitCustomEvent.d.ts.map +1 -1
  155. package/dist/types/decorators/eventMedia.d.ts +24 -1
  156. package/dist/types/decorators/eventMedia.d.ts.map +1 -1
  157. package/dist/types/decorators/fetch.d.ts +139 -0
  158. package/dist/types/decorators/fetch.d.ts.map +1 -0
  159. package/dist/types/decorators/index.d.ts +5 -2
  160. package/dist/types/decorators/index.d.ts.map +1 -1
  161. package/dist/types/decorators/intersectionObserver.d.ts +24 -11
  162. package/dist/types/decorators/intersectionObserver.d.ts.map +1 -1
  163. package/dist/types/decorators/lifecycles.d.ts +8 -7
  164. package/dist/types/decorators/lifecycles.d.ts.map +1 -1
  165. package/dist/types/decorators/mutationObserver.d.ts +26 -13
  166. package/dist/types/decorators/mutationObserver.d.ts.map +1 -1
  167. package/dist/types/decorators/parameter.d.ts +84 -6
  168. package/dist/types/decorators/parameter.d.ts.map +1 -1
  169. package/dist/types/decorators/publishSwcAppMessage.d.ts +0 -1
  170. package/dist/types/decorators/publishSwcAppMessage.d.ts.map +1 -1
  171. package/dist/types/decorators/query.d.ts +7 -7
  172. package/dist/types/decorators/query.d.ts.map +1 -1
  173. package/dist/types/decorators/requestAnimationFrame.d.ts +1 -1
  174. package/dist/types/decorators/requestAnimationFrame.d.ts.map +1 -1
  175. package/dist/types/decorators/resizeObserver.d.ts +26 -13
  176. package/dist/types/decorators/resizeObserver.d.ts.map +1 -1
  177. package/dist/types/decorators/setInterval.d.ts +10 -0
  178. package/dist/types/decorators/setInterval.d.ts.map +1 -1
  179. package/dist/types/decorators/setTimeout.d.ts +10 -0
  180. package/dist/types/decorators/setTimeout.d.ts.map +1 -1
  181. package/dist/types/decorators/state.d.ts.map +1 -1
  182. package/dist/types/decorators/subscribeSwcAppMessage.d.ts +44 -0
  183. package/dist/types/decorators/subscribeSwcAppMessage.d.ts.map +1 -0
  184. package/dist/types/decorators/subscribeSwcAppRouteChange.d.ts +60 -0
  185. package/dist/types/decorators/subscribeSwcAppRouteChange.d.ts.map +1 -0
  186. package/dist/types/decorators/swcAppRoute.d.ts +94 -0
  187. package/dist/types/decorators/swcAppRoute.d.ts.map +1 -0
  188. package/dist/types/elements/SwcApp.d.ts.map +1 -1
  189. package/dist/types/elements/SwcAppMixin.d.ts +423 -388
  190. package/dist/types/elements/SwcAppMixin.d.ts.map +1 -1
  191. package/dist/types/types/index.d.ts +43 -4
  192. package/dist/types/types/index.d.ts.map +1 -1
  193. package/dist/types/utils/Utils.d.ts +15 -5
  194. package/dist/types/utils/Utils.d.ts.map +1 -1
  195. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +1893 -1000
  196. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
  197. package/package.json +8 -6
  198. package/src/SwcAppEngine.ts +1 -0
  199. package/src/decorators/addEventListener.ts +102 -96
  200. package/src/decorators/applyAttribute.ts +76 -138
  201. package/src/decorators/applyClass.ts +8 -14
  202. package/src/decorators/applyNode.ts +33 -41
  203. package/src/decorators/applyProperty.ts +51 -99
  204. package/src/decorators/applySlot.ts +3 -3
  205. package/src/decorators/applyStyle.ts +8 -14
  206. package/src/decorators/around.ts +196 -0
  207. package/src/decorators/changedAttribute.ts +39 -15
  208. package/src/decorators/elementDefine.ts +270 -219
  209. package/src/decorators/emitCustomEvent.ts +17 -13
  210. package/src/decorators/eventMedia.ts +50 -9
  211. package/src/decorators/fetch.ts +454 -0
  212. package/src/decorators/index.ts +5 -2
  213. package/src/decorators/intersectionObserver.ts +38 -24
  214. package/src/decorators/lifecycles.ts +24 -22
  215. package/src/decorators/mutationObserver.ts +71 -52
  216. package/src/decorators/parameter.ts +145 -14
  217. package/src/decorators/publishSwcAppMessage.ts +3 -4
  218. package/src/decorators/query.ts +22 -14
  219. package/src/decorators/requestAnimationFrame.ts +10 -19
  220. package/src/decorators/resizeObserver.ts +50 -29
  221. package/src/decorators/setInterval.ts +37 -26
  222. package/src/decorators/setTimeout.ts +37 -26
  223. package/src/decorators/state.ts +19 -13
  224. package/src/decorators/subscribeSwcAppMessage.ts +106 -0
  225. package/src/decorators/subscribeSwcAppRouteChange.ts +131 -0
  226. package/src/decorators/swcAppRoute.ts +231 -0
  227. package/src/elements/SwcApp.ts +40 -10
  228. package/src/elements/SwcAppMixin.ts +340 -101
  229. package/src/types/index.ts +38 -5
  230. package/src/utils/Utils.ts +50 -18
  231. package/dist/cjs/decorators/subscribeSwcAppMessageWhileConnected.js.map +0 -7
  232. package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +0 -7
  233. package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js +0 -54
  234. package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js.map +0 -7
  235. package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +0 -7
  236. package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts +0 -23
  237. package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts.map +0 -1
  238. package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts +0 -31
  239. package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts.map +0 -1
  240. package/src/decorators/subscribeSwcAppMessageWhileConnected.ts +0 -91
  241. package/src/decorators/subscribeSwcAppRouteChangeWhileConnected.ts +0 -107
@@ -1,5 +1,6 @@
1
1
  import { ReflectUtils } from '@dooboostore/core';
2
2
  import { SpecialSelector, SwcQueryOptions, SwcFnSelector, SwcSelector, HelperHostSet } from '../types';
3
+ import { buildSwcParameterArgs } from './parameter';
3
4
 
4
5
  // 공통 옵션 — IntersectionObserverInit + filter/removeObserver. root·delegate 제외.
5
6
  // 주의: 데코레이터의 root(light/shadow/all/auto) 는 셀렉터 스코프 선택용이다.
@@ -7,7 +8,12 @@ import { SpecialSelector, SwcQueryOptions, SwcFnSelector, SwcSelector, HelperHos
7
8
  export interface IntersectionObserverBaseOptions extends Omit<IntersectionObserverInit, 'root'> {
8
9
  /** IntersectionObserver 의 스크롤 컨테이너 (viewport 대신). 데코레이터 root 와 혼동 주의. */
9
10
  intersectionRoot?: Element | Document;
10
- filter?: (matchedEls: HTMLElement[], meta: { currentThis: any, helper: HelperHostSet }) => boolean;
11
+ /** 매칭 시 핸들러 실행 여부 게이트. Promise<boolean>도 되어 async 판정 가능. false면 스킵. */
12
+ filter?: (matchedEls: HTMLElement[], meta: { currentThis: any, helper: HelperHostSet }) => boolean | Promise<boolean>;
13
+ /** filter 통과 후 핸들러 직전 훅. await되고, 리턴값은 @intersectionObserverBeforeReturn 으로 핸들러에 주입된다. */
14
+ before?: (matchedEls: HTMLElement[], meta: { currentThis: any, helper: HelperHostSet }) => any | Promise<any>;
15
+ /** 핸들러가 성공/실패해도 항상 실행되는 정리 훅. ctx로 인자/결과/에러를 받는다. 에러는 로깅됨. */
16
+ finally?: (matchedEls: HTMLElement[], meta: { currentThis: any, helper: HelperHostSet }, ctx: { args: any[]; result?: any; error?: any }) => any | Promise<any>;
11
17
  removeObserver?: (target: Element, optionValue: IntersectionObserverQueryOptions) => void;
12
18
  }
13
19
 
@@ -31,7 +37,7 @@ export const INTERSECTION_OBSERVER_METADATA_KEY = Symbol.for('simple-web-compone
31
37
 
32
38
  const applyIntersectionObserver = (selector: SwcSelector, options: IntersectionObserverOptions, targetObj: Object, propertyKey: string | symbol): void => {
33
39
  const constructor = targetObj.constructor;
34
- let observers = ReflectUtils.getMetadata<IntersectionObserverMetadata[]>(INTERSECTION_OBSERVER_METADATA_KEY, constructor);
40
+ let observers = ReflectUtils.getOwnMetadata(INTERSECTION_OBSERVER_METADATA_KEY, constructor) as IntersectionObserverMetadata[] | undefined;
35
41
  if (!observers) {
36
42
  observers = [];
37
43
  ReflectUtils.defineMetadata(INTERSECTION_OBSERVER_METADATA_KEY, observers, constructor);
@@ -51,7 +57,7 @@ const resolveIntersectionObserverArgs = (
51
57
  };
52
58
 
53
59
  /**
54
- * bare(@decorator)와 factory(@decorator()/@decorator(...)) 호출을 모두 처리하는 공통 디스패처.
60
+ * bare(@decorator)와 factory(@decorator(...), 빈 괄호는 타입에서 막음) 호출을 모두 처리하는 공통 디스패처.
55
61
  * extra는 Light/Shadow/All/Delegate 변형이 강제로 덧씌우는 옵션(root, delegate 등)이다.
56
62
  */
57
63
  const dispatchIntersectionObserver = (
@@ -65,7 +71,7 @@ const dispatchIntersectionObserver = (
65
71
  applyIntersectionObserver('$this', { ...extra }, selectorOrOptionsOrTarget as Object, maybeOptionsOrPropertyKey);
66
72
  return;
67
73
  }
68
- // 옵션과 함께: @decorator() / @decorator(selector, options) / @decorator(options)
74
+ // 옵션과 함께: @decorator(selector, options) / @decorator(options)
69
75
  const { selector, options } = resolveIntersectionObserverArgs(
70
76
  selectorOrOptionsOrTarget as SwcSelector | IntersectionObserverOptions | undefined,
71
77
  maybeOptionsOrPropertyKey as IntersectionObserverOptions | undefined,
@@ -79,7 +85,7 @@ const dispatchIntersectionObserver = (
79
85
  export function intersectionObserver(target: SpecialSelector, options?: IntersectionObserverQueryOptions): MethodDecorator;
80
86
  export function intersectionObserver(selector: string, options?: IntersectionObserverQueryOptions): MethodDecorator;
81
87
  export function intersectionObserver(selector: SwcFnSelector, options?: IntersectionObserverNonQueryOptions): MethodDecorator;
82
- export function intersectionObserver(options?: IntersectionObserverQueryOptions): MethodDecorator;
88
+ export function intersectionObserver(options: IntersectionObserverQueryOptions): MethodDecorator;
83
89
  export function intersectionObserver(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
84
90
  /**
85
91
  * @intersectionObserver decorator to observe element intersection changes.
@@ -92,37 +98,32 @@ export function intersectionObserver(selectorOrOptionsOrTarget?: SwcSelector | I
92
98
  return dispatchIntersectionObserver(selectorOrOptionsOrTarget, maybeOptionsOrPropertyKey, descriptor, {});
93
99
  }
94
100
 
95
- export function intersectionObserverThis(options?: IntersectionObserverQueryOptions): MethodDecorator;
96
- export function intersectionObserverThis(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
97
- export function intersectionObserverThis(optionsOrTarget?: IntersectionObserverQueryOptions | Object, propertyKey?: string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
98
- return dispatchIntersectionObserver(optionsOrTarget, propertyKey, descriptor, {});
99
- }
100
101
 
101
102
  // ─── root별 delegate 헬퍼 (root 주입 → 문자열 셀렉터 전용) ───
102
103
 
103
104
  export function intersectionObserverDelegateLight(selector: string, options?: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator;
104
- export function intersectionObserverDelegateLight(options?: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator;
105
+ export function intersectionObserverDelegateLight(options: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator;
105
106
  export function intersectionObserverDelegateLight(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
106
107
  export function intersectionObserverDelegateLight(selectorOrOptionsOrTarget?: string | Omit<IntersectionObserverQueryOptions, 'delegate'> | Object, maybeOptionsOrPropertyKey?: Omit<IntersectionObserverQueryOptions, 'delegate'> | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
107
108
  return dispatchIntersectionObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'light', delegate: true });
108
109
  }
109
110
 
110
111
  export function intersectionObserverDelegateShadow(selector: string, options?: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator;
111
- export function intersectionObserverDelegateShadow(options?: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator;
112
+ export function intersectionObserverDelegateShadow(options: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator;
112
113
  export function intersectionObserverDelegateShadow(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
113
114
  export function intersectionObserverDelegateShadow(selectorOrOptionsOrTarget?: string | Omit<IntersectionObserverQueryOptions, 'delegate'> | Object, maybeOptionsOrPropertyKey?: Omit<IntersectionObserverQueryOptions, 'delegate'> | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
114
115
  return dispatchIntersectionObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'shadow', delegate: true });
115
116
  }
116
117
 
117
118
  export function intersectionObserverDelegateAll(selector: string, options?: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator;
118
- export function intersectionObserverDelegateAll(options?: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator;
119
+ export function intersectionObserverDelegateAll(options: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator;
119
120
  export function intersectionObserverDelegateAll(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
120
121
  export function intersectionObserverDelegateAll(selectorOrOptionsOrTarget?: string | Omit<IntersectionObserverQueryOptions, 'delegate'> | Object, maybeOptionsOrPropertyKey?: Omit<IntersectionObserverQueryOptions, 'delegate'> | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
121
122
  return dispatchIntersectionObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'all', delegate: true });
122
123
  }
123
124
 
124
125
  export function intersectionObserverDelegate(selector: string, options?: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator;
125
- export function intersectionObserverDelegate(options?: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator;
126
+ export function intersectionObserverDelegate(options: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator;
126
127
  export function intersectionObserverDelegate(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
127
128
  export function intersectionObserverDelegate(selectorOrOptionsOrTarget?: string | Omit<IntersectionObserverQueryOptions, 'delegate'> | Object, maybeOptionsOrPropertyKey?: Omit<IntersectionObserverQueryOptions, 'delegate'> | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
128
129
  return dispatchIntersectionObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'auto', delegate: true });
@@ -131,29 +132,29 @@ export function intersectionObserverDelegate(selectorOrOptionsOrTarget?: string
131
132
  // ─── root별 일반 헬퍼 (delegate 없이, 셀렉터 생략 시 $this) ───
132
133
 
133
134
  export function intersectionObserverLight(selector: string, options?: IntersectionObserverQueryOptions): MethodDecorator;
134
- export function intersectionObserverLight(options?: IntersectionObserverQueryOptions): MethodDecorator;
135
+ export function intersectionObserverLight(options: IntersectionObserverQueryOptions): MethodDecorator;
135
136
  export function intersectionObserverLight(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
136
137
  export function intersectionObserverLight(selectorOrOptionsOrTarget?: string | IntersectionObserverQueryOptions | Object, maybeOptionsOrPropertyKey?: IntersectionObserverQueryOptions | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
137
138
  return dispatchIntersectionObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'light' });
138
139
  }
139
140
 
140
141
  export function intersectionObserverShadow(selector: string, options?: IntersectionObserverQueryOptions): MethodDecorator;
141
- export function intersectionObserverShadow(options?: IntersectionObserverQueryOptions): MethodDecorator;
142
+ export function intersectionObserverShadow(options: IntersectionObserverQueryOptions): MethodDecorator;
142
143
  export function intersectionObserverShadow(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
143
144
  export function intersectionObserverShadow(selectorOrOptionsOrTarget?: string | IntersectionObserverQueryOptions | Object, maybeOptionsOrPropertyKey?: IntersectionObserverQueryOptions | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
144
145
  return dispatchIntersectionObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'shadow' });
145
146
  }
146
147
 
147
148
  export function intersectionObserverAll(selector: string, options?: IntersectionObserverQueryOptions): MethodDecorator;
148
- export function intersectionObserverAll(options?: IntersectionObserverQueryOptions): MethodDecorator;
149
+ export function intersectionObserverAll(options: IntersectionObserverQueryOptions): MethodDecorator;
149
150
  export function intersectionObserverAll(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
150
151
  export function intersectionObserverAll(selectorOrOptionsOrTarget?: string | IntersectionObserverQueryOptions | Object, maybeOptionsOrPropertyKey?: IntersectionObserverQueryOptions | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
151
152
  return dispatchIntersectionObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'all' });
152
153
  }
153
154
 
154
155
  export function getIntersectionObserverMetadata(target: any): IntersectionObserverMetadata[] | undefined {
155
- const constructor = target instanceof Function ? target : target.constructor;
156
- return ReflectUtils.getMetadata(INTERSECTION_OBSERVER_METADATA_KEY, constructor);
156
+ const constructor = typeof target === 'function' ? target : target.constructor;
157
+ return ReflectUtils.findAllMetadata<any[]>(INTERSECTION_OBSERVER_METADATA_KEY, constructor).flat();
157
158
  }
158
159
 
159
160
  // ─────────────────────────────────────────────────────────────────────────────
@@ -200,11 +201,24 @@ export class IntersectionObserverLifeCycler implements ElementDefineLifeCycler {
200
201
  matchedEls = entries.map(e => e.target as HTMLElement).filter(t => t && t.nodeType === 1);
201
202
  }
202
203
  if (matchedEls.length === 0) continue;
203
- if (m.options.filter) {
204
- if (!m.options.filter(matchedEls, { currentThis: inst, helper: helperHostSet })) continue;
205
- }
206
- const hostSet = SwcUtils.getHostSet(inst);
207
- inst[m.propertyKey](matchedEls, entries, obs, { ...hostSet, $root: root });
204
+ const opts = m.options;
205
+ void (async () => {
206
+ const helper = SwcUtils.getHelperAndHostSet(inst);
207
+ if (opts.filter && !(await opts.filter(matchedEls, { currentThis: inst, helper }))) return;
208
+ const hostSet = SwcUtils.getHostSet(inst);
209
+ const helperSet = SwcUtils.getHelperSet(helperHostSet.$w);
210
+ const legacyArgs = [matchedEls, entries, obs, { ...hostSet, $root: root }];
211
+ const buildArgs = (beforeReturn: any) => buildSwcParameterArgs(inst, m.propertyKey, {
212
+ hostSet, helperHostSet: helper, helperSet, intersectionObserverBeforeReturn: beforeReturn
213
+ }, [...legacyArgs, beforeReturn]);
214
+ let args = buildArgs(undefined);
215
+ if (opts.before) { const br = await opts.before(matchedEls, { currentThis: inst, helper }); args = buildArgs(br); }
216
+ let result: any, error: any;
217
+ try { result = await inst[m.propertyKey](...args); }
218
+ catch (e) { error = e; }
219
+ finally { if (opts.finally) await opts.finally(matchedEls, { currentThis: inst, helper }, { args, result, error }); }
220
+ if (error) throw error;
221
+ })().catch(e => console.error('[SWC] intersectionObserver handler error:', e));
208
222
  }
209
223
  };
210
224
  };
@@ -19,6 +19,8 @@ export interface OnConnectedAppendChildOptions {
19
19
  // replaceWrap?:{ start: string, end:string},
20
20
  useShadow?: boolean;
21
21
  order?: number;
22
+ // 비동기 렌더가 끝나기 전까지 먼저 보여줄 내용. resolve되면 제거되고 실제 결과가 들어감.
23
+ fallback?: string | ((helper: any) => string | Node | Node[] | DocumentFragment);
22
24
  }
23
25
  export interface OnConnectedAppendChildOptionsMetadata {
24
26
  propertyKey: string | symbol;
@@ -48,7 +50,7 @@ export function onConnectedBefore(target: Object, propertyKey: string | symbol,
48
50
  export function onConnectedBefore(arg1?: OnConnectedOptions | Object, arg2?: string | symbol, arg3?: PropertyDescriptor): MethodDecorator | void {
49
51
  const decorator = (options: OnConnectedOptions, target: Object, propertyKey: string | symbol) => {
50
52
  const constructor = target.constructor;
51
- let list = ReflectUtils.getMetadata<OnConnectedMetadata[]>(ON_BEFORE_CONNECTED_METADATA_KEY, constructor);
53
+ let list = ReflectUtils.getOwnMetadata(ON_BEFORE_CONNECTED_METADATA_KEY, constructor) as OnConnectedMetadata[] | undefined;
52
54
  if (!list) {
53
55
  list = [];
54
56
  ReflectUtils.defineMetadata(ON_BEFORE_CONNECTED_METADATA_KEY, list, constructor);
@@ -70,7 +72,7 @@ export function onConnectedAfter(target: Object, propertyKey: string | symbol, d
70
72
  export function onConnectedAfter(arg1?: OnConnectedOptions | Object, arg2?: string | symbol, arg3?: PropertyDescriptor): MethodDecorator | void {
71
73
  const decorator = (options: OnConnectedOptions, target: Object, propertyKey: string | symbol) => {
72
74
  const constructor = target.constructor;
73
- let list = ReflectUtils.getMetadata<OnConnectedMetadata[]>(ON_AFTER_CONNECTED_METADATA_KEY, constructor);
75
+ let list = ReflectUtils.getOwnMetadata(ON_AFTER_CONNECTED_METADATA_KEY, constructor) as OnConnectedMetadata[] | undefined;
74
76
  if (!list) {
75
77
  list = [];
76
78
  ReflectUtils.defineMetadata(ON_AFTER_CONNECTED_METADATA_KEY, list, constructor);
@@ -116,7 +118,7 @@ export function onConnectedAfter(arg1?: OnConnectedOptions | Object, arg2?: stri
116
118
  // ) as any;
117
119
  // }
118
120
 
119
- // Helper to handle both @decorator and @decorator() syntax
121
+ // Helper: bare @decorator 와 옵션 @decorator({...}) (빈 괄호 @decorator() 는 타입에서 막음)
120
122
  function createLifecycleDecoratorWithOptions(metadataKey: symbol) {
121
123
  return function(optionOrTarget?: LifecycleOptions | Object, propertyKey?: string | symbol): MethodDecorator | void {
122
124
  if (propertyKey) {
@@ -144,19 +146,19 @@ function createLifecycleDecoratorWithOptions(metadataKey: symbol) {
144
146
  };
145
147
  }
146
148
 
147
- export function onInitialize(options?: LifecycleOptions): MethodDecorator;
149
+ export function onInitialize(options: LifecycleOptions): MethodDecorator;
148
150
  export function onInitialize(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
149
151
  export function onInitialize(optionOrTarget?: LifecycleOptions | Object, propertyKey?: string | symbol): MethodDecorator | void {
150
152
  return createLifecycleDecoratorWithOptions(ON_INITIALIZE_METADATA_KEY)(optionOrTarget, propertyKey);
151
153
  }
152
154
 
153
- export function onDisconnectedBefore(options?: LifecycleOptions): MethodDecorator;
155
+ export function onDisconnectedBefore(options: LifecycleOptions): MethodDecorator;
154
156
  export function onDisconnectedBefore(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
155
157
  export function onDisconnectedBefore(optionOrTarget?: LifecycleOptions | Object, propertyKey?: string | symbol): MethodDecorator | void {
156
158
  return createLifecycleDecoratorWithOptions(ON_BEFORE_DISCONNECTED_METADATA_KEY)(optionOrTarget, propertyKey);
157
159
  }
158
160
 
159
- export function onDisconnectedAfter(options?: LifecycleOptions): MethodDecorator;
161
+ export function onDisconnectedAfter(options: LifecycleOptions): MethodDecorator;
160
162
  export function onDisconnectedAfter(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
161
163
  export function onDisconnectedAfter(optionOrTarget?: LifecycleOptions | Object, propertyKey?: string | symbol): MethodDecorator | void {
162
164
  return createLifecycleDecoratorWithOptions(ON_AFTER_DISCONNECTED_METADATA_KEY)(optionOrTarget, propertyKey);
@@ -164,13 +166,13 @@ export function onDisconnectedAfter(optionOrTarget?: LifecycleOptions | Object,
164
166
 
165
167
  export const onDisconnected = onDisconnectedAfter;
166
168
 
167
- export function onAdoptedBefore(options?: LifecycleOptions): MethodDecorator;
169
+ export function onAdoptedBefore(options: LifecycleOptions): MethodDecorator;
168
170
  export function onAdoptedBefore(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
169
171
  export function onAdoptedBefore(optionOrTarget?: LifecycleOptions | Object, propertyKey?: string | symbol): MethodDecorator | void {
170
172
  return createLifecycleDecoratorWithOptions(ON_BEFORE_ADOPTED_METADATA_KEY)(optionOrTarget, propertyKey);
171
173
  }
172
174
 
173
- export function onAdoptedAfter(options?: LifecycleOptions): MethodDecorator;
175
+ export function onAdoptedAfter(options: LifecycleOptions): MethodDecorator;
174
176
  export function onAdoptedAfter(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
175
177
  export function onAdoptedAfter(optionOrTarget?: LifecycleOptions | Object, propertyKey?: string | symbol): MethodDecorator | void {
176
178
  return createLifecycleDecoratorWithOptions(ON_AFTER_ADOPTED_METADATA_KEY)(optionOrTarget, propertyKey);
@@ -178,13 +180,13 @@ export function onAdoptedAfter(optionOrTarget?: LifecycleOptions | Object, prope
178
180
 
179
181
  export const onAdopted = onAdoptedAfter;
180
182
 
181
- export function onConnectedSwcApp(options?: LifecycleOptions): MethodDecorator;
183
+ export function onConnectedSwcApp(options: LifecycleOptions): MethodDecorator;
182
184
  export function onConnectedSwcApp(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
183
185
  export function onConnectedSwcApp(optionOrTarget?: LifecycleOptions | Object, propertyKey?: string | symbol): MethodDecorator | void {
184
186
  return createLifecycleDecoratorWithOptions(ON_CONNECTED_SWC_APP_METADATA_KEY)(optionOrTarget, propertyKey);
185
187
  }
186
188
 
187
- export function onConnectedCompleted(options?: LifecycleOptions): MethodDecorator;
189
+ export function onConnectedCompleted(options: LifecycleOptions): MethodDecorator;
188
190
  export function onConnectedCompleted(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
189
191
  export function onConnectedCompleted(optionOrTarget?: LifecycleOptions | Object, propertyKey?: string | symbol): MethodDecorator | void {
190
192
  return createLifecycleDecoratorWithOptions(ON_CONNECTED_COMPLETED_METADATA_KEY)(optionOrTarget, propertyKey);
@@ -196,7 +198,7 @@ export function onConnectedCompleted(optionOrTarget?: LifecycleOptions | Object,
196
198
 
197
199
  const decorator = (options: OnConnectedAppendChildOptions, target: Object, propertyKey: string | symbol) => {
198
200
  const constructor = target.constructor;
199
- let list = ReflectUtils.getMetadata<OnConnectedAppendChildOptionsMetadata[]>(ON_CONNECTED_BODY_METADATA_KEY, constructor);
201
+ let list = ReflectUtils.getOwnMetadata(ON_CONNECTED_BODY_METADATA_KEY, constructor) as OnConnectedAppendChildOptionsMetadata[] | undefined;
200
202
  if (!list) {
201
203
  list = [];
202
204
  ReflectUtils.defineMetadata(ON_CONNECTED_BODY_METADATA_KEY, list, constructor);
@@ -210,7 +212,7 @@ export function onConnectedBodyShadow(optionOrTarget: Omit<OnConnectedAppendChil
210
212
  if (propertyKey) { // no parameter option @decorator
211
213
  return decorator({useShadow: true}, optionOrTarget!, propertyKey);
212
214
  }
213
- // parameter option @decorator()
215
+ // parameter option @decorator({...})
214
216
  return (target: Object, propertyKey: string | symbol) => {
215
217
  decorator({...optionOrTarget??{}, useShadow: true}, target, propertyKey);
216
218
  };
@@ -222,7 +224,7 @@ export function onConnectedBodyLight(optionOrTarget: Omit<OnConnectedAppendChild
222
224
  if (propertyKey) { // no parameter option @decorator
223
225
  return decorator({useShadow: false}, optionOrTarget!, propertyKey);
224
226
  }
225
- // parameter option @decorator()
227
+ // parameter option @decorator({...})
226
228
  return (target: Object, propertyKey: string | symbol) => {
227
229
  decorator({...optionOrTarget??{}, useShadow: false}, target, propertyKey);
228
230
  };
@@ -233,7 +235,7 @@ export function onConnectedBody(optionOrTarget: OnConnectedAppendChildOptions |
233
235
  if (propertyKey) { // no parameter option @decorator
234
236
  return decorator({}, optionOrTarget!, propertyKey);
235
237
  }
236
- // parameter option @decorator()
238
+ // parameter option @decorator({...})
237
239
  return (target: Object, propertyKey: string | symbol) => {
238
240
  decorator((optionOrTarget as OnConnectedAppendChildOptions) || {}, target, propertyKey);
239
241
  };
@@ -243,15 +245,15 @@ export function onConnectedBody(optionOrTarget: OnConnectedAppendChildOptions |
243
245
  * 프로토타입 체인을 순회하며 모든 라이프사이클 메서드를 수집합니다.
244
246
  */
245
247
  export const findAllLifecycleMetadata = (target: any, metadataKey: symbol): LifecycleMetadata[] => {
246
- const constructor = target instanceof Function ? target : target.constructor;
247
- const results = ReflectUtils.getOwnMetadata(metadataKey, constructor) as LifecycleMetadata[] ?? [];
248
+ const constructor = typeof target === 'function' ? target : target.constructor;
249
+ const results = ReflectUtils.findAllMetadata<LifecycleMetadata[]>(metadataKey, constructor).flat();
248
250
  // Sort by order (default 0 if not specified)
249
251
  return [...results].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
250
252
  };
251
253
 
252
254
  export const findAllOnConnectedMetadata = (target: any): OnConnectedAppendChildOptionsMetadata[] => {
253
- const constructor = target instanceof Function ? target : target.constructor;
254
- const results = ReflectUtils.getMetadata<OnConnectedAppendChildOptionsMetadata[]>(ON_CONNECTED_BODY_METADATA_KEY, constructor) ?? [];
255
+ const constructor = typeof target === 'function' ? target : target.constructor;
256
+ const results = ReflectUtils.findAllMetadata<OnConnectedAppendChildOptionsMetadata[]>(ON_CONNECTED_BODY_METADATA_KEY, constructor).flat();
255
257
  // Sort by order (default 0 if not specified)
256
258
  return [...results].sort((a, b) => {
257
259
  const orderA = a.options?.order ?? 0;
@@ -261,15 +263,15 @@ export const findAllOnConnectedMetadata = (target: any): OnConnectedAppendChildO
261
263
  };
262
264
 
263
265
  export const findAllOnConnectedBeforeMetadata = (target: any): OnConnectedMetadata[] => {
264
- const constructor = target instanceof Function ? target : target.constructor;
265
- const results = ReflectUtils.getMetadata<OnConnectedMetadata[]>(ON_BEFORE_CONNECTED_METADATA_KEY, constructor) ?? [];
266
+ const constructor = typeof target === 'function' ? target : target.constructor;
267
+ const results = ReflectUtils.findAllMetadata<OnConnectedMetadata[]>(ON_BEFORE_CONNECTED_METADATA_KEY, constructor).flat();
266
268
  // Sort by order
267
269
  return [...results].sort((a, b) => (a.options?.order ?? 0) - (b.options?.order ?? 0));
268
270
  };
269
271
 
270
272
  export const findAllOnConnectedAfterMetadata = (target: any): OnConnectedMetadata[] => {
271
- const constructor = target instanceof Function ? target : target.constructor;
272
- const results = ReflectUtils.getMetadata<OnConnectedMetadata[]>(ON_AFTER_CONNECTED_METADATA_KEY, constructor) ?? [];
273
+ const constructor = typeof target === 'function' ? target : target.constructor;
274
+ const results = ReflectUtils.findAllMetadata<OnConnectedMetadata[]>(ON_AFTER_CONNECTED_METADATA_KEY, constructor).flat();
273
275
  // Sort by order
274
276
  return [...results].sort((a, b) => (a.options?.order ?? 0) - (b.options?.order ?? 0));
275
277
  };
@@ -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
- filter?: (matchedEls: HTMLElement[], meta: { currentThis: any, helper: HelperHostSet }) => boolean;
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
  }
@@ -26,7 +32,7 @@ export const MUTATION_OBSERVER_METADATA_KEY = Symbol.for('simple-web-component:m
26
32
 
27
33
  const applyMutationObserver = (selector: SwcSelector, options: MutationObserverQueryOptions, targetObj: Object, propertyKey: string | symbol): void => {
28
34
  const constructor = targetObj.constructor;
29
- let observers = ReflectUtils.getMetadata<MutationObserverMetadata[]>(MUTATION_OBSERVER_METADATA_KEY, constructor);
35
+ let observers = ReflectUtils.getOwnMetadata(MUTATION_OBSERVER_METADATA_KEY, constructor) as MutationObserverMetadata[] | undefined;
30
36
  if (!observers) {
31
37
  observers = [];
32
38
  ReflectUtils.defineMetadata(MUTATION_OBSERVER_METADATA_KEY, observers, constructor);
@@ -47,7 +53,7 @@ const resolveMutationObserverArgs = (
47
53
 
48
54
  /**
49
55
  * selectorOrOptionsOrTarget/maybeOptionsOrPropertyKey/descriptor을 받아 bare(@decorator)와
50
- * factory(@decorator()/@decorator(...)) 호출을 모두 처리하는 공통 디스패처.
56
+ * factory(@decorator(...), 빈 괄호는 타입에서 막음) 호출을 모두 처리하는 공통 디스패처.
51
57
  * extra는 Light/Shadow/All/Delegate 변형이 강제로 덧씌우는 옵션(root, delegate 등)이다.
52
58
  */
53
59
  const dispatchMutationObserver = (
@@ -57,11 +63,11 @@ const dispatchMutationObserver = (
57
63
  extra: Partial<MutationObserverQueryOptions>
58
64
  ): MethodDecorator | void => {
59
65
  if ((typeof maybeOptionsOrPropertyKey === 'string' || typeof maybeOptionsOrPropertyKey === 'symbol') && descriptor !== undefined) {
60
- // 옵션 없이: @decorator
61
- applyMutationObserver('$this', { ...extra }, selectorOrOptionsOrTarget as Object, maybeOptionsOrPropertyKey);
66
+ // 옵션 없이: @decorator — 자기 자신의 하위 전체(childList + subtree)를 본다. 범위를 좁히려면 옵션을 명시.
67
+ applyMutationObserver('$this', { subtree: true, ...extra }, selectorOrOptionsOrTarget as Object, maybeOptionsOrPropertyKey);
62
68
  return;
63
69
  }
64
- // 옵션과 함께: @decorator() / @decorator(selector, options) / @decorator(options)
70
+ // 옵션과 함께: @decorator(selector, options) / @decorator(options)
65
71
  const { selector, options } = resolveMutationObserverArgs(
66
72
  selectorOrOptionsOrTarget as SwcSelector | MutationObserverQueryOptions | undefined,
67
73
  maybeOptionsOrPropertyKey as MutationObserverQueryOptions | undefined,
@@ -75,7 +81,7 @@ const dispatchMutationObserver = (
75
81
  export function mutationObserver(target: SpecialSelector, options?: MutationObserverQueryOptions): MethodDecorator;
76
82
  export function mutationObserver(selector: string, options?: MutationObserverQueryOptions): MethodDecorator;
77
83
  export function mutationObserver(selector: SwcFnSelector, options?: MutationObserverNonQueryOptions): MethodDecorator;
78
- export function mutationObserver(options?: MutationObserverQueryOptions): MethodDecorator;
84
+ export function mutationObserver(options: MutationObserverQueryOptions): MethodDecorator;
79
85
  export function mutationObserver(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
80
86
  /**
81
87
  * @mutationObserver decorator to observe DOM mutations.
@@ -85,37 +91,32 @@ export function mutationObserver(selectorOrOptionsOrTarget?: SwcSelector | Mutat
85
91
  return dispatchMutationObserver(selectorOrOptionsOrTarget, maybeOptionsOrPropertyKey, descriptor, {});
86
92
  }
87
93
 
88
- export function mutationObserverThis(options?: MutationObserverQueryOptions): MethodDecorator;
89
- export function mutationObserverThis(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
90
- export function mutationObserverThis(optionsOrTarget?: MutationObserverQueryOptions | Object, propertyKey?: string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
91
- return dispatchMutationObserver(optionsOrTarget, propertyKey, descriptor, {});
92
- }
93
94
 
94
95
  // ─── root별 delegate 헬퍼 (addEventListener와 동일 패턴) ───
95
96
 
96
97
  export function mutationObserverDelegateLight(selector: string, options?: MutationObserverBaseOptions): MethodDecorator;
97
- export function mutationObserverDelegateLight(options?: MutationObserverBaseOptions): MethodDecorator;
98
+ export function mutationObserverDelegateLight(options: MutationObserverBaseOptions): MethodDecorator;
98
99
  export function mutationObserverDelegateLight(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
99
100
  export function mutationObserverDelegateLight(selectorOrOptionsOrTarget?: string | Omit<MutationObserverQueryOptions, 'root'> | Object, maybeOptionsOrPropertyKey?: Omit<MutationObserverQueryOptions, 'root'> | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
100
101
  return dispatchMutationObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'light', delegate: true });
101
102
  }
102
103
 
103
104
  export function mutationObserverDelegateShadow(selector: string, options?: MutationObserverBaseOptions): MethodDecorator;
104
- export function mutationObserverDelegateShadow(options?: MutationObserverBaseOptions): MethodDecorator;
105
+ export function mutationObserverDelegateShadow(options: MutationObserverBaseOptions): MethodDecorator;
105
106
  export function mutationObserverDelegateShadow(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
106
107
  export function mutationObserverDelegateShadow(selectorOrOptionsOrTarget?: string | Omit<MutationObserverQueryOptions, 'root'> | Object, maybeOptionsOrPropertyKey?: Omit<MutationObserverQueryOptions, 'root'> | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
107
108
  return dispatchMutationObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'shadow', delegate: true });
108
109
  }
109
110
 
110
111
  export function mutationObserverDelegateAll(selector: string, options?: MutationObserverBaseOptions): MethodDecorator;
111
- export function mutationObserverDelegateAll(options?: MutationObserverBaseOptions): MethodDecorator;
112
+ export function mutationObserverDelegateAll(options: MutationObserverBaseOptions): MethodDecorator;
112
113
  export function mutationObserverDelegateAll(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
113
114
  export function mutationObserverDelegateAll(selectorOrOptionsOrTarget?: string | Omit<MutationObserverQueryOptions, 'root'> | Object, maybeOptionsOrPropertyKey?: Omit<MutationObserverQueryOptions, 'root'> | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
114
115
  return dispatchMutationObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'all', delegate: true });
115
116
  }
116
117
 
117
118
  export function mutationObserverDelegate(selector: string, options?: MutationObserverBaseOptions): MethodDecorator;
118
- export function mutationObserverDelegate(options?: MutationObserverBaseOptions): MethodDecorator;
119
+ export function mutationObserverDelegate(options: MutationObserverBaseOptions): MethodDecorator;
119
120
  export function mutationObserverDelegate(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
120
121
  export function mutationObserverDelegate(selectorOrOptionsOrTarget?: string | Omit<MutationObserverQueryOptions, 'root'> | Object, maybeOptionsOrPropertyKey?: Omit<MutationObserverQueryOptions, 'root'> | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
121
122
  return dispatchMutationObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'auto', delegate: true });
@@ -124,29 +125,29 @@ export function mutationObserverDelegate(selectorOrOptionsOrTarget?: string | Om
124
125
  // ─── root별 일반 헬퍼 (delegate 없이, 셀렉터 생략 시 $this) ───
125
126
 
126
127
  export function mutationObserverLight(selector: string, options?: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator;
127
- export function mutationObserverLight(options?: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator;
128
+ export function mutationObserverLight(options: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator;
128
129
  export function mutationObserverLight(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
129
130
  export function mutationObserverLight(selectorOrOptionsOrTarget?: string | Omit<MutationObserverQueryOptions, 'root'> | Object, maybeOptionsOrPropertyKey?: Omit<MutationObserverQueryOptions, 'root'> | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
130
131
  return dispatchMutationObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'light' });
131
132
  }
132
133
 
133
134
  export function mutationObserverShadow(selector: string, options?: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator;
134
- export function mutationObserverShadow(options?: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator;
135
+ export function mutationObserverShadow(options: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator;
135
136
  export function mutationObserverShadow(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
136
137
  export function mutationObserverShadow(selectorOrOptionsOrTarget?: string | Omit<MutationObserverQueryOptions, 'root'> | Object, maybeOptionsOrPropertyKey?: Omit<MutationObserverQueryOptions, 'root'> | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
137
138
  return dispatchMutationObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'shadow' });
138
139
  }
139
140
 
140
141
  export function mutationObserverAll(selector: string, options?: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator;
141
- export function mutationObserverAll(options?: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator;
142
+ export function mutationObserverAll(options: Omit<MutationObserverQueryOptions, 'root'>): MethodDecorator;
142
143
  export function mutationObserverAll(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
143
144
  export function mutationObserverAll(selectorOrOptionsOrTarget?: string | Omit<MutationObserverQueryOptions, 'root'> | Object, maybeOptionsOrPropertyKey?: Omit<MutationObserverQueryOptions, 'root'> | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
144
145
  return dispatchMutationObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'all' });
145
146
  }
146
147
 
147
148
  export function getMutationObserverMetadata(target: any): MutationObserverMetadata[] | undefined {
148
- const constructor = target instanceof Function ? target : target.constructor;
149
- return ReflectUtils.getMetadata(MUTATION_OBSERVER_METADATA_KEY, constructor);
149
+ const constructor = typeof target === 'function' ? target : target.constructor;
150
+ return ReflectUtils.findAllMetadata<any[]>(MUTATION_OBSERVER_METADATA_KEY, constructor).flat();
150
151
  }
151
152
 
152
153
  // ─────────────────────────────────────────────────────────────────────────────
@@ -154,20 +155,21 @@ export function getMutationObserverMetadata(target: any): MutationObserverMetada
154
155
  // observer 를 직접 생성하지 않고 OnConnectedResult 를 반환한다.
155
156
  // elementDefine 이 수집된 MutationObserverSet 으로 observer 를 생성한다.
156
157
  // ─────────────────────────────────────────────────────────────────────────────
157
- import { ElementDefineLifeCycler, MutationObserverSet, MutationObserverSetEntry, ObserverObserveTarget, OnConnectedResult } from '../types';
158
+ import { ElementDefineLifeCycler, inObserverScope, MutationObserverSet, MutationObserverSetEntry, ObserverObserveTarget, ObserverScope, OnConnectedResult, ResizeObserverSet } from '../types';
158
159
  import { SwcUtils } from '../utils/Utils';
159
160
 
160
161
  export class MutationObserverLifeCycler implements ElementDefineLifeCycler {
161
162
  private readonly removeObserverCallbacksMap = new WeakMap<Element, Array<{ fn: (target: Element, opts: unknown) => void; target: any; opts: unknown }>>();
162
163
 
163
- onConnected(helperHostSet: HelperHostSet): OnConnectedResult | void {
164
+ onConnected(helperHostSet: HelperHostSet, _set?: ResizeObserverSet, scope?: ObserverScope): OnConnectedResult | void {
164
165
  const inst = helperHostSet.$this;
165
166
  const currentWin = helperHostSet.$w;
166
167
 
167
- const removeObserverCallbacks: Array<{ fn: (target: Element, opts: unknown) => void; target: any; opts: unknown }> = [];
168
+ // 'rest' 는 같은 connect 의 'self' 뒤에 오므로 이어 붙이고, 그 외(새 connect)는 새로 시작한다.
169
+ const removeObserverCallbacks = (scope === 'rest' && this.removeObserverCallbacksMap.get(inst)) || [];
168
170
  this.removeObserverCallbacksMap.set(inst, removeObserverCallbacks);
169
171
 
170
- const allMeta = getMutationObserverMetadata(inst) ?? [];
172
+ const allMeta = (getMutationObserverMetadata(inst) ?? []).filter(m => inObserverScope(m, scope));
171
173
  // 처리할 메타가 없으면 observer 불필요
172
174
  if (allMeta.length === 0) return;
173
175
 
@@ -197,13 +199,19 @@ export class MutationObserverLifeCycler implements ElementDefineLifeCycler {
197
199
  return init;
198
200
  };
199
201
 
200
- const fnObservedSets = new Map<MutationObserverMetadata, WeakSet<Element>>();
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)));
201
207
 
202
208
  const callback = (mutations: MutationRecord[], obs: MutationObserver) => {
203
209
  // ── MutationObserver 메타 콜백 ──
204
210
  for (const meta of metas) {
205
211
  const { selector, options } = meta;
206
212
  let matchedEls: HTMLElement[] = [];
213
+ // 핸들러에 넘길 레코드 — non-delegate 는 자기 대상 레코드만 (옵저버는 공유라 배치에 다른 대상 레코드가 섞인다)
214
+ let records = mutations;
207
215
 
208
216
  const typeMatches = (m: MutationRecord): boolean => {
209
217
  const has = !!(options.childList || options.attributes || options.characterData);
@@ -213,8 +221,8 @@ export class MutationObserverLifeCycler implements ElementDefineLifeCycler {
213
221
  return true;
214
222
  };
215
223
 
216
- const collect = (matchesSel: (n: any) => boolean) =>
217
- mutations.flatMap(m => {
224
+ const collect = (matchesSel: (n: any) => boolean, records: MutationRecord[] = mutations) =>
225
+ records.flatMap(m => {
218
226
  if (!typeMatches(m)) return [];
219
227
  const els: HTMLElement[] = [];
220
228
  if (matchesSel(m.target)) els.push(m.target as HTMLElement);
@@ -223,26 +231,27 @@ export class MutationObserverLifeCycler implements ElementDefineLifeCycler {
223
231
  return els;
224
232
  });
225
233
 
226
- if (options.delegate && typeof selector === 'string') {
227
- const isThis = selector === '$this' || selector === '';
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') {
228
239
  matchedEls = collect(n => {
229
240
  if (!n || n.nodeType !== 1) return false;
230
- if (isThis) return true;
231
241
  const el = n as HTMLElement;
232
242
  return el.matches?.(selector) || !!el.closest?.(selector);
233
243
  });
234
244
  } else if (typeof selector === 'string') {
235
- const isThis = selector === '$this' || selector === '';
236
- matchedEls = collect(n => {
245
+ records = mutations.filter(m => owns(meta, m));
246
+ matchedEls = records.length ? collect(n => {
237
247
  if (!n || n.nodeType !== 1) return false;
238
- if (isThis) return true;
239
248
  return (n as HTMLElement).matches?.(selector);
240
- });
249
+ }, records) : [];
241
250
  } else if (typeof selector === 'function') {
242
- const set = fnObservedSets.get(meta);
243
- matchedEls = mutations.filter(m => typeMatches(m))
244
- .map(m => m.target as HTMLElement)
245
- .filter(t => t && t.nodeType === 1 && (set ? set.has(t) : false));
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[];
246
255
  } else {
247
256
  matchedEls = mutations.filter(m => typeMatches(m))
248
257
  .map(m => m.target as HTMLElement)
@@ -250,11 +259,24 @@ export class MutationObserverLifeCycler implements ElementDefineLifeCycler {
250
259
  }
251
260
 
252
261
  if (matchedEls.length === 0) continue;
253
- if (options.filter) {
254
- if (!options.filter(matchedEls, { currentThis: inst, helper: helperHostSet })) continue;
255
- }
256
- const hostSet = SwcUtils.getHostSet(inst);
257
- inst[meta.propertyKey](matchedEls, mutations, obs, { ...hostSet, $root: root });
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));
258
280
  }
259
281
 
260
282
  };
@@ -272,20 +294,17 @@ export class MutationObserverLifeCycler implements ElementDefineLifeCycler {
272
294
  const { selector, options } = m;
273
295
  const mInit = initFrom(options);
274
296
  if (typeof selector === 'string') {
275
- if (selector === '$this' || selector === '') {
276
- observeTargets.push({ target: root, options: mInit });
277
- } else {
278
- root.querySelectorAll(selector).forEach(el => observeTargets.push({ target: el as Element, options: mInit }));
279
- }
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);
280
300
  } else if (typeof selector === 'function') {
281
301
  const res = (selector as any)(inst, helperHostSet);
282
302
  let targets: HTMLElement[] = [];
283
303
  if (res instanceof currentWin.HTMLElement) targets = [res as HTMLElement];
284
304
  else if (res instanceof currentWin.NodeList) targets = Array.from(res as NodeList).filter((e: any) => e instanceof currentWin.HTMLElement) as HTMLElement[];
285
305
  else if (Array.isArray(res)) targets = res.filter((e: any) => e instanceof currentWin.HTMLElement) as HTMLElement[];
286
- const set = new WeakSet<Element>();
287
- for (const el of targets) { set.add(el); observeTargets.push({ target: el, options: mInit }); }
288
- fnObservedSets.set(m, set);
306
+ for (const el of targets) observeTargets.push({ target: el, options: mInit });
307
+ observedNodes.set(m, targets);
289
308
  }
290
309
  }
291
310