@dooboostore/simple-web-component 1.0.34 → 1.0.36

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 (170) hide show
  1. package/README.md +44 -51
  2. package/dist/cjs/decorators/addEventListener.js +12 -4
  3. package/dist/cjs/decorators/addEventListener.js.map +2 -2
  4. package/dist/cjs/decorators/applyAttribute.js +19 -18
  5. package/dist/cjs/decorators/applyAttribute.js.map +2 -2
  6. package/dist/cjs/decorators/applyClass.js +23 -22
  7. package/dist/cjs/decorators/applyClass.js.map +2 -2
  8. package/dist/cjs/decorators/applyNode.js +22 -17
  9. package/dist/cjs/decorators/applyNode.js.map +2 -2
  10. package/dist/cjs/decorators/applyStyle.js +20 -19
  11. package/dist/cjs/decorators/applyStyle.js.map +2 -2
  12. package/dist/cjs/decorators/attribute.js +17 -16
  13. package/dist/cjs/decorators/attribute.js.map +2 -2
  14. package/dist/cjs/decorators/{changedAttributeHost.js → changedAttributeThis.js} +6 -6
  15. package/dist/cjs/decorators/changedAttributeThis.js.map +7 -0
  16. package/dist/cjs/decorators/elementDefine.js +234 -188
  17. package/dist/cjs/decorators/elementDefine.js.map +2 -2
  18. package/dist/cjs/decorators/emitCustomEvent.js +24 -16
  19. package/dist/cjs/decorators/emitCustomEvent.js.map +2 -2
  20. package/dist/cjs/decorators/index.js +1 -1
  21. package/dist/cjs/decorators/index.js.map +1 -1
  22. package/dist/cjs/decorators/lifecycles.js +15 -17
  23. package/dist/cjs/decorators/lifecycles.js.map +2 -2
  24. package/dist/cjs/decorators/query.js +38 -60
  25. package/dist/cjs/decorators/query.js.map +2 -2
  26. package/dist/cjs/decorators/queryAll.js +31 -63
  27. package/dist/cjs/decorators/queryAll.js.map +2 -2
  28. package/dist/cjs/decorators/setProperty.js +13 -12
  29. package/dist/cjs/decorators/setProperty.js.map +2 -2
  30. package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js +2 -2
  31. package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +2 -2
  32. package/dist/cjs/elements/SwcAppEngine.js +8 -2
  33. package/dist/cjs/elements/SwcAppEngine.js.map +2 -2
  34. package/dist/cjs/elements/SwcAppMixin.js +120 -65
  35. package/dist/cjs/elements/SwcAppMixin.js.map +2 -2
  36. package/dist/cjs/elements/SwcAsync.js +31 -21
  37. package/dist/cjs/elements/SwcAsync.js.map +2 -2
  38. package/dist/cjs/elements/SwcChoose.js +53 -34
  39. package/dist/cjs/elements/SwcChoose.js.map +2 -2
  40. package/dist/cjs/elements/SwcIf.js +54 -32
  41. package/dist/cjs/elements/SwcIf.js.map +2 -2
  42. package/dist/cjs/elements/SwcLoop.js +111 -37
  43. package/dist/cjs/elements/SwcLoop.js.map +2 -2
  44. package/dist/cjs/elements/register.js +249 -122
  45. package/dist/cjs/elements/register.js.map +2 -2
  46. package/dist/cjs/router/ElementRouter.js +4 -2
  47. package/dist/cjs/router/ElementRouter.js.map +1 -1
  48. package/dist/cjs/types.js.map +1 -1
  49. package/dist/cjs/utils/Utils.js +31 -17
  50. package/dist/cjs/utils/Utils.js.map +2 -2
  51. package/dist/esm/decorators/addEventListener.js +12 -4
  52. package/dist/esm/decorators/addEventListener.js.map +2 -2
  53. package/dist/esm/decorators/applyAttribute.js +19 -18
  54. package/dist/esm/decorators/applyAttribute.js.map +2 -2
  55. package/dist/esm/decorators/applyClass.js +23 -22
  56. package/dist/esm/decorators/applyClass.js.map +2 -2
  57. package/dist/esm/decorators/applyNode.js +22 -17
  58. package/dist/esm/decorators/applyNode.js.map +2 -2
  59. package/dist/esm/decorators/applyStyle.js +20 -19
  60. package/dist/esm/decorators/applyStyle.js.map +2 -2
  61. package/dist/esm/decorators/attribute.js +17 -16
  62. package/dist/esm/decorators/attribute.js.map +2 -2
  63. package/dist/esm/decorators/{changedAttributeHost.js → changedAttributeThis.js} +3 -3
  64. package/dist/esm/decorators/changedAttributeThis.js.map +7 -0
  65. package/dist/esm/decorators/elementDefine.js +233 -187
  66. package/dist/esm/decorators/elementDefine.js.map +2 -2
  67. package/dist/esm/decorators/emitCustomEvent.js +24 -16
  68. package/dist/esm/decorators/emitCustomEvent.js.map +2 -2
  69. package/dist/esm/decorators/index.js +1 -1
  70. package/dist/esm/decorators/index.js.map +1 -1
  71. package/dist/esm/decorators/lifecycles.js +15 -17
  72. package/dist/esm/decorators/lifecycles.js.map +2 -2
  73. package/dist/esm/decorators/query.js +38 -60
  74. package/dist/esm/decorators/query.js.map +2 -2
  75. package/dist/esm/decorators/queryAll.js +31 -63
  76. package/dist/esm/decorators/queryAll.js.map +2 -2
  77. package/dist/esm/decorators/setProperty.js +13 -12
  78. package/dist/esm/decorators/setProperty.js.map +2 -2
  79. package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js +2 -2
  80. package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +2 -2
  81. package/dist/esm/elements/SwcAppEngine.js +9 -2
  82. package/dist/esm/elements/SwcAppEngine.js.map +2 -2
  83. package/dist/esm/elements/SwcAppMixin.js +122 -66
  84. package/dist/esm/elements/SwcAppMixin.js.map +2 -2
  85. package/dist/esm/elements/SwcAsync.js +32 -22
  86. package/dist/esm/elements/SwcAsync.js.map +2 -2
  87. package/dist/esm/elements/SwcChoose.js +54 -35
  88. package/dist/esm/elements/SwcChoose.js.map +2 -2
  89. package/dist/esm/elements/SwcIf.js +55 -33
  90. package/dist/esm/elements/SwcIf.js.map +2 -2
  91. package/dist/esm/elements/SwcLoop.js +112 -38
  92. package/dist/esm/elements/SwcLoop.js.map +2 -2
  93. package/dist/esm/elements/register.js +250 -123
  94. package/dist/esm/elements/register.js.map +2 -2
  95. package/dist/esm/router/ElementRouter.js +5 -2
  96. package/dist/esm/router/ElementRouter.js.map +1 -1
  97. package/dist/esm/types.js.map +1 -1
  98. package/dist/esm/utils/Utils.js +31 -17
  99. package/dist/esm/utils/Utils.js.map +2 -2
  100. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +563 -557
  101. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
  102. package/dist/types/decorators/addEventListener.d.ts +5 -7
  103. package/dist/types/decorators/addEventListener.d.ts.map +1 -1
  104. package/dist/types/decorators/applyAttribute.d.ts +4 -4
  105. package/dist/types/decorators/applyAttribute.d.ts.map +1 -1
  106. package/dist/types/decorators/applyClass.d.ts +6 -6
  107. package/dist/types/decorators/applyClass.d.ts.map +1 -1
  108. package/dist/types/decorators/applyNode.d.ts +7 -6
  109. package/dist/types/decorators/applyNode.d.ts.map +1 -1
  110. package/dist/types/decorators/applyStyle.d.ts +4 -4
  111. package/dist/types/decorators/applyStyle.d.ts.map +1 -1
  112. package/dist/types/decorators/attribute.d.ts +5 -5
  113. package/dist/types/decorators/attribute.d.ts.map +1 -1
  114. package/dist/types/decorators/changedAttributeThis.d.ts +18 -0
  115. package/dist/types/decorators/changedAttributeThis.d.ts.map +1 -0
  116. package/dist/types/decorators/elementDefine.d.ts.map +1 -1
  117. package/dist/types/decorators/emitCustomEvent.d.ts +11 -12
  118. package/dist/types/decorators/emitCustomEvent.d.ts.map +1 -1
  119. package/dist/types/decorators/index.d.ts +1 -1
  120. package/dist/types/decorators/lifecycles.d.ts +10 -7
  121. package/dist/types/decorators/lifecycles.d.ts.map +1 -1
  122. package/dist/types/decorators/query.d.ts +17 -63
  123. package/dist/types/decorators/query.d.ts.map +1 -1
  124. package/dist/types/decorators/queryAll.d.ts +6 -63
  125. package/dist/types/decorators/queryAll.d.ts.map +1 -1
  126. package/dist/types/decorators/setProperty.d.ts +1 -1
  127. package/dist/types/decorators/setProperty.d.ts.map +1 -1
  128. package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts +4 -5
  129. package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts.map +1 -1
  130. package/dist/types/elements/SwcAppEngine.d.ts +4 -1
  131. package/dist/types/elements/SwcAppEngine.d.ts.map +1 -1
  132. package/dist/types/elements/SwcAppMixin.d.ts +11 -8
  133. package/dist/types/elements/SwcAppMixin.d.ts.map +1 -1
  134. package/dist/types/elements/register.d.ts.map +1 -1
  135. package/dist/types/types.d.ts +3 -2
  136. package/dist/types/types.d.ts.map +1 -1
  137. package/dist/types/utils/Utils.d.ts +11 -8
  138. package/dist/types/utils/Utils.d.ts.map +1 -1
  139. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +563 -557
  140. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
  141. package/package.json +3 -3
  142. package/src/decorators/addEventListener.ts +11 -9
  143. package/src/decorators/applyAttribute.ts +16 -15
  144. package/src/decorators/applyClass.ts +18 -17
  145. package/src/decorators/applyNode.ts +34 -21
  146. package/src/decorators/applyStyle.ts +17 -16
  147. package/src/decorators/attribute.ts +21 -20
  148. package/src/decorators/{changedAttributeHost.ts → changedAttributeThis.ts} +13 -14
  149. package/src/decorators/elementDefine.ts +402 -358
  150. package/src/decorators/emitCustomEvent.ts +40 -31
  151. package/src/decorators/index.ts +1 -1
  152. package/src/decorators/lifecycles.ts +11 -10
  153. package/src/decorators/query.ts +51 -124
  154. package/src/decorators/queryAll.ts +30 -127
  155. package/src/decorators/setProperty.ts +12 -11
  156. package/src/decorators/subscribeSwcAppRouteChangeWhileConnected.ts +10 -10
  157. package/src/elements/SwcAppEngine.ts +10 -3
  158. package/src/elements/SwcAppMixin.ts +177 -97
  159. package/src/elements/SwcAsync.ts +32 -21
  160. package/src/elements/SwcChoose.ts +74 -37
  161. package/src/elements/SwcIf.ts +60 -23
  162. package/src/elements/SwcLoop.ts +141 -28
  163. package/src/elements/register.ts +300 -102
  164. package/src/types.ts +6 -5
  165. package/src/utils/Utils.ts +40 -23
  166. package/tsconfig.json +2 -2
  167. package/dist/cjs/decorators/changedAttributeHost.js.map +0 -7
  168. package/dist/esm/decorators/changedAttributeHost.js.map +0 -7
  169. package/dist/types/decorators/changedAttributeHost.d.ts +0 -19
  170. package/dist/types/decorators/changedAttributeHost.d.ts.map +0 -1
