@dooboostore/simple-web-component 1.0.50 → 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.
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 +256 -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 +258 -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 +1886 -999
  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 +1886 -999
  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 +330 -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,35 +1,45 @@
1
1
  import { ReflectUtils } from '@dooboostore/core';
2
2
 
3
3
  /**
4
- * @eventObject/@matchedElement/@hostSet/@helperHostSet/@helperSet/@routerEvent/@appMessage —
5
- * @addEventListener/lifecycle/subscribeSwcAppRouteChangeWhileConnected/subscribeSwcAppMessageWhileConnected
4
+ * @eventObject/@matchedElement/@hostSet/@helperHostSet/@helperSet/@swcAppRouterEvent/@appMessage/@eventBeforeReturn —
5
+ * @event/lifecycle/subscribeSwcAppRouteChange/subscribeSwcAppMessage
6
6
  * 계열 핸들러의 파라미터를 순서 무관하게 선언할 수 있게 해주는 파라미터 데코레이터.
7
7
  * @dooboostore/simple-boot의 @Inject와 동일한 인덱스 기반 메타데이터 패턴을 따른다:
8
8
  * 데코레이터가 실행되는 순서가 아니라 실제 parameterIndex로 슬롯을 매칭하므로,
9
9
  * 사용자가 파라미터 선언 순서를 자유롭게 바꿔도 된다.
10
10
  */
11
- export type SwcParamKind = 'event' | 'matched' | 'hostSet' | 'helperHostSet' | 'helperSet' | 'routerEvent' | 'appMessage';
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';
12
21
 
13
22
  const SWC_PARAMETER_METADATA_KEY = Symbol.for('simple-web-component:parameter');
14
23
 
15
- type SaveParamConfig = { index: number; kind: SwcParamKind };
24
+ /** key: @swcAppRouteQueryParam('q') 처럼 키를 받는 파라미터 데코레이터의 키 */
25
+ type SaveParamConfig = { index: number; kind: SwcParamKind; key?: string };
16
26
 
