@dooboostore/simple-web-component 1.0.52 → 1.0.53

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 (40) hide show
  1. package/README.md +7 -8
  2. package/dist/cjs/decorators/addEventListener.js +8 -3
  3. package/dist/cjs/decorators/addEventListener.js.map +2 -2
  4. package/dist/cjs/decorators/requestAnimationFrame.js +10 -2
  5. package/dist/cjs/decorators/requestAnimationFrame.js.map +2 -2
  6. package/dist/cjs/decorators/setInterval.js +4 -2
  7. package/dist/cjs/decorators/setInterval.js.map +2 -2
  8. package/dist/cjs/decorators/setTimeout.js +4 -2
  9. package/dist/cjs/decorators/setTimeout.js.map +2 -2
  10. package/dist/cjs/decorators/subscribeSwcAppMessage.js +14 -1
  11. package/dist/cjs/decorators/subscribeSwcAppMessage.js.map +2 -2
  12. package/dist/esm/decorators/addEventListener.js +8 -3
  13. package/dist/esm/decorators/addEventListener.js.map +2 -2
  14. package/dist/esm/decorators/requestAnimationFrame.js +10 -2
  15. package/dist/esm/decorators/requestAnimationFrame.js.map +2 -2
  16. package/dist/esm/decorators/setInterval.js +4 -2
  17. package/dist/esm/decorators/setInterval.js.map +2 -2
  18. package/dist/esm/decorators/setTimeout.js +4 -2
  19. package/dist/esm/decorators/setTimeout.js.map +2 -2
  20. package/dist/esm/decorators/subscribeSwcAppMessage.js +14 -1
  21. package/dist/esm/decorators/subscribeSwcAppMessage.js.map +2 -2
  22. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +36 -6
  23. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +3 -3
  24. package/dist/types/decorators/addEventListener.d.ts.map +1 -1
  25. package/dist/types/decorators/requestAnimationFrame.d.ts +7 -4
  26. package/dist/types/decorators/requestAnimationFrame.d.ts.map +1 -1
  27. package/dist/types/decorators/setInterval.d.ts +6 -4
  28. package/dist/types/decorators/setInterval.d.ts.map +1 -1
  29. package/dist/types/decorators/setTimeout.d.ts +6 -4
  30. package/dist/types/decorators/setTimeout.d.ts.map +1 -1
  31. package/dist/types/decorators/subscribeSwcAppMessage.d.ts +12 -0
  32. package/dist/types/decorators/subscribeSwcAppMessage.d.ts.map +1 -1
  33. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +36 -6
  34. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +3 -3
  35. package/package.json +1 -1
  36. package/src/decorators/addEventListener.ts +10 -3
  37. package/src/decorators/requestAnimationFrame.ts +17 -5
  38. package/src/decorators/setInterval.ts +9 -5
  39. package/src/decorators/setTimeout.ts +9 -5
  40. package/src/decorators/subscribeSwcAppMessage.ts +27 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dooboostore/simple-web-component",