@@ -56,15 +56,16 @@ export const setProperty = (selector: string, propertyNameOrOptions?: string | P
56
56
  targetEls.push(t);
57
57
  };
58
58
 
59
- if (selector === ':parentHost') applyRoot(hostSet.$parentHost);
60
- else if (selector === ':appHost') applyRoot(hostSet.$appHost);
61
- else if (selector === ':firstHost') applyRoot(hostSet.$firstHost);
62
- else if (selector === ':lastHost') applyRoot(hostSet.$lastHost);
63
- else if (selector === ':firstAppHost') applyRoot(hostSet.$firstAppHost);
64
- else if (selector === ':lastAppHost') applyRoot(hostSet.$lastAppHost);
65
- else if (selector === ':hosts') hostSet.$hosts.forEach(applyRoot);
66
- else if (selector === ':appHosts') hostSet.$appHosts.forEach(applyRoot);
67
- else if (selector === ':host' || !selector) applyRoot(host);
59
+ if (selector === '$this' || !selector) applyRoot(host);
60
+ else if (selector === '$host') applyRoot(hostSet.$host);
61
+ else if (selector === '$parentHost') applyRoot(hostSet.$parentHost);
62
+ else if (selector === '$appHost') applyRoot(hostSet.$appHost);
63
+ else if (selector === '$firstHost') applyRoot(hostSet.$firstHost);
64
+ else if (selector === '$lastHost') applyRoot(hostSet.$lastHost);
65
+ else if (selector === '$firstAppHost') applyRoot(hostSet.$firstAppHost);
66
+ else if (selector === '$lastAppHost') applyRoot(hostSet.$lastAppHost);
67
+ else if (selector === '$hosts') hostSet.$hosts.forEach(applyRoot);
68
+ else if (selector === '$appHosts') hostSet.$appHosts.forEach(applyRoot);
68
69
  else {
69
70
  const targetRoot = r === 'auto' ? (host.shadowRoot || host) : (r === 'shadow' ? host.shadowRoot : host);
70
71
  if (targetRoot) {
@@ -106,6 +107,6 @@ export const setProperty = (selector: string, propertyNameOrOptions?: string | P
106
107
  };
107
108
  };
108
109
 
109
- export const setPropertyHost = (propertyNameOrOptions?: string | PropertySetOptions, options: PropertySetOptions = {}): MethodDecorator => {
110
- return setProperty(':host', propertyNameOrOptions, options);
110
+ export const setPropertyThis = (propertyNameOrOptions?: string | PropertySetOptions, options: PropertySetOptions = {}): MethodDecorator => {
111
+ return setProperty('$this', propertyNameOrOptions, options);
111
112
  };
@@ -3,14 +3,15 @@ import { Router } from '@dooboostore/core-web';
3
3
 
4
4
  export const SUBSCRIBE_SWC_APP_ROUTE_CHANGE_WHILE_CONNECTED_METADATA_KEY = Symbol.for('simple-web-component:subscribe-swc-app-route-change-while-connected');
5
5
 
6
+ export type RoutePathType = string | string[] | ((currentThis: any) => string | string[]);
7
+
6
8
  export interface SwcAppRouteChangeSubscriberMetadata {
7
9
  propertyKey: string | symbol;
8
- pathPattern?: string | string[];
9
- filter?: (router: Router, currentThis: any) => boolean;
10
+ options?: SwcAppRouteChangeOptions;
10
11
  }
11
12
 
12
13
  export interface SwcAppRouteChangeOptions {
13
- path?: string | string[];
14
+ path?: RoutePathType;
14
15
  filter?: (router: Router, currentThis: any) => boolean;
15
16
  }
16
17
 
@@ -25,8 +26,8 @@ function createSubscribeSwcAppRouteChangeWhileConnected(options?: SwcAppRouteCha
25
26
  list = [];
26
27
  ReflectUtils.defineMetadata(SUBSCRIBE_SWC_APP_ROUTE_CHANGE_WHILE_CONNECTED_METADATA_KEY, list, constructor);
27
28
  }
28
- list.push({ propertyKey, pathPattern, filter });
29
-
29
+ list.push({ propertyKey, options });
30
+
30
31
  return descriptor;
31
32
  };
32
33
  }
