@dooboostore/simple-web-component 1.0.47 → 1.0.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. package/README.md +223 -27
  2. package/dist/cjs/config/config.js +1 -1
  3. package/dist/cjs/config/config.js.map +2 -2
  4. package/dist/cjs/decorators/addEventListener.js +412 -16
  5. package/dist/cjs/decorators/addEventListener.js.map +3 -3
  6. package/dist/cjs/decorators/applyAttribute.js +25 -0
  7. package/dist/cjs/decorators/applyAttribute.js.map +2 -2
  8. package/dist/cjs/decorators/applyClass.js +49 -18
  9. package/dist/cjs/decorators/applyClass.js.map +3 -3
  10. package/dist/cjs/decorators/applyNode.js +67 -1
  11. package/dist/cjs/decorators/applyNode.js.map +3 -3
  12. package/dist/cjs/decorators/applyProperty.js +101 -3
  13. package/dist/cjs/decorators/applyProperty.js.map +2 -2
  14. package/dist/cjs/decorators/applyStyle.js +36 -5
  15. package/dist/cjs/decorators/applyStyle.js.map +2 -2
  16. package/dist/cjs/decorators/changedAttribute.js +39 -0
  17. package/dist/cjs/decorators/changedAttribute.js.map +2 -2
  18. package/dist/cjs/decorators/elementDefine.js +244 -225
  19. package/dist/cjs/decorators/elementDefine.js.map +3 -3
  20. package/dist/cjs/decorators/emitCustomEvent.js +55 -0
  21. package/dist/cjs/decorators/emitCustomEvent.js.map +2 -2
  22. package/dist/cjs/decorators/index.js +5 -1
  23. package/dist/cjs/decorators/index.js.map +2 -2
  24. package/dist/cjs/decorators/intersectionObserver.js +209 -0
  25. package/dist/cjs/decorators/intersectionObserver.js.map +7 -0
  26. package/dist/cjs/decorators/mutationObserver.js +244 -0
  27. package/dist/cjs/decorators/mutationObserver.js.map +7 -0
  28. package/dist/cjs/decorators/query.js +129 -102
  29. package/dist/cjs/decorators/query.js.map +2 -2
  30. package/dist/cjs/decorators/resizeObserver.js +191 -0
  31. package/dist/cjs/decorators/resizeObserver.js.map +7 -0
  32. package/dist/cjs/decorators/setInterval.js +82 -0
  33. package/dist/cjs/decorators/setInterval.js.map +7 -0
  34. package/dist/cjs/decorators/setTimeout.js +82 -0
  35. package/dist/cjs/decorators/setTimeout.js.map +7 -0
  36. package/dist/cjs/decorators/subscribeSwcAppMessageWhileConnected.js +9 -0
  37. package/dist/cjs/decorators/subscribeSwcAppMessageWhileConnected.js.map +2 -2
  38. package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js +9 -0
  39. package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +2 -2
  40. package/dist/cjs/examples/RxJSOperatorsExample.js +285 -0
  41. package/dist/cjs/examples/RxJSOperatorsExample.js.map +7 -0
  42. package/dist/cjs/types/index.js.map +1 -1
  43. package/dist/esm/config/config.js +1 -1
  44. package/dist/esm/config/config.js.map +2 -2
  45. package/dist/esm/decorators/addEventListener.js +413 -16
  46. package/dist/esm/decorators/addEventListener.js.map +3 -3
  47. package/dist/esm/decorators/applyAttribute.js +25 -0
  48. package/dist/esm/decorators/applyAttribute.js.map +2 -2
  49. package/dist/esm/decorators/applyClass.js +49 -18
  50. package/dist/esm/decorators/applyClass.js.map +3 -3
  51. package/dist/esm/decorators/applyNode.js +67 -1
  52. package/dist/esm/decorators/applyNode.js.map +3 -3
  53. package/dist/esm/decorators/applyProperty.js +101 -3
  54. package/dist/esm/decorators/applyProperty.js.map +2 -2
  55. package/dist/esm/decorators/applyStyle.js +36 -5
  56. package/dist/esm/decorators/applyStyle.js.map +2 -2
  57. package/dist/esm/decorators/changedAttribute.js +40 -0
  58. package/dist/esm/decorators/changedAttribute.js.map +2 -2
  59. package/dist/esm/decorators/elementDefine.js +249 -230
  60. package/dist/esm/decorators/elementDefine.js.map +3 -3
  61. package/dist/esm/decorators/emitCustomEvent.js +55 -0
  62. package/dist/esm/decorators/emitCustomEvent.js.map +2 -2
  63. package/dist/esm/decorators/index.js +5 -1
  64. package/dist/esm/decorators/index.js.map +2 -2
  65. package/dist/esm/decorators/intersectionObserver.js +191 -0
  66. package/dist/esm/decorators/intersectionObserver.js.map +7 -0
  67. package/dist/esm/decorators/mutationObserver.js +226 -0
  68. package/dist/esm/decorators/mutationObserver.js.map +7 -0
  69. package/dist/esm/decorators/query.js +129 -102
  70. package/dist/esm/decorators/query.js.map +2 -2
  71. package/dist/esm/decorators/resizeObserver.js +173 -0
  72. package/dist/esm/decorators/resizeObserver.js.map +7 -0
  73. package/dist/esm/decorators/setInterval.js +64 -0
  74. package/dist/esm/decorators/setInterval.js.map +7 -0
  75. package/dist/esm/decorators/setTimeout.js +64 -0
  76. package/dist/esm/decorators/setTimeout.js.map +7 -0
  77. package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js +9 -0
  78. package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js.map +2 -2
  79. package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js +9 -0
  80. package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +2 -2
  81. package/dist/esm/examples/RxJSOperatorsExample.js +266 -0
  82. package/dist/esm/examples/RxJSOperatorsExample.js.map +7 -0
  83. package/dist/esm/types/index.js.map +1 -1
  84. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +2413 -889
  85. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
  86. package/dist/types/config/config.d.ts.map +1 -1
  87. package/dist/types/decorators/addEventListener.d.ts +93 -23
  88. package/dist/types/decorators/addEventListener.d.ts.map +1 -1
  89. package/dist/types/decorators/applyAttribute.d.ts +22 -34
  90. package/dist/types/decorators/applyAttribute.d.ts.map +1 -1
  91. package/dist/types/decorators/applyClass.d.ts +34 -34
  92. package/dist/types/decorators/applyClass.d.ts.map +1 -1
  93. package/dist/types/decorators/applyNode.d.ts +30 -20
  94. package/dist/types/decorators/applyNode.d.ts.map +1 -1
  95. package/dist/types/decorators/applyProperty.d.ts +57 -34
  96. package/dist/types/decorators/applyProperty.d.ts.map +1 -1
  97. package/dist/types/decorators/applyStyle.d.ts +25 -12
  98. package/dist/types/decorators/applyStyle.d.ts.map +1 -1
  99. package/dist/types/decorators/changedAttribute.d.ts +11 -0
  100. package/dist/types/decorators/changedAttribute.d.ts.map +1 -1
  101. package/dist/types/decorators/elementDefine.d.ts.map +1 -1
  102. package/dist/types/decorators/emitCustomEvent.d.ts +28 -4
  103. package/dist/types/decorators/emitCustomEvent.d.ts.map +1 -1
  104. package/dist/types/decorators/index.d.ts +5 -1
  105. package/dist/types/decorators/index.d.ts.map +1 -1
  106. package/dist/types/decorators/intersectionObserver.d.ts +49 -0
  107. package/dist/types/decorators/intersectionObserver.d.ts.map +1 -0
  108. package/dist/types/decorators/mutationObserver.d.ts +46 -0
  109. package/dist/types/decorators/mutationObserver.d.ts.map +1 -0
  110. package/dist/types/decorators/query.d.ts +63 -8
  111. package/dist/types/decorators/query.d.ts.map +1 -1
  112. package/dist/types/decorators/resizeObserver.d.ts +48 -0
  113. package/dist/types/decorators/resizeObserver.d.ts.map +1 -0
  114. package/dist/types/decorators/setInterval.d.ts +29 -0
  115. package/dist/types/decorators/setInterval.d.ts.map +1 -0
  116. package/dist/types/decorators/setTimeout.d.ts +29 -0
  117. package/dist/types/decorators/setTimeout.d.ts.map +1 -0
  118. package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts +7 -1
  119. package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts.map +1 -1
  120. package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts +6 -0
  121. package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts.map +1 -1
  122. package/dist/types/examples/RxJSOperatorsExample.d.ts +94 -0
  123. package/dist/types/examples/RxJSOperatorsExample.d.ts.map +1 -0
  124. package/dist/types/types/index.d.ts +104 -0
  125. package/dist/types/types/index.d.ts.map +1 -1
  126. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +2413 -889
  127. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
  128. package/package.json +8 -6
  129. package/src/config/config.ts +1 -1
  130. package/src/decorators/addEventListener.ts +426 -23
  131. package/src/decorators/applyAttribute.ts +50 -36
  132. package/src/decorators/applyClass.ts +76 -26
  133. package/src/decorators/applyNode.ts +114 -36
  134. package/src/decorators/applyProperty.ts +152 -40
  135. package/src/decorators/applyStyle.ts +64 -17
  136. package/src/decorators/changedAttribute.ts +46 -0
  137. package/src/decorators/elementDefine.ts +301 -317
  138. package/src/decorators/emitCustomEvent.ts +73 -5
  139. package/src/decorators/index.ts +5 -1
  140. package/src/decorators/intersectionObserver.ts +259 -0
  141. package/src/decorators/mutationObserver.ts +304 -0
  142. package/src/decorators/query.ts +182 -117
  143. package/src/decorators/resizeObserver.ts +235 -0
  144. package/src/decorators/setInterval.ts +80 -0
  145. package/src/decorators/setTimeout.ts +80 -0
  146. package/src/decorators/subscribeSwcAppMessageWhileConnected.ts +17 -0
  147. package/src/decorators/subscribeSwcAppRouteChangeWhileConnected.ts +19 -0
  148. package/src/examples/RxJSOperatorsExample.ts +279 -0
  149. package/src/types/index.ts +141 -0
  150. package/dist/cjs/decorators/queryAll.js +0 -181
  151. package/dist/cjs/decorators/queryAll.js.map +0 -7
  152. package/dist/cjs/elements/tt/SwcAppMixin.js +0 -1
  153. package/dist/cjs/elements/tt/SwcAppMixin.js.map +0 -7
  154. package/dist/cjs/elements/tt/SwcAsync.js +0 -1
  155. package/dist/cjs/elements/tt/SwcAsync.js.map +0 -7
  156. package/dist/cjs/elements/tt/SwcAsyncTemplate.js +0 -1
  157. package/dist/cjs/elements/tt/SwcAsyncTemplate.js.map +0 -7
  158. package/dist/cjs/elements/tt/SwcChoose.js +0 -1
  159. package/dist/cjs/elements/tt/SwcChoose.js.map +0 -7
  160. package/dist/cjs/elements/tt/SwcChooseTemplate.js +0 -1
  161. package/dist/cjs/elements/tt/SwcChooseTemplate.js.map +0 -7
  162. package/dist/cjs/elements/tt/SwcIf.js +0 -1
  163. package/dist/cjs/elements/tt/SwcIf.js.map +0 -7
  164. package/dist/cjs/elements/tt/SwcIfTemplate.js +0 -1
  165. package/dist/cjs/elements/tt/SwcIfTemplate.js.map +0 -7
  166. package/dist/cjs/elements/tt/SwcLoop.js +0 -1
  167. package/dist/cjs/elements/tt/SwcLoop.js.map +0 -7
  168. package/dist/cjs/elements/tt/SwcLoopTemplate.js +0 -1
  169. package/dist/cjs/elements/tt/SwcLoopTemplate.js.map +0 -7
  170. package/dist/cjs/elements/tt/SwcSubTemplates.js +0 -1
  171. package/dist/cjs/elements/tt/SwcSubTemplates.js.map +0 -7
  172. package/dist/cjs/elements/tt/register.js +0 -1
  173. package/dist/cjs/elements/tt/register.js.map +0 -7
  174. package/dist/esm/decorators/queryAll.js +0 -162
  175. package/dist/esm/decorators/queryAll.js.map +0 -7
  176. package/dist/esm/elements/tt/SwcAppMixin.js +0 -1
  177. package/dist/esm/elements/tt/SwcAppMixin.js.map +0 -7
  178. package/dist/esm/elements/tt/SwcAsync.js +0 -1
  179. package/dist/esm/elements/tt/SwcAsync.js.map +0 -7
  180. package/dist/esm/elements/tt/SwcAsyncTemplate.js +0 -1
  181. package/dist/esm/elements/tt/SwcAsyncTemplate.js.map +0 -7
  182. package/dist/esm/elements/tt/SwcChoose.js +0 -1
  183. package/dist/esm/elements/tt/SwcChoose.js.map +0 -7
  184. package/dist/esm/elements/tt/SwcChooseTemplate.js +0 -1
  185. package/dist/esm/elements/tt/SwcChooseTemplate.js.map +0 -7
  186. package/dist/esm/elements/tt/SwcIf.js +0 -1
  187. package/dist/esm/elements/tt/SwcIf.js.map +0 -7
  188. package/dist/esm/elements/tt/SwcIfTemplate.js +0 -1
  189. package/dist/esm/elements/tt/SwcIfTemplate.js.map +0 -7
  190. package/dist/esm/elements/tt/SwcLoop.js +0 -1
  191. package/dist/esm/elements/tt/SwcLoop.js.map +0 -7
  192. package/dist/esm/elements/tt/SwcLoopTemplate.js +0 -1
  193. package/dist/esm/elements/tt/SwcLoopTemplate.js.map +0 -7
  194. package/dist/esm/elements/tt/SwcSubTemplates.js +0 -1
  195. package/dist/esm/elements/tt/SwcSubTemplates.js.map +0 -7
  196. package/dist/esm/elements/tt/register.js +0 -1
  197. package/dist/esm/elements/tt/register.js.map +0 -7
  198. package/dist/types/decorators/queryAll.d.ts +0 -22
  199. package/dist/types/decorators/queryAll.d.ts.map +0 -1
  200. package/dist/types/elements/tt/SwcAppMixin.d.ts +0 -1
  201. package/dist/types/elements/tt/SwcAppMixin.d.ts.map +0 -1
  202. package/dist/types/elements/tt/SwcAsync.d.ts +0 -1
  203. package/dist/types/elements/tt/SwcAsync.d.ts.map +0 -1
  204. package/dist/types/elements/tt/SwcAsyncTemplate.d.ts +0 -1
  205. package/dist/types/elements/tt/SwcAsyncTemplate.d.ts.map +0 -1
  206. package/dist/types/elements/tt/SwcChoose.d.ts +0 -1
  207. package/dist/types/elements/tt/SwcChoose.d.ts.map +0 -1
  208. package/dist/types/elements/tt/SwcChooseTemplate.d.ts +0 -1
  209. package/dist/types/elements/tt/SwcChooseTemplate.d.ts.map +0 -1
  210. package/dist/types/elements/tt/SwcIf.d.ts +0 -1
  211. package/dist/types/elements/tt/SwcIf.d.ts.map +0 -1
  212. package/dist/types/elements/tt/SwcIfTemplate.d.ts +0 -1
  213. package/dist/types/elements/tt/SwcIfTemplate.d.ts.map +0 -1
  214. package/dist/types/elements/tt/SwcLoop.d.ts +0 -1
  215. package/dist/types/elements/tt/SwcLoop.d.ts.map +0 -1
  216. package/dist/types/elements/tt/SwcLoopTemplate.d.ts +0 -1
  217. package/dist/types/elements/tt/SwcLoopTemplate.d.ts.map +0 -1
  218. package/dist/types/elements/tt/SwcSubTemplates.d.ts +0 -1
  219. package/dist/types/elements/tt/SwcSubTemplates.d.ts.map +0 -1
  220. package/dist/types/elements/tt/register.d.ts +0 -1
  221. package/dist/types/elements/tt/register.d.ts.map +0 -1
  222. package/src/decorators/queryAll.ts +0 -186
  223. package/src/elements/tt/SwcAppMixin.ts +0 -13
  224. package/src/elements/tt/SwcAsync.ts +0 -139
  225. package/src/elements/tt/SwcAsyncTemplate.ts +0 -126
  226. package/src/elements/tt/SwcChoose.ts +0 -182
  227. package/src/elements/tt/SwcChooseTemplate.ts +0 -229
  228. package/src/elements/tt/SwcIf.ts +0 -145
  229. package/src/elements/tt/SwcIfTemplate.ts +0 -158
  230. package/src/elements/tt/SwcLoop.ts +0 -222
  231. package/src/elements/tt/SwcLoopTemplate.ts +0 -255
  232. package/src/elements/tt/SwcSubTemplates.ts +0 -6
  233. package/src/elements/tt/register.ts +0 -720