17
- const registerParam = (kind: SwcParamKind, target: Object, propertyKey: string | symbol | undefined, parameterIndex: number) => {
27
+ const registerParam = (kind: SwcParamKind, target: Object, propertyKey: string | symbol | undefined, parameterIndex: number, key?: string) => {
18
28
  if (!propertyKey) return;
19
29
  const constructor = target.constructor;
20
30
  const saves = (ReflectUtils.getOwnMetadata(SWC_PARAMETER_METADATA_KEY, constructor, propertyKey) ?? []) as SaveParamConfig[];
21
- saves.push({ index: parameterIndex, kind });
31
+ saves.push(key === undefined ? { index: parameterIndex, kind } : { index: parameterIndex, kind, key });
22
32
  ReflectUtils.defineMetadata(SWC_PARAMETER_METADATA_KEY, saves, constructor, propertyKey);
23
33
  };
24
34
 
25
35
  /** 이벤트 핸들러의 원본 Event 객체를 주입한다. */
26
36
  export function eventObject(target: Object, propertyKey: string | symbol, parameterIndex: number): void {
27
- registerParam('event', target, propertyKey, parameterIndex);
37
+ registerParam('eventObject', target, propertyKey, parameterIndex);
28
38
  }
29
39
 
30
40
  /** delegate로 매칭된 실제 엘리먼트($matchedElement)를 주입한다. */
31
41
  export function matchedElement(target: Object, propertyKey: string | symbol, parameterIndex: number): void {
32
- registerParam('matched', target, propertyKey, parameterIndex);
42
+ registerParam('matchedElement', target, propertyKey, parameterIndex);
33
43
  }
34
44
 
35
45
  /** HostSet(호스트 트리 정보 — $host/$hosts/$firstHost/$appHost 등)을 주입한다. */
@@ -47,18 +57,91 @@ export function helperSet(target: Object, propertyKey: string | symbol, paramete
47
57
  registerParam('helperSet', target, propertyKey, parameterIndex);
48
58
  }
49
59
 
50
- /** @subscribeSwcAppRouteChangeWhileConnected 핸들러의 라우트 변경 이벤트({...RouterEventType, pathData})를 주입한다. */
51
- export function routerEvent(target: Object, propertyKey: string | symbol, parameterIndex: number): void {
52
- registerParam('routerEvent', target, propertyKey, parameterIndex);
60
+ /** @subscribeSwcAppRouteChange 핸들러의 라우트 변경 이벤트({...RouterEventType, pathData})를 주입한다. */
61
+ export function swcAppRouterEvent(target: Object, propertyKey: string | symbol, parameterIndex: number): void {
62
+ registerParam('swcAppRouterEvent', target, propertyKey, parameterIndex);
53
63
  }
54
64
 
55
- /** @subscribeSwcAppMessageWhileConnected 핸들러의 SwcAppMessage 페이로드를 주입한다. */
65
+ /** @subscribeSwcAppMessage 핸들러의 SwcAppMessage 페이로드를 주입한다. */
56
66
  export function appMessage(target: Object, propertyKey: string | symbol, parameterIndex: number): void {
57
67
  registerParam('appMessage', target, propertyKey, parameterIndex);
58
68
  }
59
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
+
60
143
  export const getParameterMetadata = (target: any, propertyKey: string | symbol): SaveParamConfig[] => {
61
- const constructor = target instanceof Function ? target : target.constructor;
144
+ const constructor = typeof target === 'function' ? target : target.constructor;
62
145
  return ReflectUtils.getMetadata(SWC_PARAMETER_METADATA_KEY, constructor, propertyKey) ?? [];
63
146
  };
64
147
 
@@ -76,6 +159,54 @@ export const buildSwcParameterArgs = (
76
159
  if (saves.length === 0) return legacyArgs;
77
160
  const maxIndex = Math.max(...saves.map(s => s.index));
78
161
  const args: any[] = new Array(maxIndex + 1);
79
- for (const s of saves) args[s.index] = kindValues[s.kind];
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
+ }
80
167
  return args;
81
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
- // 함수로 호출된 경우 (괄호 있음): @publishSwcAppMessage() / @publishSwcAppMessage('messageType') / @publishSwcAppMessage({...})
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 instanceof Function ? target : target.constructor;
142
- return ReflectUtils.getOwnMetadata(PUBLISH_SWC_APP_MESSAGE_METADATA_KEY, constructor);
140
+ const constructor = typeof target === 'function' ? target : target.constructor;
141
+ return ReflectUtils.findAllMetadata<any[]>(PUBLISH_SWC_APP_MESSAGE_METADATA_KEY, constructor).flat();
143
142
  };
@@ -39,7 +39,7 @@ export const resolveQueryElements = (
39
39
  options: QueryOptions,
40
40
  win: Window
41
41
  ): HTMLElement[] => {
42
- const hostSet = SwcUtils.getHelperAndHostSet(win, inst);
42
+ const hostSet = SwcUtils.getHelperAndHostSet(inst);
43
43
  let all: HTMLElement[] = [];
44
44
 
45
45
  if (typeof selector === 'function') {
@@ -95,10 +95,11 @@ export const pickElements = (
95
95
  return all.length ? all[0] : null;
96
96
  };
97
97
 
98
- export function query(target: Object, propertyKey: string | symbol, descriptor?: PropertyDescriptor): PropertyDescriptor | void;
99
98
  export function query(selector: string, options?: QueryOptions): PropertyDecorator;
100
99
  export function query(selector: QueryFnSelector, options?: QueryNonQueryOptions): PropertyDecorator;
101
- export function query(options?: QueryOptions): PropertyDecorator;
100
+ export function query(options: QueryOptions): PropertyDecorator;
101
+ // bare(@query) 시그니처는 맨 뒤 — @attribute 와 같은 이유 (TS1240/TS1271)
102
+ export function query(target: Object, propertyKey: string | symbol): void;
102
103
  /**
103
104
  * @query decorator — 클래스 필드에 요소를 주입한다.
104
105
  *
@@ -111,6 +112,10 @@ export function query(selectorOrTarget?: string | ((currentThis: any, helper: He
111
112
  if (descriptor !== undefined && (typeof optionsOrPropertyKey === 'string' || typeof optionsOrPropertyKey === 'symbol')) {
112
113
  throw new Error(`@query decorator cannot be used on methods. (Method: ${String(optionsOrPropertyKey)})`);
113
114
  }
115
+ // bare: @query — 자기 자신($this). 빈 괄호 @query() 는 타입에서 막는다 (인자가 없으면 괄호도 없다)
116
+ if (selectorOrTarget && (typeof optionsOrPropertyKey === 'string' || typeof optionsOrPropertyKey === 'symbol')) {
117
+ return query('$this')(selectorOrTarget, optionsOrPropertyKey);
118
+ }
114
119
  // With selector
115
120
  if (typeof selectorOrTarget === 'string' || typeof selectorOrTarget === 'function') {
116
121
  return (targetObj: Object, propertyKey: string | symbol, descriptor?: never): void => {
@@ -119,7 +124,7 @@ export function query(selectorOrTarget?: string | ((currentThis: any, helper: He
119
124
  }
120
125
 
121
126
  const constructor = targetObj.constructor;
122
- let queries = ReflectUtils.getMetadata<QueryMetadata[]>(QUERY_METADATA_KEY, constructor);
127
+ let queries = ReflectUtils.getOwnMetadata(QUERY_METADATA_KEY, constructor) as QueryMetadata[] | undefined;
123
128
  if (!queries) {
124
129
  queries = [];
125
130
  ReflectUtils.defineMetadata(QUERY_METADATA_KEY, queries, constructor);
@@ -157,26 +162,29 @@ export function query(selectorOrTarget?: string | ((currentThis: any, helper: He
157
162
  });
158
163
  };
159
164
  }
160
- // Without selector (defaults to $this)
165
+ // 옵션만: $this
161
166
  return query('$this', selectorOrTarget as QueryOptions);
162
167
  }
163
168
 
164
169
  export const getQueryMetadata = (target: any): QueryMetadata[] => {
165
- const constructor = target instanceof Function ? target : target.constructor;
166
- return ReflectUtils.getMetadata(QUERY_METADATA_KEY, constructor) ?? [];
170
+ const constructor = typeof target === 'function' ? target : target.constructor;
171
+ return ReflectUtils.findAllMetadata<any[]>(QUERY_METADATA_KEY, constructor).flat();
167
172
  };
168
173
 
169
174
  // ─── queryAll (query의 pick:'all' 편의 래퍼 — 호환용) ───
170
175
  export const QUERY_ALL_METADATA_KEY = QUERY_METADATA_KEY;
171
176
 
172
- export function queryAll(target: Object, propertyKey: string | symbol, descriptor?: PropertyDescriptor): PropertyDescriptor | void;
173
177
  export function queryAll(selector: string, options?: Omit<QueryOptions, 'pick'>): PropertyDecorator;
174
178
  export function queryAll(selector: QueryFnSelector, options?: Omit<QueryNonQueryOptions, 'pick'>): PropertyDecorator;
175
- export function queryAll(options?: Omit<QueryOptions, 'pick'>): PropertyDecorator;
179
+ export function queryAll(options: Omit<QueryOptions, 'pick'>): PropertyDecorator;
180
+ export function queryAll(target: Object, propertyKey: string | symbol): void;
176
181
  export function queryAll(selectorOrTarget?: any, optionsOrPropertyKey?: any, descriptor?: PropertyDescriptor): any {
177
- // bare(필드 직접 적용)는 query로 위임
178
182
  if (descriptor !== undefined && (typeof optionsOrPropertyKey === 'string' || typeof optionsOrPropertyKey === 'symbol')) {
179
- return query(selectorOrTarget, optionsOrPropertyKey, descriptor);
183
+ throw new Error(`@queryAll decorator cannot be used on methods. (Method: ${String(optionsOrPropertyKey)})`);
184
+ }
185
+ // bare: @queryAll — [$this]. 빈 괄호 @queryAll() 는 타입에서 막는다
186
+ if (selectorOrTarget && (typeof optionsOrPropertyKey === 'string' || typeof optionsOrPropertyKey === 'symbol')) {
187
+ return query('$this', { pick: 'all' })(selectorOrTarget, optionsOrPropertyKey);
180
188
  }
181
189
  if (typeof selectorOrTarget === 'string' || typeof selectorOrTarget === 'function') {
182
190
  return query(selectorOrTarget, {...(optionsOrPropertyKey ?? {}), pick: 'all'});
@@ -235,9 +243,9 @@ export function queryAllAll(selector: string | QueryFnSelector, options?: QueryB
235
243
  * first/last/even/odd/all/number를 모두 지원하는 데코레이터를 생성한다.
236
244
  *
237
245
  * @example
238
- * @queryIn('shadow', 'even')('.item') // shadow DOM 짝수 인덱스들
239
- * @queryIn('light', 2)('.item') // light DOM 3번째 요소
240
- * @queryIn('all')('.item') // root all, pick 기본 first
246
+ * @(queryIn('shadow', 'even')('.item')) // shadow DOM 짝수 인덱스들 (호출이 이어지면 바깥 괄호 필요)
247
+ * @(queryIn('light', 2)('.item')) // light DOM 3번째 요소
248
+ * @(queryIn('all')('.item')) // root all, pick 기본 first
241
249
  */
242
250
  export const queryIn = (root: SwcRootType, pick?: QueryPick) =>
243
251
  (selector: string | QueryFnSelector, options?: QueryBaseOptions): PropertyDecorator =>
@@ -1,5 +1,5 @@
1
1
  import { ReflectUtils } from '@dooboostore/core';
2
- import { ensureInit, getElementConfig } from './elementDefine';
2
+ import { ensureInit } from './elementDefine';
3
3
  import { SwcUtils } from '../utils/Utils';
4
4
  import { ElementDefineLifeCycler, HelperHostSet } from '../types';
5
5
 
@@ -38,15 +38,7 @@ export interface RequestAnimationFrameMetadata {
38
38
  */
39
39
  export type FrameCallback = (timestamp: number, prevValue?: any) => any;
40
40
 
41
- const activeMap = new WeakMap<any, number[]>();
42
- const getActiveEntries = (inst: any): number[] => {
43
- let entries = activeMap.get(inst);
44
- if (!entries) {
45
- entries = [];
46
- activeMap.set(inst, entries);
47
- }
48
- return entries;
49
- };
41
+ const getActiveEntries = (inst: any): number[] => (inst.__swc_requestAnimationFrameIds ??= []);
50
42
 
51
43
  const startFrameLoop = (win: Window, entries: number[], frameFn: FrameCallback): number => {
52
44
  let currentId = 0;
@@ -94,10 +86,9 @@ const applyRequestAnimationFrame = (options: RequestAnimationFrameOptions, targe
94
86
 
95
87
  if (frameFn) {
96
88
  ensureInit(this);
97
- const conf = getElementConfig(this);
98
- const win = (this as any)._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as Window);
89
+ const win = SwcUtils.resolveWindow(this);
99
90
  const id = startFrameLoop(win, getActiveEntries(this), frameFn);
100
- normalizedOptions.created?.(SwcUtils.getHelperAndHostSet(win, this), id);
91
+ normalizedOptions.created?.(SwcUtils.getHelperAndHostSet(this), id);
101
92
  }
102
93
  return res;
103
94
  };
@@ -112,7 +103,7 @@ const applyRequestAnimationFrame = (options: RequestAnimationFrameOptions, targe
112
103
  *
113
104
  * 옵션 없이 `@requestAnimationFrame` 그대로 붙여도 되고, `@requestAnimationFrame({...})`처럼 옵션을 줄 수도 있다.
114
105
  */
115
- export function requestAnimationFrame(options?: RequestAnimationFrameOptions): MethodDecorator;
106
+ export function requestAnimationFrame(options: RequestAnimationFrameOptions): MethodDecorator;
116
107
  export function requestAnimationFrame(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
117
108
  export function requestAnimationFrame(optionsOrTarget?: RequestAnimationFrameOptions | Object, propertyKey?: string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
118
109
  if (propertyKey !== undefined) {
@@ -120,21 +111,21 @@ export function requestAnimationFrame(optionsOrTarget?: RequestAnimationFrameOpt
120
111
  applyRequestAnimationFrame({}, optionsOrTarget as Object, propertyKey, descriptor);
121
112
  return;
122
113
  }
123
- // 옵션과 함께: @requestAnimationFrame() 또는 @requestAnimationFrame({...})
114
+ // 옵션과 함께: @requestAnimationFrame({...})
124
115
  return (target: Object, propertyKey: string | symbol, descriptor?: PropertyDescriptor) => {
125
116
  return applyRequestAnimationFrame((optionsOrTarget as RequestAnimationFrameOptions) ?? {}, target, propertyKey, descriptor);
126
117
  };
127
118
  }
128
119
 
129
120
  export const findAllRequestAnimationFrameMetadata = (target: any): RequestAnimationFrameMetadata[] => {
130
- const constructor = target instanceof Function ? target : target.constructor;
121
+ const constructor = typeof target === 'function' ? target : target.constructor;
131
122
  return (ReflectUtils.findAllMetadata<RequestAnimationFrameMetadata[]>(REQUEST_ANIMATION_FRAME_METADATA_KEY, constructor) || []).flat();
132
123
  };
133
124
 
134
125
  export class RequestAnimationFrameLifeCycler implements ElementDefineLifeCycler {
135
126
  onConnected(helperHostSet: HelperHostSet): void {
136
127
  const inst = helperHostSet.$this;
137
- activeMap.delete(inst); // 재연결 대비 리셋
128
+ inst.__swc_requestAnimationFrameIds = []; // 재연결 대비 리셋
138
129
  const entries = getActiveEntries(inst);
139
130
  for (const meta of findAllRequestAnimationFrameMetadata(inst)) {
140
131
  if (meta.options.type !== 'onConnected') continue; // returnValue 타입은 수동 호출을 기다림
@@ -146,13 +137,13 @@ export class RequestAnimationFrameLifeCycler implements ElementDefineLifeCycler
146
137
 
147
138
  onDisconnected(helperHostSet: HelperHostSet): void {
148
139
  const inst = helperHostSet.$this;
149
- for (const id of activeMap.get(inst) ?? []) {
140
+ for (const id of inst.__swc_requestAnimationFrameIds ?? []) {
150
141
  try {
151
142
  helperHostSet.$w.cancelAnimationFrame(id);
152
143
  } catch (e) {
153
144
  console.error('[SWC] cancelAnimationFrame error:', e);
154
145
  }
155
146
  }
156
- activeMap.delete(inst);
147
+ inst.__swc_requestAnimationFrameIds = [];
157
148
  }
158
149
  }
@@ -1,10 +1,16 @@
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
  // 공통 옵션 — root·delegate 없음
5
6
  export interface ResizeObserverBaseOptions {
6
7
  box?: 'content-box' | 'border-box' | 'device-pixel-content-box';
7
- filter?: (matchedEls: HTMLElement[], meta: { currentThis: any, helper: HelperHostSet }) => boolean;
8
+ /** 매칭 시 핸들러 실행 여부 게이트. Promise<boolean>도 되어 async 판정 가능. false면 스킵. */
9
+ filter?: (matchedEls: HTMLElement[], meta: { currentThis: any, helper: HelperHostSet }) => boolean | Promise<boolean>;
10
+ /** filter 통과 후 핸들러 직전 훅. await되고, 리턴값은 @resizeObserverBeforeReturn 으로 핸들러에 주입된다. */
11
+ before?: (matchedEls: HTMLElement[], meta: { currentThis: any, helper: HelperHostSet }) => any | Promise<any>;
12
+ /** 핸들러가 성공/실패해도 항상 실행되는 정리 훅. ctx로 인자/결과/에러를 받는다. 에러는 로깅됨. */
13
+ finally?: (matchedEls: HTMLElement[], meta: { currentThis: any, helper: HelperHostSet }, ctx: { args: any[]; result?: any; error?: any }) => any | Promise<any>;
8
14
  removeObserver?: (target: Element, optionValue: ResizeObserverOptions) => void;
9
15
  }
10
16
 
@@ -28,7 +34,7 @@ export const RESIZE_OBSERVER_METADATA_KEY = Symbol.for('simple-web-component:res
28
34
 
29
35
  const applyResizeObserver = (selector: SwcSelector, options: ResizeObserverOptions, targetObj: Object, propertyKey: string | symbol): void => {
30
36
  const constructor = targetObj.constructor;
31
- let observers = ReflectUtils.getMetadata<ResizeObserverMetadata[]>(RESIZE_OBSERVER_METADATA_KEY, constructor);
37
+ let observers = ReflectUtils.getOwnMetadata(RESIZE_OBSERVER_METADATA_KEY, constructor) as ResizeObserverMetadata[] | undefined;
32
38
  if (!observers) {
33
39
  observers = [];
34
40
  ReflectUtils.defineMetadata(RESIZE_OBSERVER_METADATA_KEY, observers, constructor);
@@ -48,7 +54,7 @@ const resolveResizeObserverArgs = (
48
54
  };
49
55
 
50
56
  /**
51
- * bare(@decorator)와 factory(@decorator()/@decorator(...)) 호출을 모두 처리하는 공통 디스패처.
57
+ * bare(@decorator)와 factory(@decorator(...), 빈 괄호는 타입에서 막음) 호출을 모두 처리하는 공통 디스패처.
52
58
  * extra는 Light/Shadow/All/Delegate 변형이 강제로 덧씌우는 옵션(root, delegate 등)이다.
53
59
  */
54
60
  const dispatchResizeObserver = (
@@ -62,7 +68,7 @@ const dispatchResizeObserver = (
62
68
  applyResizeObserver('$this', { ...extra }, selectorOrOptionsOrTarget as Object, maybeOptionsOrPropertyKey);
63
69
  return;
64
70
  }
65
- // 옵션과 함께: @decorator() / @decorator(selector, options) / @decorator(options)
71
+ // 옵션과 함께: @decorator(selector, options) / @decorator(options)
66
72
  const { selector, options } = resolveResizeObserverArgs(
67
73
  selectorOrOptionsOrTarget as SwcSelector | ResizeObserverOptions | undefined,
68
74
  maybeOptionsOrPropertyKey as ResizeObserverOptions | undefined,
@@ -76,7 +82,7 @@ const dispatchResizeObserver = (
76
82
  export function resizeObserver(target: SpecialSelector, options?: ResizeObserverQueryOptions): MethodDecorator;
77
83
  export function resizeObserver(selector: string, options?: ResizeObserverQueryOptions): MethodDecorator;
78
84
  export function resizeObserver(selector: SwcFnSelector, options?: ResizeObserverNonQueryOptions): MethodDecorator;
79
- export function resizeObserver(options?: ResizeObserverQueryOptions): MethodDecorator;
85
+ export function resizeObserver(options: ResizeObserverQueryOptions): MethodDecorator;
80
86
  export function resizeObserver(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
81
87
  /**
82
88
  * @resizeObserver decorator to observe element size changes.
@@ -86,37 +92,32 @@ export function resizeObserver(selectorOrOptionsOrTarget?: SwcSelector | ResizeO
86
92
  return dispatchResizeObserver(selectorOrOptionsOrTarget, maybeOptionsOrPropertyKey, descriptor, {});
87
93
  }
88
94
 
89
- export function resizeObserverThis(options?: ResizeObserverQueryOptions): MethodDecorator;
90
- export function resizeObserverThis(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
91
- export function resizeObserverThis(optionsOrTarget?: ResizeObserverQueryOptions | Object, propertyKey?: string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
92
- return dispatchResizeObserver(optionsOrTarget, propertyKey, descriptor, {});
93
- }
94
95
 
95
96
  // ─── root별 delegate 헬퍼 (root 주입 → 문자열 셀렉터 전용) ───
96
97
 
97
98
  export function resizeObserverDelegateLight(selector: string, options?: Omit<ResizeObserverQueryOptions, 'delegate'>): MethodDecorator;
98
- export function resizeObserverDelegateLight(options?: Omit<ResizeObserverQueryOptions, 'delegate'>): MethodDecorator;
99
+ export function resizeObserverDelegateLight(options: Omit<ResizeObserverQueryOptions, 'delegate'>): MethodDecorator;
99
100
  export function resizeObserverDelegateLight(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
100
101
  export function resizeObserverDelegateLight(selectorOrOptionsOrTarget?: string | Omit<ResizeObserverQueryOptions, 'delegate'> | Object, maybeOptionsOrPropertyKey?: Omit<ResizeObserverQueryOptions, 'delegate'> | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
101
102
  return dispatchResizeObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'light', delegate: true });
102
103
  }
103
104
 
104
105
  export function resizeObserverDelegateShadow(selector: string, options?: Omit<ResizeObserverQueryOptions, 'delegate'>): MethodDecorator;
105
- export function resizeObserverDelegateShadow(options?: Omit<ResizeObserverQueryOptions, 'delegate'>): MethodDecorator;
106
+ export function resizeObserverDelegateShadow(options: Omit<ResizeObserverQueryOptions, 'delegate'>): MethodDecorator;
106
107
  export function resizeObserverDelegateShadow(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
107
108
  export function resizeObserverDelegateShadow(selectorOrOptionsOrTarget?: string | Omit<ResizeObserverQueryOptions, 'delegate'> | Object, maybeOptionsOrPropertyKey?: Omit<ResizeObserverQueryOptions, 'delegate'> | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
108
109
  return dispatchResizeObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'shadow', delegate: true });
109
110
  }
110
111
 
111
112
  export function resizeObserverDelegateAll(selector: string, options?: Omit<ResizeObserverQueryOptions, 'delegate'>): MethodDecorator;
112
- export function resizeObserverDelegateAll(options?: Omit<ResizeObserverQueryOptions, 'delegate'>): MethodDecorator;
113
+ export function resizeObserverDelegateAll(options: Omit<ResizeObserverQueryOptions, 'delegate'>): MethodDecorator;
113
114
  export function resizeObserverDelegateAll(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
114
115
  export function resizeObserverDelegateAll(selectorOrOptionsOrTarget?: string | Omit<ResizeObserverQueryOptions, 'delegate'> | Object, maybeOptionsOrPropertyKey?: Omit<ResizeObserverQueryOptions, 'delegate'> | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
115
116
  return dispatchResizeObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'all', delegate: true });
116
117
  }
117
118
 
118
119
  export function resizeObserverDelegate(selector: string, options?: Omit<ResizeObserverQueryOptions, 'delegate'>): MethodDecorator;
119
- export function resizeObserverDelegate(options?: Omit<ResizeObserverQueryOptions, 'delegate'>): MethodDecorator;
120
+ export function resizeObserverDelegate(options: Omit<ResizeObserverQueryOptions, 'delegate'>): MethodDecorator;
120
121
  export function resizeObserverDelegate(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
121
122
  export function resizeObserverDelegate(selectorOrOptionsOrTarget?: string | Omit<ResizeObserverQueryOptions, 'delegate'> | Object, maybeOptionsOrPropertyKey?: Omit<ResizeObserverQueryOptions, 'delegate'> | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
122
123
  return dispatchResizeObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'auto', delegate: true });
@@ -125,29 +126,29 @@ export function resizeObserverDelegate(selectorOrOptionsOrTarget?: string | Omit
125
126
  // ─── root별 일반 헬퍼 (delegate 없이, 셀렉터 생략 시 $this) ───
126
127
 
127
128
  export function resizeObserverLight(selector: string, options?: ResizeObserverQueryOptions): MethodDecorator;
128
- export function resizeObserverLight(options?: ResizeObserverQueryOptions): MethodDecorator;
129
+ export function resizeObserverLight(options: ResizeObserverQueryOptions): MethodDecorator;
129
130
  export function resizeObserverLight(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
130
131
  export function resizeObserverLight(selectorOrOptionsOrTarget?: string | ResizeObserverQueryOptions | Object, maybeOptionsOrPropertyKey?: ResizeObserverQueryOptions | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
131
132
  return dispatchResizeObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'light' });
132
133
  }
133
134
 
134
135
  export function resizeObserverShadow(selector: string, options?: ResizeObserverQueryOptions): MethodDecorator;
135
- export function resizeObserverShadow(options?: ResizeObserverQueryOptions): MethodDecorator;
136
+ export function resizeObserverShadow(options: ResizeObserverQueryOptions): MethodDecorator;
136
137
  export function resizeObserverShadow(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
137
138
  export function resizeObserverShadow(selectorOrOptionsOrTarget?: string | ResizeObserverQueryOptions | Object, maybeOptionsOrPropertyKey?: ResizeObserverQueryOptions | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
138
139
  return dispatchResizeObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'shadow' });
139
140
  }
140
141
 
141
142
  export function resizeObserverAll(selector: string, options?: ResizeObserverQueryOptions): MethodDecorator;
142
- export function resizeObserverAll(options?: ResizeObserverQueryOptions): MethodDecorator;
143
+ export function resizeObserverAll(options: ResizeObserverQueryOptions): MethodDecorator;
143
144
  export function resizeObserverAll(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
144
145
  export function resizeObserverAll(selectorOrOptionsOrTarget?: string | ResizeObserverQueryOptions | Object, maybeOptionsOrPropertyKey?: ResizeObserverQueryOptions | string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
145
146
  return dispatchResizeObserver(selectorOrOptionsOrTarget as any, maybeOptionsOrPropertyKey as any, descriptor, { root: 'all' });
146
147
  }
147
148
 
148
149
  export function getResizeObserverMetadata(target: any): ResizeObserverMetadata[] | undefined {
149
- const constructor = target instanceof Function ? target : target.constructor;
150
- return ReflectUtils.getMetadata(RESIZE_OBSERVER_METADATA_KEY, constructor);
150
+ const constructor = typeof target === 'function' ? target : target.constructor;
151
+ return ReflectUtils.findAllMetadata<any[]>(RESIZE_OBSERVER_METADATA_KEY, constructor).flat();
151
152
  }
152
153
 
153
154
  // ─────────────────────────────────────────────────────────────────────────────
@@ -156,20 +157,21 @@ export function getResizeObserverMetadata(target: any): ResizeObserverMetadata[]
156
157
  // elementDefine 이 수집된 ResizeObserverSet 으로 observer 를 생성하고,
157
158
  // observe/unobserve 함수를 주입해 MutationObserver delegate 추적이 사용할 수 있게 한다.
158
159
  // ─────────────────────────────────────────────────────────────────────────────
159
- import { ElementDefineLifeCycler, OnConnectedResult, ResizeObserverSet, ResizeObserverSetEntry } from '../types';
160
+ import { ElementDefineLifeCycler, inObserverScope, ObserverScope, OnConnectedResult, ResizeObserverSet, ResizeObserverSetEntry } from '../types';
160
161
  import { SwcUtils } from '../utils/Utils';
161
162
 
162
163
  export class ResizeObserverLifeCycler implements ElementDefineLifeCycler {
163
164
  private readonly removeObserverCallbacksMap = new WeakMap<Element, Array<{ fn: (target: Element, opts: unknown) => void; target: any; opts: unknown }>>();
164
165
 
165
- onConnected(helperHostSet: HelperHostSet): OnConnectedResult | void {
166
+ onConnected(helperHostSet: HelperHostSet, _set?: ResizeObserverSet, scope?: ObserverScope): OnConnectedResult | void {
166
167
  const inst = helperHostSet.$this;
167
168
  const currentWin = helperHostSet.$w;
168
169
 
169
- const removeObserverCallbacks: Array<{ fn: (target: Element, opts: unknown) => void; target: any; opts: unknown }> = [];
170
+ // 'rest' 는 같은 connect 의 'self' 뒤에 오므로 이어 붙이고, 그 외(새 connect)는 새로 시작한다.
171
+ const removeObserverCallbacks = (scope === 'rest' && this.removeObserverCallbacksMap.get(inst)) || [];
170
172
  this.removeObserverCallbacksMap.set(inst, removeObserverCallbacks);
171
173
 
172
- const allMeta = getResizeObserverMetadata(inst) ?? [];
174
+ const allMeta = (getResizeObserverMetadata(inst) ?? []).filter(m => inObserverScope(m, scope));
173
175
  if (allMeta.length === 0) return;
174
176
 
175
177
  const root: HTMLElement | ShadowRoot = inst.shadowRoot || inst;
@@ -179,6 +181,9 @@ export class ResizeObserverLifeCycler implements ElementDefineLifeCycler {
179
181
  if (m.options.removeObserver) removeObserverCallbacks.push({ fn: m.options.removeObserver, target: root, opts: m.options });
180
182
  }
181
183
 
184
+ // non-delegate 메타별 observe 대상 — 콜백은 모든 메타가 공유하므로, 엔트리를 자기 대상에만 배달한다.
185
+ const metaTargets = new Map<typeof allMeta[number], WeakSet<Element>>();
186
+
182
187
  // ── ResizeObserver 콜백 ──
183
188
  const callback: ResizeObserverSetEntry['callback'] = (entries, obs) => {
184
189
  for (const m of allMeta) {
@@ -191,14 +196,29 @@ export class ResizeObserverLifeCycler implements ElementDefineLifeCycler {
191
196
  return el.matches?.(m.selector as string) || !!el.closest?.(m.selector as string);
192
197
  });
193
198
  } else {
194
- matchedEls = entries.map(e => e.target as HTMLElement).filter(t => t && t.nodeType === 1);
199
+ const set = metaTargets.get(m);
200
+ matchedEls = entries.map(e => e.target as HTMLElement).filter(t => t && t.nodeType === 1 && !!set?.has(t));
195
201
  }
196
202
  if (matchedEls.length === 0) continue;
197
- if (m.options.filter) {
198
- if (!m.options.filter(matchedEls, { currentThis: inst, helper: helperHostSet })) continue;
199
- }
200
- const hostSet = SwcUtils.getHostSet(inst);
201
- inst[m.propertyKey](matchedEls, entries, obs, { ...hostSet, $root: root });
203
+ const opts = m.options;
204
+ void (async () => {
205
+ const helper = SwcUtils.getHelperAndHostSet(inst);
206
+ if (opts.filter && !(await opts.filter(matchedEls, { currentThis: inst, helper }))) return;
207
+ const hostSet = SwcUtils.getHostSet(inst);
208
+ const helperSet = SwcUtils.getHelperSet(helperHostSet.$w);
209
+ // entries 도 이 메서드 대상 것만 (옵저버는 공유라 배치에 다른 대상 엔트리가 섞인다)
210
+ const legacyArgs = [matchedEls, entries.filter(e => matchedEls.includes(e.target as HTMLElement)), obs, { ...hostSet, $root: root }];
211
+ const buildArgs = (beforeReturn: any) => buildSwcParameterArgs(inst, m.propertyKey, {
212
+ hostSet, helperHostSet: helper, helperSet, resizeObserverBeforeReturn: 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] resizeObserver handler error:', e));
202
222
  }
203
223
  };
204
224
 
@@ -235,6 +255,7 @@ export class ResizeObserverLifeCycler implements ElementDefineLifeCycler {
235
255
  }
236
256
  }
237
257
  }
258
+ metaTargets.set(m, new WeakSet(targets));
238
259
  for (const el of targets) resizeObserverSet.push({ target: el, options: m.options.box ? { box: m.options.box } : undefined, callback });
239
260
  }
240
261