@@ -35,8 +36,7 @@ function createSubscribeSwcAppRouteChangeWhileConnected(options?: SwcAppRouteCha
35
36
  export function subscribeSwcAppRouteChangeWhileConnected(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
36
37
  // 오버로드 시그니처 - 함수 호출 (괄호 있음)
37
38
  export function subscribeSwcAppRouteChangeWhileConnected(): MethodDecorator;
38
- export function subscribeSwcAppRouteChangeWhileConnected(pathPattern: string): MethodDecorator;
39
- export function subscribeSwcAppRouteChangeWhileConnected(pathPatterns: string[]): MethodDecorator;
39
+ export function subscribeSwcAppRouteChangeWhileConnected(pathPattern: RoutePathType): MethodDecorator;
40
40
  export function subscribeSwcAppRouteChangeWhileConnected(options: SwcAppRouteChangeOptions): MethodDecorator;
41
41
 
42
42
  // 실제 구현 (이중 모드)
@@ -46,15 +46,15 @@ export function subscribeSwcAppRouteChangeWhileConnected(targetOrOptions?: any,
46
46
  if (propertyKey && (typeof propertyKey === 'string' || typeof propertyKey === 'symbol')) {
47
47
  return createSubscribeSwcAppRouteChangeWhileConnected({})(targetOrOptions, propertyKey, descriptor);
48
48
  }
49
-
49
+
50
50
  // 함수로 호출된 경우 (괄호 있음): @subscribeSwcAppRouteChangeWhileConnected() / @subscribeSwcAppRouteChangeWhileConnected('/path')
51
51
  let options: SwcAppRouteChangeOptions = {};
52
52
 
53
53
  if (Array.isArray(targetOrOptions)) {
54
54
  // 배열: @subscribeSwcAppRouteChangeWhileConnected(['/path1', '/path2'])
55
55
  options.path = targetOrOptions;
56
- } else if (typeof targetOrOptions === 'string') {
57
- // 문자열: @subscribeSwcAppRouteChangeWhileConnected('/path')
56
+ } else if (typeof targetOrOptions === 'string' || typeof targetOrOptions === 'function') {
57
+ // 문자열 또는 함수: @subscribeSwcAppRouteChangeWhileConnected('/path')
58
58
  options.path = targetOrOptions;
59
59
  } else if (targetOrOptions && typeof targetOrOptions === 'object') {
60
60
  // 객체: @subscribeSwcAppRouteChangeWhileConnected({ path: '/path', filter: ... })
@@ -17,7 +17,13 @@ export type SwcConfigType = {
17
17
  onEngineStarted?: (sp: SimpleApplication, app: SwcAppInterface) => void;
18
18
  onConnected?: (app: SwcAppInterface) => void;
19
19
  onDisconnected?: (app: SwcAppInterface) => void;
20
- onRouteChanged?: (event: RouterEventType, app: SwcAppInterface) => void;
20
+
21
+ onChildrenConnectedDone?: (app: SwcAppInterface) => void;
22
+ // onChildrenSwcAppStartedDone?: (app: SwcAppInterface) => void;
23
+ // childrenSwcAppStartedDoneCheckIntervalTime?: number;
24
+ onChildrenRouteChanged?: (event: RouterEventType, app: SwcAppInterface) => void;
25
+ childrenRouteChangedCheckIntervalTime?: number; // 자식 연결 완료 이벤트 디바운스 타임 (ms)
26
+ childrenConnectedDoneCheckIntervalTime?: number;
21
27
  };
22
28
 
23
29
  export type SwcAttributeConfigType = OptionalType<SwcConfigType, 'routeType' | 'window'>;
@@ -33,6 +39,7 @@ export class SwcAppEngine {
33
39
  get config() {
34
40
  return this._config;
35
41
  }
42
+
36
43
  async connect(config: SwcConfigType) {
37
44
  try {
38
45
  this._config = config;
@@ -51,13 +58,13 @@ export class SwcAppEngine {
51
58
  // App start
52
59
  this.simpleApplication = new SimpleApplication(
53
60
  new SimOption({
54
- excludeProxys: [Node],
61
+ excludeProxys: [(this._config.window as any).Node],
55
62
  container: this._config.container
56
63
  })
57
64
  );
58
65
 
59
66
  const otherInstanceSim = new Map<any, any>();
60
- this.config.otherInstanceSim?.forEach((v, k) => {
67
+ this.config?.otherInstanceSim?.forEach((v, k) => {
61
68
  otherInstanceSim.set(k, v);
62
69
  });
63
70
  if (this.router) otherInstanceSim.set(Router, this.router);
@@ -1,21 +1,24 @@
1
- import { SwcAppEngine, SwcAttributeConfigType, SwcConfigType } from './SwcAppEngine';
2
- import { SwcAppInterface, SwcAppMessage } from '../types';
3
- import { SwcUtils } from '../utils/Utils';
4
- import { FunctionUtils, Subscription } from '@dooboostore/core';
5
- import { Router, RouterEventType } from '@dooboostore/core-web';
6
- import { ON_CONNECTED_SWC_APP_METADATA_KEY, findAllLifecycleMetadata } from '../decorators/lifecycles';
7
- import { getSubscribeSwcAppRouteChangeWhileConnectedMetadata } from '../decorators/subscribeSwcAppRouteChangeWhileConnected';
8
- import { getSubscribeSwcAppMessageWhileConnectedMetadata } from '../decorators/subscribeSwcAppMessageWhileConnected';
9
-
10
- export function SwcAppMixin<T extends { new (...args: any[]): HTMLElement }>(Base: T) {
1
+ import {SwcAppEngine, SwcAttributeConfigType, SwcConfigType} from './SwcAppEngine';
2
+ import {SwcAppInterface, SwcAppMessage} from '../types';
3
+ import {SwcUtils} from '../utils/Utils';
4
+ import {debounceTimeIntervalLock, FunctionUtils, Subscription} from '@dooboostore/core';
5
+ import {RouterEventType} from '@dooboostore/core-web';
6
+ import {getSubscribeSwcAppRouteChangeWhileConnectedMetadata} from '../decorators/subscribeSwcAppRouteChangeWhileConnected';
7
+ import {getSubscribeSwcAppMessageWhileConnectedMetadata} from '../decorators/subscribeSwcAppMessageWhileConnected';
8
+
9
+ export function SwcAppMixin<T extends { new(...args: any[]): HTMLElement }>(Base: T) {
11
10
  //@ts-ignore
12
11
  return class extends Base implements SwcAppInterface {
13
12
  __swc_engine = new SwcAppEngine(this as any);
14
13
  _swc_connected_instance = new Set<any>();
15
- _swc_started_instances = new WeakSet<any>();
16
- _swc_notified_routes = new WeakMap<any, RouterEventType>();
14
+ // _swc_notified_routes = new WeakMap<any, RouterEventType>();
17
15
  _routerSubscription?: Subscription;
18
16
  _lastRouterEvent?: RouterEventType;
17
+ _routeChangeInvocations = 0;
18
+ _connectedInvocations = 0;
19
+
20
+ _childrenRouteChangedInterval: any;
21
+ _childrenConnectedDoneInterval: any;
19
22
 
20
23
  /*
21
24
  사파리 is 일경우
@@ -24,104 +27,171 @@ export function SwcAppMixin<T extends { new (...args: any[]): HTMLElement }>(Bas
24
27
  저 polyfill에서는 자식부터 만들어지고 부모가 만들어진다 is일때 아 .. 이문제때문에 자식이 _connected_safari 에 강제로 자기자식넣어준다
25
28
  */
26
29
  _connected_safari = [];
30
+
27
31
  get simpleApplication() {
28
32
  return this.__swc_engine.simpleApplication;
29
33
  }
34
+
35
+ get config() {
36
+ return this.__swc_engine?.config;
37
+ }
38
+
30
39
  get router() {
31
- return this.__swc_engine.router;
40
+ return this.__swc_engine?.router;
32
41
  }
33
42
 
34
43
  async _invokeRouteChangeSubscribers(instance: any, re: RouterEventType) {
35
- // 이미 이 라우트 이벤트에 대해 처리된 인스턴스라면 스킵 (동시성/중복 방지)
36
- if (this._swc_notified_routes.get(instance) === re) return;
37
- this._swc_notified_routes.set(instance, re);
44
+ if (instance.isConnected === false) return;
38
45
 
39
- const routeChangeSubscribers = getSubscribeSwcAppRouteChangeWhileConnectedMetadata(instance);
40
- if (routeChangeSubscribers && Array.isArray(routeChangeSubscribers)) {
41
- const ps = routeChangeSubscribers.map(async metadata => {
42
- const methodName = metadata.propertyKey;
43
- const pathPattern = metadata.pathPattern;
44
- const filter = metadata.filter;
46
+ this._routeChangeInvocations++;
47
+
48
+ if (this._childrenRouteChangedInterval) {
49
+ clearInterval(this._childrenRouteChangedInterval);
50
+ }
51
+ this._childrenRouteChangedInterval = debounceTimeIntervalLock(
52
+ () => this._routeChangeInvocations === 0,
53
+ () => {
54
+ this._childrenRouteChangedInterval = null;
55
+ this.config.onChildrenRouteChanged(re, this)
56
+ },
57
+ this.config?.childrenConnectedDoneCheckIntervalTime ?? 30,
58
+ {setInterval: window.setInterval, clearInterval: window.clearInterval}
59
+ // {setInterval: window.setInterval, clearInterval: window.clearInterval}
60
+ );
61
+
62
+
63
+ // debounceTimeIntervalLock({
64
+ // unlockChecker: () => this._routeChangeInvocations === 0,
65
+ // unlocked: () => this.config.onChildrenRouteChanged(re, this)
66
+ // }, {
67
+ // intervalId: this._childrenRouteChangedInterval,
68
+ // setIntervalId: (id) => this._childrenRouteChangedInterval = id,
69
+ // intervalTime: this.config?.childrenRouteChangedCheckIntervalTime ?? 30
70
+ // }, {
71
+ // setInterval: window.setInterval,
72
+ // clearInterval: window.clearInterval
73
+ // });
74
+
75
+ try {
76
+ // if (this._swc_notified_routes.get(instance) === re) {
77
+ // return;
78
+ // }
79
+ // this._swc_notified_routes.set(instance, re);
45
80
 
46
- // Path pattern matching (support both string and array)
47
- let pathMatched = false;
48
- let pathData: any = null;
49
-
50
- if (!pathPattern) {
51
- // pathPattern이 없으면 모든 경로 매칭 (와일드카드)
52
- pathMatched = true;
53
- pathData = {};
54
- } else if (Array.isArray(pathPattern)) {
55
- // 배열: 하나라도 매칭되면 OK
56
- for (const pattern of pathPattern) {
57
- const data = SwcUtils.parsePathPattern(pattern, re.path || '/');
58
- if (data !== null) {
59
- pathMatched = true;
60
- pathData = data;
61
- break;
81
+ const routeChangeSubscribers = getSubscribeSwcAppRouteChangeWhileConnectedMetadata(instance);
82
+ if (routeChangeSubscribers && Array.isArray(routeChangeSubscribers)) {
83
+ const ps = routeChangeSubscribers.map(async metadata => {
84
+ const methodName = metadata.propertyKey;
85
+ let pathPattern = metadata.options?.path as any;
86
+ const filter = metadata.options?.filter;
87
+
88
+ if (typeof pathPattern === 'function') {
89
+ pathPattern = (pathPattern as Function)(instance);
90
+ }
91
+
92
+ let pathMatched = false;
93
+ let pathData: any = null;
94
+
95
+ if (!pathPattern) {
96
+ pathMatched = true;
97
+ pathData = {};
98
+ } else if (Array.isArray(pathPattern)) {
99
+ for (const pattern of pathPattern) {
100
+ const data = SwcUtils.parsePathPattern(pattern, re.path || '/');
101
+ if (data !== null) {
102
+ pathMatched = true;
103
+ pathData = data;
104
+ break;
105
+ }
62
106
  }
107
+ } else {
108
+ pathData = SwcUtils.parsePathPattern(pathPattern, re.path || '/');
109
+ pathMatched = pathData !== null;
63
110
  }
64
- } else {
65
- // 문자열
66
- pathData = SwcUtils.parsePathPattern(pathPattern, re.path || '/');
67
- pathMatched = pathData !== null;
68
- }
69
111
 
70
- // Filter validation
71
- const filterPassed = !filter || filter(this.router!, instance);
112
+ const filterPassed = !filter || filter(this.router!, instance);
72
113
 
73
- // Invoke method if conditions pass
74
- if (pathMatched && filterPassed && instance[methodName]) {
75
- await instance[methodName]({ ...re, pathData: pathData });
76
- }
77
- });
78
- return await Promise.allSettled(ps);
114
+ if (pathMatched && filterPassed && instance[methodName]) {
115
+ await instance[methodName]({...re, pathData: pathData});
116
+ }
117
+ });
118
+ await Promise.allSettled(ps);
119
+ }
120
+ } finally {
121
+ this._routeChangeInvocations--;
79
122
  }
80
123
  }
81
124
 
82
- _connected(instance: any) {
83
- // console.log('appmixin--> connected', this, instance);
125
+ async _connected(instance: any) {
84
126
  if (instance) {
127
+ this._connectedInvocations++;
85
128
  this._swc_connected_instance.add(instance);
129
+
130
+ if (this._childrenConnectedDoneInterval) {
131
+ clearInterval(this._childrenConnectedDoneInterval);
132
+ }
133
+ this._childrenConnectedDoneInterval = debounceTimeIntervalLock(
134
+ () => this._connectedInvocations === 0,
135
+ () => {
136
+ this._childrenConnectedDoneInterval = null;
137
+ this.config.onChildrenConnectedDone(this)
138
+ },
139
+ this.config?.childrenConnectedDoneCheckIntervalTime ?? 30,
140
+ {setInterval: window.setInterval, clearInterval: window.clearInterval}
141
+ );
142
+
143
+
86
144
  if (this.simpleApplication) {
87
- this._invokeOnConnectedSwcAppStarted(instance);
88
- // Notify current route subscribers immediately after connection
89
- if (this.router && this._lastRouterEvent) {
90
- this._invokeRouteChangeSubscribers(instance, this._lastRouterEvent);
145
+ try {
146
+ // await this._invokeOnConnectedSwcAppStarted(instance);
147
+
148
+ if (this.router && this._lastRouterEvent) {
149
+ await this._invokeRouteChangeSubscribers(instance, this._lastRouterEvent!);
150
+ }
151
+ } catch (e) {
152
+ throw e;
91
153
  }
92
154
  }
93
155
  }
94
156
  }
95
157
 
158
+ async _connectedDone(instance: any) {
159
+ try {
160
+ // 내부 연결 처리 로직이 있다면 여기에 추가
161
+ } finally {
162
+ this._connectedInvocations--;
163
+ }
164
+ }
165
+
96
166
  _disconnected(instance: any) {
167
+ // console.log('_disconnected', instance);
97
168
  if (instance) {
98
169
  this._swc_connected_instance.delete(instance);
99
- this._swc_started_instances.delete(instance);
100
- this._swc_notified_routes.delete(instance);
170
+ // this._swc_notified_routes.delete(instance);
101
171
  }
102
172
  }
103
173
 
104
174
  async _handleRouteChange(route: RouterEventType) {
105
175
  // Save last router event
106
176
  this._lastRouterEvent = route;
107
- if (route.triggerPoint === 'end') {
108
- // Iterate through all connected component instances
109
- const swcConnectedInstance = Array.from(this._swc_connected_instance);
110
- const ps = swcConnectedInstance.map((instance: any) => this._invokeRouteChangeSubscribers(instance, route));
111
- await Promise.allSettled(ps);
112
- }
177
+ // if (route.triggerPoint === 'end') {
178
+ // Iterate through all connected component instances
179
+ const swcConnectedInstance = Array.from(this._swc_connected_instance);
180
+ // console.log('routing handle-->', swcConnectedInstance)
181
+ const ps = swcConnectedInstance.map((instance: any) => this._invokeRouteChangeSubscribers(instance, route));
182
+ await Promise.allSettled(ps);
183
+ // }
113
184
  }
114
185
 
115
186
  async connect(config?: SwcAttributeConfigType) {
116
187
  const swcConfig = {
117
188
  routeType: 'element',
118
- window: config.window,
189
+ window: config?.window,
119
190
  ...config
120
191
  } as SwcConfigType;
121
192
 
122
193
  const mode = config?.connectMode || 'direct';
123
194
 
124
- // console.log('-------mode', mode);
125
195
  if (mode === 'direct') {
126
196
  await this.__swc_engine.connect(swcConfig);
127
197
  this.setAttribute('swc-connect-mode', 'direct');
@@ -134,21 +204,21 @@ export function SwcAppMixin<T extends { new (...args: any[]): HTMLElement }>(Bas
134
204
  // 1. 현재 SSR 상태(화면)를 그대로 유지한 채로, 백그라운드용 클론을 만듭니다.
135
205
  const clonedApp = this.cloneNode(mode === 'swap') as any; // clear-swap 모드면 자식 노드를 클론하지 않음(false)
136
206
  clonedApp.style.display = 'none';
137
-
207
+
138
208
  // 2. DOM에 클론을 몰래 붙입니다.
139
209
  this.parentNode.insertBefore(clonedApp, this.nextSibling);
140
210
 
141
211
  try {
142
212
  // 3. 클론을 direct 모드로 연결(초기화/렌더링) 시킵니다.
143
- await clonedApp.connect({ ...(config || {}), connectMode: 'direct' });
144
-
213
+ await clonedApp.connect({...(config || {}), connectMode: 'direct'});
214
+
145
215
  // 4. 클론의 렌더링이 완전히 끝나면, 기존 SSR 화면(this)을 지우고 클론을 보여줍니다.
146
216
  if (this.parentNode) {
147
217
  this.parentNode.removeChild(this);
148
218
  }
149
219
  clonedApp.style.display = '';
150
220
  clonedApp.setAttribute('swc-connect-mode', mode);
151
-
221
+
152
222
  // ★ 매우 중요: 교체가 완료되었으므로 기존 앱(this)은 여기서 즉시 종료하여 불필요한 라우터/이벤트 구독을 막아야 합니다!
153
223
  return;
154
224
  } catch (e) {
@@ -164,12 +234,16 @@ export function SwcAppMixin<T extends { new (...args: any[]): HTMLElement }>(Bas
164
234
 
165
235
  // 사파리일떄 예외이다 is 일때 polyfill되는데 이떄 부모부터 만들어지는게 아니라 자식부터 만들어진다 그래서 부모가 만들어질때 자식들이 이미 만들어져있어서 부모가 자식들을 등록해주는 형태로 강제로 등록해준다
166
236
  this._connected_safari.forEach((instance: any) => {
167
- this._swc_connected_instance.add(instance);
237
+ // console.log('safari!!!!!!!!!!', instance)
238
+ this._connected(instance);
239
+ // this._swc_connected_instance.add(instance);
168
240
  });
169
241
  // Invoke @onConnectedSwcApp lifecycle methods on all connected component instances
170
242
  // const hostSet = SwcUtils.getHostSet(this as any);
171
- const scis = Array.from(this._swc_connected_instance);
172
- await Promise.allSettled(scis.map(instance => this._invokeOnConnectedSwcAppStarted(instance)));
243
+
244
+ // const scis = Array.from(this._swc_connected_instance);
245
+ // await Promise.allSettled(scis.map(instance => this._invokeOnConnectedSwcAppStarted(instance)));
246
+
173
247
  // this._swc_connected_instance.forEach((instance: any) => {
174
248
  // this._invokeOnConnectedSwcAppStarted(instance);
175
249
  // });
@@ -177,36 +251,42 @@ export function SwcAppMixin<T extends { new (...args: any[]): HTMLElement }>(Bas
177
251
  // Subscribe to router changes after connect
178
252
  if (!this._routerSubscription && this.router) {
179
253
  const config = this.__swc_engine.config;
180
- this._routerSubscription = this.router.observable.subscribe((route: RouterEventType) => {
181
- //@ts-ignore
182
- // console.log('Route changed:', route, this._swcId);
183
- this._handleRouteChange(route).then(it => {
184
- config?.onRouteChanged?.(route, this);
185
- });
254
+
255
+ this._routerSubscription = this.router.observable.subscribe(async (route: RouterEventType) => {
256
+ // console.log('[SWC] Router event received:', route.triggerPoint);
257
+ if (route.triggerPoint === 'end') {
258
+ // 1. 모든 기존 연결된 자식들에게 라우트 이벤트 알림
259
+ await this._handleRouteChange(route);
260
+ }
186
261
  });
262
+
187
263
  // Navigate to initial path if specified
188
- // if (config?.path) {
189
- // this.router.go(config.path);
190
- // }
264
+ if (config?.path) {
265
+ // console.log('[DEBUG] Navigating to initial path:', config.path);
266
+ this.router.go(config.path);
267
+ }
191
268
  }
192
269
  }
193
270
 
194
- async _invokeOnConnectedSwcAppStarted(instance: any) {
195
- // 이미 시작된 인스턴스라면 스킵 (비동기 병렬 중복 호출 방지)
196
- if (this._swc_started_instances.has(instance)) return;
197
- this._swc_started_instances.add(instance);
198
-
199
- const startedMethods = findAllLifecycleMetadata(instance, ON_CONNECTED_SWC_APP_METADATA_KEY);
200
- if (startedMethods) {
201
- const ps = startedMethods.map(m => instance._invokeLifecycleMethod(m));
202
- return await Promise.allSettled(ps)
203
- // for (const m of startedMethods) {
204
- // instance._invokeLifecycleMethod(m);
205
- // }
206
- }
207
- }
271
+ // async _invokeOnConnectedSwcAppStarted(instance: any) {
272
+ // this._swcAppStartedInvocations++;
273
+ // try {
274
+ // // 이미 시작된 인스턴스라면 스킵 (비동기 병렬 중복 호출 방지)
275
+ // if (this._swc_started_instances.has(instance)) return;
276
+ // this._swc_started_instances.add(instance);
277
+ //
278
+ // const startedMethods = findAllLifecycleMetadata(instance, ON_CONNECTED_SWC_APP_METADATA_KEY);
279
+ // if (startedMethods) {
280
+ // const ps = startedMethods.map(m => instance._invokeLifecycleMethod(m));
281
+ // await Promise.allSettled(ps);
282
+ // }
283
+ // } finally {
284
+ // this._swcAppStartedInvocations--;
285
+ // }
286
+ // }
208
287
 
209
288
  connectedCallback() {
289
+ // this.innerHTML='';
210
290
  // @ts-ignore
211
291
  if (super.connectedCallback) super.connectedCallback();
212
292
 
@@ -1,17 +1,16 @@
1
- import { changedAttributeHost } from '../decorators/changedAttributeHost';
1
+ import { changedAttributeThis } from '../decorators/changedAttributeThis';
2
2
  import { SwcUtils } from '../utils/Utils';
3
3
  import { FunctionUtils, ActionExpression } from '@dooboostore/core';
4
4
  import { ConvertUtils } from '@dooboostore/core-web';
5
- import { attributeHost } from '../decorators';
5
+ import { attributeThis } from '../decorators';
6
6
 
7
7
  class SwcAsync extends HTMLTemplateElement {
8
- @attributeHost('value')
8
+ @attributeThis('value')
9
9
  _value: any;
10
-
11
- @attributeHost('replace-wrap')
12
- _replaceWrap: string | null;
13
-
14
- resultValue?: any;
10
+ @attributeThis('replace-wrap-start')
11
+ _replaceWrapStart: string | null;
12
+ @attributeThis('replace-wrap-end')
13
+ _replaceWrapEnd: string | null; resultValue?: any;
15
14
 
16
15
  get value(): boolean {
17
16
  return this._value;
@@ -23,15 +22,15 @@ class SwcAsync extends HTMLTemplateElement {
23
22
 
24
23
  private _nodes: Node[] = [];
25
24
 
26
- @changedAttributeHost('value')
25
+ @changedAttributeThis('value')
27
26
  private setValue(valueAttr?: string | null) {
28
27
  this.executeAsync(this._value);
29
28
  }
30
29
 
31
- @changedAttributeHost('replace-wrap')
32
- private setReplaceWrap() {
33
- this.executeAsync(this._value);
34
- }
30
+ // @changedAttributeThis('replace-wrap')
31
+ // private setReplaceWrap() {
32
+ // this.executeAsync(this._value);
33
+ // }
35
34
 
36
35
  private executeAsync(result: any = this._value) {
37
36
  if (result === undefined || result === null) {
@@ -57,14 +56,22 @@ class SwcAsync extends HTMLTemplateElement {
57
56
  }
58
57
  }
59
58
 
60
- private replaceExpressions(html: string, groupArgs: any, context: any, wrap?: string | null): string {
61
- const config = wrap ? { wrapExpression: wrap } : undefined;
59
+ private replaceExpressions(html: string, groupArgs: any, context: any, wrap: {start: string, end: string}): string {
60
+ let config: any = undefined;
61
+ if (wrap) {
62
+ config = {
63
+ expression: {
64
+ replace: { start: `${wrap.start}`, end: `${wrap.end}` },
65
+ callReturn: { start: `${wrap.start}=`, end: `${wrap.end}` },
66
+ call: { start: `${wrap.start}@`, end: `${wrap.end}` }
67
+ }
68
+ };
69
+ }
62
70
  const ae = new ActionExpression(html, config);
63
- const filterOptions = wrap ? { type: 'replace' as const, wrap } : 'replace';
64
71
  const win = this.ownerDocument?.defaultView || window;
65
72
 
66
73
  // @ts-ignore
67
- for (const expr of ae.getExpressions(filterOptions)) {
74
+ for (const expr of ae.getExpressions('replace')) {
68
75
  try {
69
76
  const value = FunctionUtils.executeReturn({
70
77
  script: ConvertUtils.decodeHtmlEntity(expr.script, win.document),
@@ -80,9 +87,9 @@ class SwcAsync extends HTMLTemplateElement {
80
87
  }
81
88
 
82
89
  refresh(state: string = 'default') {
83
- console.log('rrrrrrrrrrrrrrrrr', state);
90
+ // console.log('rrrrrrrrrrrrrrrrr', state);
84
91
  this.cleanup();
85
- const portal = this.parentElement;
92
+ const portal = SwcUtils.getParentContainer(this);
86
93
  if (!portal) return;
87
94
 
88
95
  const win = this.ownerDocument?.defaultView || window;
@@ -91,15 +98,19 @@ class SwcAsync extends HTMLTemplateElement {
91
98
  const t = this.content.querySelector(`template[is="swc-${state}"]`) as HTMLTemplateElement;
92
99
  if (t) {
93
100
  let htmlString = t.innerHTML;
94
- const groupArgs = { ...helperSet, $value: this._value, $state: state };
101
+ const groupArgs = { ...helperSet, $value: this._value, $state: state, $templateHost: this };
95
102
 
96
- htmlString = this.replaceExpressions(htmlString, groupArgs, this, this._replaceWrap);
103
+ htmlString = this.replaceExpressions(htmlString, groupArgs, this, {start:this._replaceWrapStart ?? '{#{', end: this._replaceWrapEnd ?? '}#}'});
97
104
 
98
105
  const temp = this.ownerDocument?.createElement('template') || document.createElement('template');
99
106
  temp.innerHTML = htmlString;
100
107
  const content = temp.content;
101
108
 
102
109
  this._nodes = Array.from(content.childNodes);
110
+ this._nodes.forEach((node: any) => {
111
+ if (node instanceof HTMLElement) (node as any).__template_swc_host = this;
112
+ });
113
+
103
114
  portal.insertBefore(content, this.nextSibling);
104
115
  }
105
116
  }