@@ -1,9 +1,10 @@
1
1
  import {ReflectUtils} from '@dooboostore/core';
2
- import { SpecialSelector, SwcQueryOptions, HelperHostSet } from '../types';
2
+ import { SpecialSelector, SwcQueryOptions, SwcFnSelector, SwcSelector, HelperHostSet } from '../types';
3
3
  import {ensureInit, getElementConfig} from './elementDefine';
4
4
  import {SwcUtils} from '../utils/Utils';
5
5
 
6
- export type EmitCustomEventSelector = string | ((currentThis: any, helper: HelperHostSet) => NodeList | Element | Element[] | null);
6
+ export type EmitCustomEventFnSelector = SwcFnSelector;
7
+ export type EmitCustomEventSelector = SwcSelector;
7
8
 
8
9
  export interface EmitCustomEventBaseOptions {
9
10
  bubbles?: boolean;
@@ -30,6 +31,13 @@ export interface EmitCustomEventBaseOptions {
30
31
 
31
32
  type Options = (EmitCustomEventBaseOptions & SwcQueryOptions) | (EmitCustomEventBaseOptions & SwcQueryOptions & { attributeName?: string });
32
33
 
34
+ // 문자열 셀렉터 전용 — root 허용
35
+ export type EmitCustomEventQueryOptions = Options;
36
+ // 함수 셀렉터 전용 — root 금지
37
+ export type EmitCustomEventNonQueryOptions = EmitCustomEventBaseOptions | (EmitCustomEventBaseOptions & { attributeName?: string });
38
+ // 셀렉터 종류에 따라 옵션 타입 분기
39
+ export type EmitCustomEventOptionsOf<S extends EmitCustomEventSelector> = S extends string ? EmitCustomEventQueryOptions : EmitCustomEventNonQueryOptions;
40
+
33
41
  export interface EmitCustomEventMetadata {
34
42
  propertyKey: string | symbol;
35
43
  selector: EmitCustomEventSelector;
@@ -39,9 +47,10 @@ export interface EmitCustomEventMetadata {
39
47
 
40
48
  export const EMIT_CUSTOM_EVENT_METADATA_KEY = Symbol.for('simple-web-component:emit-custom-event');
41
49
 
50
+ export function emitCustomEvent(selector: string, type: string, options?: EmitCustomEventQueryOptions): MethodDecorator;
51
+ export function emitCustomEvent(selector: EmitCustomEventFnSelector, type: string, options?: EmitCustomEventNonQueryOptions): MethodDecorator;
52
+ export function emitCustomEvent(type: string, options?: EmitCustomEventQueryOptions): MethodDecorator;
42
53
  export function emitCustomEvent(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
43
- export function emitCustomEvent(selector: EmitCustomEventSelector, type: string, options?: Options): MethodDecorator;
44
- export function emitCustomEvent(type: string, options?: Options): MethodDecorator;
45
54
  /**
46
55
  * @emitCustomEvent decorator to dispatch custom events to a target.
47
56
  *
@@ -108,7 +117,7 @@ function createEmitDecorator(selector: EmitCustomEventSelector, type: string, op
108
117
  const eventTargets: EventTarget[] = [];
109
118
 
110
119
  // Resolve selector if it's a function
111
- let resolvedSelector: string | Element | NodeList | Element[] | null = selector as any;
120
+ let resolvedSelector: string | Node | Element | NodeList | Element[] | null = selector as any;
112
121
  if (typeof selector === 'function') {
113
122
  resolvedSelector = selector(this, hostSet);
114
123
  }
@@ -191,3 +200,62 @@ export const getEmitCustomEventMetadataList = (target: any): EmitCustomEventMeta
191
200
 
192
201
  // --- Aliases: emit... ---
193
202
  export const emit = emitCustomEvent;
203
+
204
+ // ─── 편의 헬퍼 (selector/root 생략) ───
205
+
206
+ export function emitThis(type: string, options?: EmitCustomEventQueryOptions): MethodDecorator {
207
+ return emitCustomEvent('$this', type, options);
208
+ }
209
+ export function emitAppHost(type: string, options?: EmitCustomEventQueryOptions): MethodDecorator {
210
+ return emitCustomEvent('$appHost', type, options);
211
+ }
212
+ export function emitWindow(type: string, options?: EmitCustomEventQueryOptions): MethodDecorator {
213
+ return emitCustomEvent('$window', type, options);
214
+ }
215
+ export function emitDocument(type: string, options?: EmitCustomEventQueryOptions): MethodDecorator {
216
+ return emitCustomEvent('$document', type, options);
217
+ }
218
+ export function emitLight(selector: string, type: string, options?: Omit<EmitCustomEventQueryOptions, 'root'>): MethodDecorator {
219
+ return emitCustomEvent(selector, type, {...options ?? {}, root: 'light'} as any);
220
+ }
221
+ export function emitShadow(selector: string, type: string, options?: Omit<EmitCustomEventQueryOptions, 'root'>): MethodDecorator {
222
+ return emitCustomEvent(selector, type, {...options ?? {}, root: 'shadow'} as any);
223
+ }
224
+ export function emitAll(selector: string, type: string, options?: Omit<EmitCustomEventQueryOptions, 'root'>): MethodDecorator {
225
+ return emitCustomEvent(selector, type, {...options ?? {}, root: 'all'} as any);
226
+ }
227
+
228
+ // ─────────────────────────────────────────────────────────────────────────────
229
+ // EmitCustomEventLifeCycler
230
+ // ─────────────────────────────────────────────────────────────────────────────
231
+ import { ElementDefineLifeCycler } from '../types';
232
+
233
+ export class EmitCustomEventLifeCycler implements ElementDefineLifeCycler {
234
+ private hostEmitMeta: EmitCustomEventMetadata[] | null = null;
235
+
236
+ private getHostEmitMeta(inst: any): EmitCustomEventMetadata[] {
237
+ if (!this.hostEmitMeta) {
238
+ const all = getEmitCustomEventMetadataList(inst) ?? [];
239
+ this.hostEmitMeta = all.filter(m => m.selector === '$this' || m.selector === '');
240
+ }
241
+ return this.hostEmitMeta;
242
+ }
243
+
244
+ /** observedAttributes 에 포함할 attributeName 목록 */
245
+ getObservedAttributeNames(inst: any): string[] {
246
+ return this.getHostEmitMeta(inst).map(m => (m.options as any).attributeName).filter(Boolean) as string[];
247
+ }
248
+
249
+ onConnected(_helperHostSet: HelperHostSet): void {
250
+ // emit 처리는 descriptor.value 래핑으로 이미 완료. connected 시 별도 작업 없음
251
+ }
252
+
253
+ /** attributeChangedCallback 에서 elementDefine 이 직접 호출 */
254
+ onAttributeChanged(helperHostSet: HelperHostSet, name: string, _old: string | null, newVal: string | null): void {
255
+ const inst = helperHostSet.$this;
256
+ const matched = this.getHostEmitMeta(inst).find(m => (m.options as any).attributeName === name);
257
+ if (matched && newVal !== null) {
258
+ inst._bindAttributeEvent?.(inst, name, newVal, matched.type);
259
+ }
260
+ }
261
+ }
@@ -1,4 +1,7 @@
1
1
  export * from './addEventListener';
2
+ export * from './mutationObserver';
3
+ export * from './resizeObserver';
4
+ export * from './intersectionObserver';
2
5
  export * from './applyAttribute';
3
6
  export * from './elementDefine';
4
7
  export * from './changedAttribute';
@@ -6,7 +9,6 @@ export * from './emitCustomEvent';
6
9
  export * from './applyNode';
7
10
  export * from './lifecycles';
8
11
  export * from './query';
9
- export * from './queryAll';
10
12
  export * from './applyClass';
11
13
  export * from './applyStyle';
12
14
  export * from './applyAttribute';
@@ -16,3 +18,5 @@ export * from './subscribeSwcAppMessageWhileConnected';
16
18
  export * from './publishSwcAppMessage';
17
19
  export * from './applySlot';
18
20
  export * from './state';
21
+ export * from './setInterval';
22
+ export * from './setTimeout';
@@ -0,0 +1,259 @@
1
+ import { ReflectUtils } from '@dooboostore/core';
2
+ import { SpecialSelector, SwcQueryOptions, SwcFnSelector, SwcSelector, HelperHostSet } from '../types';
3
+
4
+ // 공통 옵션 — IntersectionObserverInit + filter/removeObserver. root·delegate 제외.
5
+ // 주의: 데코레이터의 root(light/shadow/all/auto) 는 셀렉터 스코프 선택용이다.
6
+ // IntersectionObserver 의 스크롤 컨테이너 root 는 intersectionRoot 로 지정한다.
7
+ export interface IntersectionObserverBaseOptions extends Omit<IntersectionObserverInit, 'root'> {
8
+ /** IntersectionObserver 의 스크롤 컨테이너 (viewport 대신). 데코레이터 root 와 혼동 주의. */
9
+ intersectionRoot?: Element | Document;
10
+ filter?: (matchedEls: HTMLElement[], meta: { currentThis: any, helper: HelperHostSet }) => boolean;
11
+ removeObserver?: (target: Element, optionValue: IntersectionObserverQueryOptions) => void;
12
+ }
13
+
14
+ // 문자열 셀렉터 전용 — root·delegate 허용
15
+ export type IntersectionObserverQueryOptions = IntersectionObserverBaseOptions & SwcQueryOptions & { delegate?: boolean };
16
+ // 함수 셀렉터 전용 — root·delegate 금지
17
+ export type IntersectionObserverNonQueryOptions = IntersectionObserverBaseOptions;
18
+ // 내부 저장/해석용
19
+ export type IntersectionObserverOptions = IntersectionObserverQueryOptions;
20
+
21
+ // 셀렉터 종류에 따라 옵션 타입 분기
22
+ export type IntersectionObserverOptionsOf<S extends SwcSelector> = S extends string ? IntersectionObserverQueryOptions : IntersectionObserverNonQueryOptions;
23
+
24
+ export interface IntersectionObserverMetadata {
25
+ propertyKey: string | symbol;
26
+ selector: SwcSelector;
27
+ options: IntersectionObserverOptions;
28
+ }
29
+
30
+ export const INTERSECTION_OBSERVER_METADATA_KEY = Symbol.for('simple-web-component:intersection-observer');
31
+
32
+ export function intersectionObserver(target: SpecialSelector, options?: IntersectionObserverQueryOptions): MethodDecorator;
33
+ export function intersectionObserver(selector: string, options?: IntersectionObserverQueryOptions): MethodDecorator;
34
+ export function intersectionObserver(selector: SwcFnSelector, options?: IntersectionObserverNonQueryOptions): MethodDecorator;
35
+ export function intersectionObserver(options?: IntersectionObserverQueryOptions): MethodDecorator;
36
+ /**
37
+ * @intersectionObserver decorator to observe element intersection changes.
38
+ *
39
+ * IntersectionObserver 는 생성 시점에 옵션(threshold/rootMargin/root)이 고정되므로,
40
+ * 옵션별로 그룹을 만들어 observer 를 생성한다. 같은 옵션 그룹 안에서 delegate 동적 추적이 가능하다.
41
+ */
42
+ export function intersectionObserver(selectorOrOptions?: SwcSelector | IntersectionObserverOptions, maybeOptions?: IntersectionObserverOptions): MethodDecorator {
43
+ return (targetObj: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
44
+ let selector: SwcSelector = '$this';
45
+ let options: IntersectionObserverOptions = {};
46
+
47
+ if (typeof selectorOrOptions === 'string' || typeof selectorOrOptions === 'function') {
48
+ selector = selectorOrOptions;
49
+ options = maybeOptions ?? {};
50
+ } else {
51
+ selector = '$this';
52
+ options = selectorOrOptions ?? {};
53
+ }
54
+
55
+ const constructor = targetObj.constructor;
56
+
57
+ let observers = ReflectUtils.getMetadata<IntersectionObserverMetadata[]>(INTERSECTION_OBSERVER_METADATA_KEY, constructor);
58
+ if (!observers) {
59
+ observers = [];
60
+ ReflectUtils.defineMetadata(INTERSECTION_OBSERVER_METADATA_KEY, observers, constructor);
61
+ }
62
+
63
+ observers.push({ propertyKey, selector, options });
64
+ };
65
+ }
66
+
67
+ export function intersectionObserverThis(options?: IntersectionObserverQueryOptions): MethodDecorator {
68
+ return intersectionObserver('$this', options);
69
+ }
70
+
71
+ // ─── root별 delegate 헬퍼 (root 주입 → 문자열 셀렉터 전용) ───
72
+
73
+ export function intersectionObserverDelegateLight(selector: string, options?: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator;
74
+ export function intersectionObserverDelegateLight(options?: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator;
75
+ export function intersectionObserverDelegateLight(selectorOrOptions?: string | Omit<IntersectionObserverQueryOptions, 'delegate'>, maybeOptions?: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator {
76
+ if (typeof selectorOrOptions === 'string' || typeof selectorOrOptions === 'function') {
77
+ return intersectionObserver(selectorOrOptions as any, {...maybeOptions ?? {}, root: 'light', delegate: true});
78
+ }
79
+ return intersectionObserver({...selectorOrOptions ?? {}, root: 'light', delegate: true});
80
+ }
81
+
82
+ export function intersectionObserverDelegateShadow(selector: string, options?: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator;
83
+ export function intersectionObserverDelegateShadow(options?: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator;
84
+ export function intersectionObserverDelegateShadow(selectorOrOptions?: string | Omit<IntersectionObserverQueryOptions, 'delegate'>, maybeOptions?: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator {
85
+ if (typeof selectorOrOptions === 'string' || typeof selectorOrOptions === 'function') {
86
+ return intersectionObserver(selectorOrOptions as any, {...maybeOptions ?? {}, root: 'shadow', delegate: true});
87
+ }
88
+ return intersectionObserver({...selectorOrOptions ?? {}, root: 'shadow', delegate: true});
89
+ }
90
+
91
+ export function intersectionObserverDelegateAll(selector: string, options?: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator;
92
+ export function intersectionObserverDelegateAll(options?: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator;
93
+ export function intersectionObserverDelegateAll(selectorOrOptions?: string | Omit<IntersectionObserverQueryOptions, 'delegate'>, maybeOptions?: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator {
94
+ if (typeof selectorOrOptions === 'string' || typeof selectorOrOptions === 'function') {
95
+ return intersectionObserver(selectorOrOptions as any, {...maybeOptions ?? {}, root: 'all', delegate: true});
96
+ }
97
+ return intersectionObserver({...selectorOrOptions ?? {}, root: 'all', delegate: true});
98
+ }
99
+
100
+ export function intersectionObserverDelegate(selector: string, options?: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator;
101
+ export function intersectionObserverDelegate(options?: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator;
102
+ export function intersectionObserverDelegate(selectorOrOptions?: string | Omit<IntersectionObserverQueryOptions, 'delegate'>, maybeOptions?: Omit<IntersectionObserverQueryOptions, 'delegate'>): MethodDecorator {
103
+ if (typeof selectorOrOptions === 'string' || typeof selectorOrOptions === 'function') {
104
+ return intersectionObserver(selectorOrOptions as any, {...maybeOptions ?? {}, root: 'auto', delegate: true});
105
+ }
106
+ return intersectionObserver({...selectorOrOptions ?? {}, root: 'auto', delegate: true});
107
+ }
108
+
109
+ // ─── root별 일반 헬퍼 (delegate 없이, 셀렉터 생략 시 $this) ───
110
+
111
+ export function intersectionObserverLight(selector: string, options?: IntersectionObserverQueryOptions): MethodDecorator;
112
+ export function intersectionObserverLight(options?: IntersectionObserverQueryOptions): MethodDecorator;
113
+ export function intersectionObserverLight(selectorOrOptions?: string | IntersectionObserverQueryOptions, maybeOptions?: IntersectionObserverQueryOptions): MethodDecorator {
114
+ if (typeof selectorOrOptions === 'string' || typeof selectorOrOptions === 'function') {
115
+ return intersectionObserver(selectorOrOptions as any, {...maybeOptions ?? {}, root: 'light'});
116
+ }
117
+ return intersectionObserver({...selectorOrOptions ?? {}, root: 'light'});
118
+ }
119
+
120
+ export function intersectionObserverShadow(selector: string, options?: IntersectionObserverQueryOptions): MethodDecorator;
121
+ export function intersectionObserverShadow(options?: IntersectionObserverQueryOptions): MethodDecorator;
122
+ export function intersectionObserverShadow(selectorOrOptions?: string | IntersectionObserverQueryOptions, maybeOptions?: IntersectionObserverQueryOptions): MethodDecorator {
123
+ if (typeof selectorOrOptions === 'string' || typeof selectorOrOptions === 'function') {
124
+ return intersectionObserver(selectorOrOptions as any, {...maybeOptions ?? {}, root: 'shadow'});
125
+ }
126
+ return intersectionObserver({...selectorOrOptions ?? {}, root: 'shadow'});
127
+ }
128
+
129
+ export function intersectionObserverAll(selector: string, options?: IntersectionObserverQueryOptions): MethodDecorator;
130
+ export function intersectionObserverAll(options?: IntersectionObserverQueryOptions): MethodDecorator;
131
+ export function intersectionObserverAll(selectorOrOptions?: string | IntersectionObserverQueryOptions, maybeOptions?: IntersectionObserverQueryOptions): MethodDecorator {
132
+ if (typeof selectorOrOptions === 'string' || typeof selectorOrOptions === 'function') {
133
+ return intersectionObserver(selectorOrOptions as any, {...maybeOptions ?? {}, root: 'all'});
134
+ }
135
+ return intersectionObserver({...selectorOrOptions ?? {}, root: 'all'});
136
+ }
137
+
138
+ export function getIntersectionObserverMetadata(target: any): IntersectionObserverMetadata[] | undefined {
139
+ const constructor = target instanceof Function ? target : target.constructor;
140
+ return ReflectUtils.getMetadata(INTERSECTION_OBSERVER_METADATA_KEY, constructor);
141
+ }
142
+
143
+ // ─────────────────────────────────────────────────────────────────────────────
144
+ // IntersectionObserverLifeCycler
145
+ // observer 를 직접 생성하지 않고 옵션 그룹 배열(IntersectionObserverSet)을 반환한다.
146
+ // elementDefine 이 그룹별로 observer 를 생성한다.
147
+ // ─────────────────────────────────────────────────────────────────────────────
148
+ import { ElementDefineLifeCycler, OnConnectedResult, IntersectionObserverSet, IntersectionObserverGroup, IntersectionObserverSetEntry } from '../types';
149
+ import { SwcUtils } from '../utils/Utils';
150
+
151
+ export class IntersectionObserverLifeCycler implements ElementDefineLifeCycler {
152
+ private readonly removeObserverCallbacksMap = new WeakMap<Element, Array<{ fn: (target: Element, opts: unknown) => void; target: any; opts: unknown }>>();
153
+
154
+ onConnected(helperHostSet: HelperHostSet): OnConnectedResult | void {
155
+ const inst = helperHostSet.$this;
156
+ const currentWin = helperHostSet.$w;
157
+
158
+ const removeObserverCallbacks: Array<{ fn: (target: Element, opts: unknown) => void; target: any; opts: unknown }> = [];
159
+ this.removeObserverCallbacksMap.set(inst, removeObserverCallbacks);
160
+
161
+ const allMeta = getIntersectionObserverMetadata(inst) ?? [];
162
+ if (allMeta.length === 0) return;
163
+
164
+ const root: HTMLElement | ShadowRoot = inst.shadowRoot || inst;
165
+
166
+ // removeObserver 콜백 수집
167
+ for (const m of allMeta) {
168
+ if (m.options.removeObserver) removeObserverCallbacks.push({ fn: m.options.removeObserver, target: root, opts: m.options });
169
+ }
170
+
171
+ // ── IntersectionObserver 콜백 ──
172
+ const buildCallback = (metas: IntersectionObserverMetadata[]): IntersectionObserverSetEntry['callback'] => {
173
+ return (entries, obs) => {
174
+ for (const m of metas) {
175
+ let matchedEls: HTMLElement[];
176
+ if (m.options.delegate && typeof m.selector === 'string') {
177
+ const isThis = m.selector === '$this' || m.selector === '';
178
+ matchedEls = entries.map(e => e.target as HTMLElement).filter(el => {
179
+ if (!el || el.nodeType !== 1) return false;
180
+ if (isThis) return true;
181
+ return el.matches?.(m.selector as string) || !!el.closest?.(m.selector as string);
182
+ });
183
+ } else {
184
+ matchedEls = entries.map(e => e.target as HTMLElement).filter(t => t && t.nodeType === 1);
185
+ }
186
+ if (matchedEls.length === 0) continue;
187
+ if (m.options.filter) {
188
+ if (!m.options.filter(matchedEls, { currentThis: inst, helper: helperHostSet })) continue;
189
+ }
190
+ const hostSet = SwcUtils.getHostSet(inst);
191
+ inst[m.propertyKey](matchedEls, entries, obs, { ...hostSet, $root: root });
192
+ }
193
+ };
194
+ };
195
+
196
+ // ── 옵션별 그룹핑: 같은 observer 옵션(threshold/rootMargin/intersectionRoot)끼리 묶는다 ──
197
+ // delegate:true 항목은 동적 추적용 셀렉터 문자열로 선언된다.
198
+ const groups = new Map<string, { options: IntersectionObserverInit; metas: IntersectionObserverMetadata[] }>();
199
+ for (const m of allMeta) {
200
+ const obsOptions: IntersectionObserverInit = {
201
+ root: m.options.intersectionRoot ?? null,
202
+ rootMargin: m.options.rootMargin,
203
+ threshold: m.options.threshold,
204
+ };
205
+ const key = JSON.stringify([obsOptions.root, obsOptions.rootMargin, obsOptions.threshold]);
206
+ if (!groups.has(key)) groups.set(key, { options: obsOptions, metas: [] });
207
+ groups.get(key)!.metas.push(m);
208
+ }
209
+
210
+ const intersectionObserverSet: IntersectionObserverSet = [];
211
+ for (const [, group] of groups) {
212
+ const callback = buildCallback(group.metas);
213
+ const observeTargets: IntersectionObserverGroup['observeTargets'] = [];
214
+
215
+ for (const m of group.metas) {
216
+ if (m.options.delegate && typeof m.selector === 'string') {
217
+ observeTargets.push({ target: m.selector, delegate: true, delegateRoot: m.options.root, callback });
218
+ continue;
219
+ }
220
+ let targets: HTMLElement[] = [];
221
+
222
+ if (typeof m.selector === 'function') {
223
+ const res = (m.selector as any)(inst, helperHostSet);
224
+ if (res instanceof currentWin.HTMLElement) targets = [res as HTMLElement];
225
+ else if (res instanceof currentWin.NodeList) targets = Array.from(res as NodeList).filter((e: any) => e instanceof currentWin.HTMLElement) as HTMLElement[];
226
+ else if (Array.isArray(res)) targets = res.filter((e: any) => e instanceof currentWin.HTMLElement) as HTMLElement[];
227
+ } else if (typeof m.selector === 'string') {
228
+ if (m.selector === '$this' || m.selector === '') {
229
+ targets = [inst as HTMLElement];
230
+ } else {
231
+ const r: any = m.options.root || 'auto';
232
+ const scopes: any[] = [];
233
+ if (r === 'auto') scopes.push(inst.shadowRoot || inst);
234
+ else if (r === 'light') scopes.push(inst);
235
+ else if (r === 'shadow' && inst.shadowRoot) scopes.push(inst.shadowRoot);
236
+ else if (r === 'all') { scopes.push(inst); if (inst.shadowRoot) scopes.push(inst.shadowRoot); }
237
+ for (const s of scopes) {
238
+ const found = s?.querySelectorAll?.(m.selector as string) as NodeListOf<HTMLElement> | undefined;
239
+ if (found?.length) targets.push(...Array.from(found));
240
+ }
241
+ }
242
+ }
243
+ for (const el of targets) observeTargets.push({ target: el, callback });
244
+ }
245
+
246
+ intersectionObserverSet.push({ options: group.options, observeTargets });
247
+ }
248
+
249
+ return { intersectionObserverSet };
250
+ }
251
+
252
+ onDisconnected(helperHostSet: HelperHostSet): void {
253
+ const inst = helperHostSet.$this;
254
+ for (const cb of this.removeObserverCallbacksMap.get(inst) ?? []) {
255
+ try { cb.fn(cb.target, cb.opts); } catch (e) { console.error('[SWC] removeObserver error:', e); }
256
+ }
257
+ this.removeObserverCallbacksMap.delete(inst);
258
+ }
259
+ }