3
- "version": "1.0.52",
3
+ "version": "1.0.53",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",
@@ -1228,7 +1228,11 @@ export class EventListenerLifeCycler implements ElementDefineLifeCycler {
1228
1228
  const { type, options } = meta;
1229
1229
  const opts = { capture: options.capture, once: options.once, passive: options.passive };
1230
1230
 
1231
+ // event.currentTarget 은 dispatch 가 끝나면 null 이 된다 (표준). debounce/throttle 이나 async filter 뒤에 읽으면 이미 null 이라
1232
+ // 리스너가 불리는 순간에 잡아 둔다 → @matchedElement 가 항상 채워진다.
1233
+ const matchedTargets = new WeakMap<Event, EventTarget | null>();
1231
1234
  const handler = async (event: Event) => {
1235
+ const matchedElement = matchedTargets.get(event) ?? event.currentTarget;
1232
1236
  const helper = (options.filter || options.before || options.finally) ? SwcUtils.getHelperAndHostSet(target as HTMLElement, currentWin) : undefined;
1233
1237
  if (options.filter) {
1234
1238
  if (!(await options.filter(event, { currentThis: inst, helper }))) return;
@@ -1237,12 +1241,12 @@ export class EventListenerLifeCycler implements ElementDefineLifeCycler {
1237
1241
  if (options.stopImmediatePropagation) event.stopImmediatePropagation();
1238
1242
  if (options.preventDefault) event.preventDefault();
1239
1243
  const currentHostSet = SwcUtils.getHostSet(inst);
1240
- const legacyArgs = [event, { currentHostSet, $matchedElement: event.currentTarget }, { event, ...currentHostSet, $el: target, $root: target }];
1244
+ const legacyArgs = [event, { currentHostSet, $matchedElement: matchedElement }, { event, ...currentHostSet, $el: target, $root: target }];
1241
1245
  const currentHelperSet = SwcUtils.getHelperSet(currentWin);
1242
1246
  const currentHelperHostSet = { ...currentHelperSet, ...currentHostSet, $this: inst };
1243
1247
  const buildArgs = (beforeReturn: any) => buildSwcParameterArgs(inst, meta.propertyKey, {
1244
1248
  eventObject: event,
1245
- matchedElement: event.currentTarget,
1249
+ matchedElement,
1246
1250
  hostSet: currentHostSet,
1247
1251
  helperHostSet: currentHelperHostSet,
1248
1252
  helperSet: currentHelperSet,
@@ -1283,7 +1287,10 @@ export class EventListenerLifeCycler implements ElementDefineLifeCycler {
1283
1287
  error: (err: any) => console.error('Event stream error:', err),
1284
1288
  });
1285
1289
 
1286
- const wrappedHandler = (event: Event) => eventSubject.next(event);
1290
+ const wrappedHandler = (event: Event) => {
1291
+ matchedTargets.set(event, event.currentTarget);
1292
+ eventSubject.next(event);
1293
+ };
1287
1294
  target.addEventListener(type, wrappedHandler, opts);
1288
1295
 
1289
1296
  const onRemoves: Array<{ fn: any; opts: any }> =
@@ -9,8 +9,8 @@ export type RequestAnimationFrameType = 'onConnected' | 'returnValue';
9
9
 
10
10
  export interface RequestAnimationFrameOptions {
11
11
  /**
12
- * 'onConnected' - connect 시 자동으로 루프 시작 (매 프레임 데코레이트된 메서드를 직접 호출), disconnect 시 자동 정리.
13
- * 'returnValue'(기본값) - 자동 시작 없음. 개발자가 이 메서드를 직접 호출해야 시작되고,
12
+ * 'onConnected'(기본값) - connect 시 자동으로 루프 시작 (매 프레임 데코레이트된 메서드를 직접 호출), disconnect 시 자동 정리.
13
+ * 'returnValue' - 자동 시작 없음. 개발자가 이 메서드를 직접 호출해야 시작되고,
14
14
  * 그 호출의 리턴값(또는 valueKey로 뽑은 값)이 실제로 매 프레임 호출될 함수가 된다.
15
15
  */
16
16
  type?: RequestAnimationFrameType;
@@ -63,7 +63,7 @@ const startFrameLoop = (win: Window, entries: number[], frameFn: FrameCallback):
63
63
 
64
64
  const applyRequestAnimationFrame = (options: RequestAnimationFrameOptions, target: Object, propertyKey: string | symbol, descriptor?: PropertyDescriptor): PropertyDescriptor | void => {
65
65
  const constructor = target.constructor;
66
- const normalizedOptions: RequestAnimationFrameOptions = { ...options, type: options.type ?? 'returnValue' };
66
+ const normalizedOptions: RequestAnimationFrameOptions = { ...options, type: options.type ?? 'onConnected' };
67
67
 
68
68
  let metaList = ReflectUtils.getOwnMetadata(REQUEST_ANIMATION_FRAME_METADATA_KEY, constructor) as RequestAnimationFrameMetadata[];
69
69
  if (!metaList) {
@@ -96,8 +96,8 @@ const applyRequestAnimationFrame = (options: RequestAnimationFrameOptions, targe
96
96
  };
97
97
 
98
98
  /**
99
- * type:'onConnected' - connect 시 자동으로 매 프레임 루프를 시작하고, disconnect 시 자동으로 cancelAnimationFrame 한다.
100
- * type:'returnValue'(기본값) - 메서드를 감싸지 않는 대신, 호출될 때마다(개발자가 직접 호출) 원본 로직을
99
+ * type:'onConnected'(기본값) - connect 시 자동으로 매 프레임 루프를 시작하고, disconnect 시 자동으로 cancelAnimationFrame 한다.
100
+ * type:'returnValue' (@requestAnimationFrameReturnValue) - 메서드를 감싸지 않는 대신, 호출될 때마다(개발자가 직접 호출) 원본 로직을
101
101
  * 그대로 실행하고 리턴값(또는 valueKey로 뽑은 값)이 함수면 그 함수를 매 프레임 호출되는 루프로 등록한다.
102
102
  * 원본 리턴값은 그대로 통과시키므로 다른 데코레이터와 같은 메서드에 스택해도 순서에 상관없이 안전하다.
103
103
  *
@@ -147,3 +147,15 @@ export class RequestAnimationFrameLifeCycler implements ElementDefineLifeCycler
147
147
  inst.__swc_requestAnimationFrameIds = [];
148
148
  }
149
149
  }
150
+
151
+ /** 수동 시작: 메서드를 직접 호출해야 시작되고, 그 리턴 함수가 매 프레임 돈다. = @requestAnimationFrame({ type: 'returnValue' }) */
152
+ export function requestAnimationFrameReturnValue(options: Omit<RequestAnimationFrameOptions, 'type'>): MethodDecorator;
153
+ export function requestAnimationFrameReturnValue(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
154
+ export function requestAnimationFrameReturnValue(optionsOrTarget?: Omit<RequestAnimationFrameOptions, 'type'> | Object, propertyKey?: string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
155
+ if (propertyKey !== undefined) {
156
+ applyRequestAnimationFrame({ type: 'returnValue' }, optionsOrTarget as Object, propertyKey, descriptor);
157
+ return;
158
+ }
159
+ return (target: Object, propertyKey: string | symbol, descriptor?: PropertyDescriptor) =>
160
+ applyRequestAnimationFrame({ ...((optionsOrTarget as RequestAnimationFrameOptions) ?? {}), type: 'returnValue' }, target, propertyKey, descriptor);
161
+ }
@@ -10,8 +10,8 @@ export type SetIntervalType = 'onConnected' | 'returnValue';
10
10
 
11
11
  export interface SetIntervalOptions {
12
12
  /**
13
- * 'onConnected' (connect 시 자동으로 시작, disconnect 시 자동 정리) |
14
- * 'returnValue' (기본값 - 자동 시작 없음. 개발자가 이 메서드를 직접 호출해야 시작되고,
13
+ * 'onConnected' (기본값 - connect 시 자동으로 시작, disconnect 시 자동 정리) |
14
+ * 'returnValue' (자동 시작 없음. 개발자가 이 메서드를 직접 호출해야 시작되고,
15
15
  * 그 호출의 리턴값이 실제로 반복 실행될 함수가 된다 - 아래 설명 참고).
16
16
  */
17
17
  type?: SetIntervalType;
@@ -43,8 +43,8 @@ export interface SetIntervalMetadata {
43
43
  const getActiveEntries = (inst: any): number[] => (inst.__swc_intervalIds ??= []);
44
44
 
45
45
  /**
46
- * type:'onConnected' - connect 시 자동으로 setInterval을 걸고, disconnect 시 자동으로 clearInterval 한다.
47
- * type:'returnValue'(기본값) - 메서드를 감싸지 않는 대신, 호출될 때마다(개발자가 직접 호출) 원본 로직을
46
+ * type:'onConnected'(기본값) - connect 시 자동으로 setInterval을 걸고, disconnect 시 자동으로 clearInterval 한다.
47
+ * type:'returnValue' (@setIntervalReturnValue) - 메서드를 감싸지 않는 대신, 호출될 때마다(개발자가 직접 호출) 원본 로직을
48
48
  * 그대로 실행하고 리턴값(또는 valueKey로 뽑은 값)이 함수면 그 함수를 새 setInterval의 반복 콜백으로 등록한다.
49
49
  * 호출할 때마다 별도의 새 타이머가 생기며, disconnect 시 전부 정리된다. 원본 리턴값은 그대로 통과시키므로
50
50
  * 다른 데코레이터와 같은 메서드에 스택해도 순서에 상관없이 안전하다.
@@ -52,7 +52,7 @@ const getActiveEntries = (inst: any): number[] => (inst.__swc_intervalIds ??= []
52
52
  export function setInterval(interval: number, options: SetIntervalOptions = {}): MethodDecorator {
53
53
  return (target: Object, propertyKey: string | symbol, descriptor?: PropertyDescriptor) => {
54
54
  const constructor = target.constructor;
55
- const normalizedOptions: SetIntervalOptions = { ...options, type: options.type ?? 'returnValue' };
55
+ const normalizedOptions: SetIntervalOptions = { ...options, type: options.type ?? 'onConnected' };
56
56
 
57
57
  let metaList = ReflectUtils.getOwnMetadata(SET_INTERVAL_METADATA_KEY, constructor) as SetIntervalMetadata[];
58
58
  if (!metaList) {
@@ -145,3 +145,7 @@ export class SetIntervalLifeCycler implements ElementDefineLifeCycler {
145
145
  inst.__swc_intervalIds = [];
146
146
  }
147
147
  }
148
+
149
+ /** 수동 시작: 메서드를 직접 호출해야 시작된다. = @setInterval(interval, { type: 'returnValue' }) */
150
+ export const setIntervalReturnValue = (interval: number, options: Omit<SetIntervalOptions, 'type'> = {}): MethodDecorator =>
151
+ setInterval(interval, { ...options, type: 'returnValue' });
@@ -10,8 +10,8 @@ export type SetTimeoutType = 'onConnected' | 'returnValue';
10
10
 
11
11
  export interface SetTimeoutOptions {
12
12
  /**
13
- * 'onConnected' (connect 시 자동으로 예약, disconnect 시 자동 정리) |
14
- * 'returnValue' (기본값 - 자동 예약 없음. 개발자가 이 메서드를 직접 호출해야 예약되고,
13
+ * 'onConnected' (기본값 - connect 시 자동으로 예약, disconnect 시 자동 정리) |
14
+ * 'returnValue' (자동 예약 없음. 개발자가 이 메서드를 직접 호출해야 예약되고,
15
15
  * 그 호출의 리턴값이 실제로 실행될 함수가 된다 - 아래 설명 참고).
16
16
  */
17
17
  type?: SetTimeoutType;
@@ -43,8 +43,8 @@ export interface SetTimeoutMetadata {
43
43
  const getActiveEntries = (inst: any): number[] => (inst.__swc_timeoutIds ??= []);
44
44
 
45
45
  /**
46
- * type:'onConnected' - connect 시 자동으로 setTimeout을 걸고, disconnect 시 (아직 실행 전이라면) 자동으로 clearTimeout 한다.
47
- * type:'returnValue'(기본값) - 메서드를 감싸지 않는 대신, 호출될 때마다(개발자가 직접 호출) 원본 로직을
46
+ * type:'onConnected'(기본값) - connect 시 자동으로 setTimeout을 걸고, disconnect 시 (아직 실행 전이라면) 자동으로 clearTimeout 한다.
47
+ * type:'returnValue' (@setTimeoutReturnValue) - 메서드를 감싸지 않는 대신, 호출될 때마다(개발자가 직접 호출) 원본 로직을
48
48
  * 그대로 실행하고 리턴값(또는 valueKey로 뽑은 값)이 함수면 그 함수를 새 setTimeout으로 예약한다.
49
49
  * 호출할 때마다 별도의 새 타이머가 생기며, disconnect 시 (아직 실행 전인 것들은) 전부 정리된다.
50
50
  * 원본 리턴값은 그대로 통과시키므로 다른 데코레이터와 같은 메서드에 스택해도 순서에 상관없이 안전하다.
@@ -52,7 +52,7 @@ const getActiveEntries = (inst: any): number[] => (inst.__swc_timeoutIds ??= [])
52
52
  export function setTimeout(delay: number, options: SetTimeoutOptions = {}): MethodDecorator {
53
53
  return (target: Object, propertyKey: string | symbol, descriptor?: PropertyDescriptor) => {
54
54
  const constructor = target.constructor;
55
- const normalizedOptions: SetTimeoutOptions = { ...options, type: options.type ?? 'returnValue' };
55
+ const normalizedOptions: SetTimeoutOptions = { ...options, type: options.type ?? 'onConnected' };
56
56
 
57
57
  let metaList = ReflectUtils.getOwnMetadata(SET_TIMEOUT_METADATA_KEY, constructor) as SetTimeoutMetadata[];
58
58
  if (!metaList) {
@@ -148,3 +148,7 @@ export class SetTimeoutLifeCycler implements ElementDefineLifeCycler {
148
148
  inst.__swc_timeoutIds = [];
149
149
  }
150
150
  }
151
+
152
+ /** 수동 예약: 메서드를 직접 호출해야 예약된다. = @setTimeout(delay, { type: 'returnValue' }) */
153
+ export const setTimeoutReturnValue = (delay: number, options: Omit<SetTimeoutOptions, 'type'> = {}): MethodDecorator =>
154
+ setTimeout(delay, { ...options, type: 'returnValue' });
@@ -82,6 +82,33 @@ export function subscribeSwcAppMessage(targetOrMessageTypeOrOptions?: any, optio
82
82
  }
83
83
 
84
84
  export const receiveMessage = subscribeSwcAppMessage;
85
+
86
+ // ── subject 를 이름에 박은 별칭: @subscribeSwcAppMessageBehavior('auth') = @subscribeSwcAppMessage('auth', { subject: 'behavior' }) ──
87
+ type SubjectlessOptions<Data, BeforeReturn, Result> = Omit<SwcAppMessageOptions<Data, BeforeReturn, Result>, 'subject'>;
88
+
89
+ const withSubject = (subject: SwcAppMessageSubject, a?: any, b?: any, descriptor?: PropertyDescriptor): any => {
90
+ if (descriptor) return createSubscribeSwcAppMessage({ subject })(a, b, descriptor); // 괄호 없이
91
+ if (typeof a === 'string') return createSubscribeSwcAppMessage({ ...(b ?? {}), subject }, a);
92
+ return createSubscribeSwcAppMessage({ ...(a ?? {}), subject });
93
+ };
94
+
95
+ /** 늦게 붙어도 마지막 메시지 1개를 받는다 (subject: 'behavior') */
96
+ export function subscribeSwcAppMessageBehavior(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
97
+ export function subscribeSwcAppMessageBehavior(messageType: string): MethodDecorator;
98
+ export function subscribeSwcAppMessageBehavior<Data = any, BeforeReturn = any, Result = any>(options: SubjectlessOptions<NoInfer<Data>, NoInfer<BeforeReturn>, NoInfer<Result>>): MethodDecorator;
99
+ export function subscribeSwcAppMessageBehavior<Data = any, BeforeReturn = any, Result = any>(messageType: string, options: SubjectlessOptions<NoInfer<Data>, NoInfer<BeforeReturn>, NoInfer<Result>>): MethodDecorator;
100
+ export function subscribeSwcAppMessageBehavior(a?: any, b?: any, descriptor?: PropertyDescriptor): any {
101
+ return withSubject('behavior', a, b, descriptor);
102
+ }
103
+
104
+ /** 늦게 붙어도 지나간 메시지를 전부 시간순으로 받는다 (subject: 'replay') */
105
+ export function subscribeSwcAppMessageReplay(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
106
+ export function subscribeSwcAppMessageReplay(messageType: string): MethodDecorator;
107
+ export function subscribeSwcAppMessageReplay<Data = any, BeforeReturn = any, Result = any>(options: SubjectlessOptions<NoInfer<Data>, NoInfer<BeforeReturn>, NoInfer<Result>>): MethodDecorator;
108
+ export function subscribeSwcAppMessageReplay<Data = any, BeforeReturn = any, Result = any>(messageType: string, options: SubjectlessOptions<NoInfer<Data>, NoInfer<BeforeReturn>, NoInfer<Result>>): MethodDecorator;
109
+ export function subscribeSwcAppMessageReplay(a?: any, b?: any, descriptor?: PropertyDescriptor): any {
110
+ return withSubject('replay', a, b, descriptor);
111
+ }
85
112
  // Helper function to retrieve message subscribers metadata
86
113
  export const getSubscribeSwcAppMessageMetadata = (target: any): SwcAppMessageSubscriberMetadata[] | undefined => {
87
114
  const constructor = typeof target === 'function' ? target : target.constructor;