@dooboostore/simple-web-component 1.0.33 → 1.0.35

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 (150) hide show
  1. package/README.md +23 -30
  2. package/dist/cjs/decorators/addEventListener.js.map +1 -1
  3. package/dist/cjs/decorators/applyAttribute.js +67 -57
  4. package/dist/cjs/decorators/applyAttribute.js.map +2 -2
  5. package/dist/cjs/decorators/applyClass.js +80 -70
  6. package/dist/cjs/decorators/applyClass.js.map +2 -2
  7. package/dist/cjs/decorators/applyNode.js +5 -8
  8. package/dist/cjs/decorators/applyNode.js.map +2 -2
  9. package/dist/cjs/decorators/applyStyle.js +66 -56
  10. package/dist/cjs/decorators/applyStyle.js.map +2 -2
  11. package/dist/cjs/decorators/attribute.js +35 -29
  12. package/dist/cjs/decorators/attribute.js.map +2 -2
  13. package/dist/cjs/decorators/changedAttributeHost.js +32 -12
  14. package/dist/cjs/decorators/changedAttributeHost.js.map +2 -2
  15. package/dist/cjs/decorators/elementDefine.js +238 -180
  16. package/dist/cjs/decorators/elementDefine.js.map +2 -2
  17. package/dist/cjs/decorators/emitCustomEvent.js +67 -48
  18. package/dist/cjs/decorators/emitCustomEvent.js.map +2 -2
  19. package/dist/cjs/decorators/lifecycles.js +15 -17
  20. package/dist/cjs/decorators/lifecycles.js.map +2 -2
  21. package/dist/cjs/decorators/setProperty.js +50 -39
  22. package/dist/cjs/decorators/setProperty.js.map +2 -2
  23. package/dist/cjs/decorators/subscribeSwcAppMessageWhileConnected.js.map +1 -1
  24. package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js +2 -2
  25. package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +2 -2
  26. package/dist/cjs/elements/SwcAppEngine.js +14 -8
  27. package/dist/cjs/elements/SwcAppEngine.js.map +3 -3
  28. package/dist/cjs/elements/SwcAppMixin.js +154 -81
  29. package/dist/cjs/elements/SwcAppMixin.js.map +2 -2
  30. package/dist/cjs/elements/SwcAsync.js +28 -18
  31. package/dist/cjs/elements/SwcAsync.js.map +2 -2
  32. package/dist/cjs/elements/SwcChoose.js +68 -45
  33. package/dist/cjs/elements/SwcChoose.js.map +2 -2
  34. package/dist/cjs/elements/SwcIf.js +52 -30
  35. package/dist/cjs/elements/SwcIf.js.map +2 -2
  36. package/dist/cjs/elements/SwcLoop.js +109 -35
  37. package/dist/cjs/elements/SwcLoop.js.map +2 -2
  38. package/dist/cjs/elements/register.js +263 -131
  39. package/dist/cjs/elements/register.js.map +2 -2
  40. package/dist/cjs/router/ElementRouter.js +4 -2
  41. package/dist/cjs/router/ElementRouter.js.map +1 -1
  42. package/dist/cjs/types.js.map +1 -1
  43. package/dist/cjs/utils/Utils.js +25 -7
  44. package/dist/cjs/utils/Utils.js.map +2 -2
  45. package/dist/esm/decorators/addEventListener.js.map +1 -1
  46. package/dist/esm/decorators/applyAttribute.js +67 -57
  47. package/dist/esm/decorators/applyAttribute.js.map +2 -2
  48. package/dist/esm/decorators/applyClass.js +80 -70
  49. package/dist/esm/decorators/applyClass.js.map +2 -2
  50. package/dist/esm/decorators/applyNode.js +5 -8
  51. package/dist/esm/decorators/applyNode.js.map +2 -2
  52. package/dist/esm/decorators/applyStyle.js +66 -56
  53. package/dist/esm/decorators/applyStyle.js.map +2 -2
  54. package/dist/esm/decorators/attribute.js +35 -29
  55. package/dist/esm/decorators/attribute.js.map +2 -2
  56. package/dist/esm/decorators/changedAttributeHost.js +32 -12
  57. package/dist/esm/decorators/changedAttributeHost.js.map +2 -2
  58. package/dist/esm/decorators/elementDefine.js +240 -182
  59. package/dist/esm/decorators/elementDefine.js.map +2 -2
  60. package/dist/esm/decorators/emitCustomEvent.js +67 -48
  61. package/dist/esm/decorators/emitCustomEvent.js.map +2 -2
  62. package/dist/esm/decorators/lifecycles.js +15 -17
  63. package/dist/esm/decorators/lifecycles.js.map +2 -2
  64. package/dist/esm/decorators/setProperty.js +50 -39
  65. package/dist/esm/decorators/setProperty.js.map +2 -2
  66. package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js.map +1 -1
  67. package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js +2 -2
  68. package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +2 -2
  69. package/dist/esm/elements/SwcAppEngine.js +14 -7
  70. package/dist/esm/elements/SwcAppEngine.js.map +2 -2
  71. package/dist/esm/elements/SwcAppMixin.js +156 -82
  72. package/dist/esm/elements/SwcAppMixin.js.map +2 -2
  73. package/dist/esm/elements/SwcAsync.js +28 -18
  74. package/dist/esm/elements/SwcAsync.js.map +2 -2
  75. package/dist/esm/elements/SwcChoose.js +69 -46
  76. package/dist/esm/elements/SwcChoose.js.map +2 -2
  77. package/dist/esm/elements/SwcIf.js +53 -31
  78. package/dist/esm/elements/SwcIf.js.map +2 -2
  79. package/dist/esm/elements/SwcLoop.js +110 -36
  80. package/dist/esm/elements/SwcLoop.js.map +2 -2
  81. package/dist/esm/elements/register.js +264 -132
  82. package/dist/esm/elements/register.js.map +2 -2
  83. package/dist/esm/router/ElementRouter.js +5 -2
  84. package/dist/esm/router/ElementRouter.js.map +1 -1
  85. package/dist/esm/types.js.map +1 -1
  86. package/dist/esm/utils/Utils.js +25 -7
  87. package/dist/esm/utils/Utils.js.map +2 -2
  88. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +728 -595
  89. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
  90. package/dist/types/decorators/addEventListener.d.ts +4 -1
  91. package/dist/types/decorators/addEventListener.d.ts.map +1 -1
  92. package/dist/types/decorators/applyAttribute.d.ts +5 -1
  93. package/dist/types/decorators/applyAttribute.d.ts.map +1 -1
  94. package/dist/types/decorators/applyClass.d.ts +4 -0
  95. package/dist/types/decorators/applyClass.d.ts.map +1 -1
  96. package/dist/types/decorators/applyNode.d.ts +5 -1
  97. package/dist/types/decorators/applyNode.d.ts.map +1 -1
  98. package/dist/types/decorators/applyStyle.d.ts +5 -1
  99. package/dist/types/decorators/applyStyle.d.ts.map +1 -1
  100. package/dist/types/decorators/attribute.d.ts +5 -0
  101. package/dist/types/decorators/attribute.d.ts.map +1 -1
  102. package/dist/types/decorators/changedAttributeHost.d.ts +14 -3
  103. package/dist/types/decorators/changedAttributeHost.d.ts.map +1 -1
  104. package/dist/types/decorators/elementDefine.d.ts +1 -1
  105. package/dist/types/decorators/elementDefine.d.ts.map +1 -1
  106. package/dist/types/decorators/emitCustomEvent.d.ts +15 -7
  107. package/dist/types/decorators/emitCustomEvent.d.ts.map +1 -1
  108. package/dist/types/decorators/lifecycles.d.ts +10 -7
  109. package/dist/types/decorators/lifecycles.d.ts.map +1 -1
  110. package/dist/types/decorators/setProperty.d.ts +5 -1
  111. package/dist/types/decorators/setProperty.d.ts.map +1 -1
  112. package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts +2 -2
  113. package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts.map +1 -1
  114. package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts +5 -6
  115. package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts.map +1 -1
  116. package/dist/types/elements/SwcAppEngine.d.ts +9 -3
  117. package/dist/types/elements/SwcAppEngine.d.ts.map +1 -1
  118. package/dist/types/elements/SwcAppMixin.d.ts +12 -7
  119. package/dist/types/elements/SwcAppMixin.d.ts.map +1 -1
  120. package/dist/types/elements/register.d.ts.map +1 -1
  121. package/dist/types/types.d.ts +1 -0
  122. package/dist/types/types.d.ts.map +1 -1
  123. package/dist/types/utils/Utils.d.ts +4 -1
  124. package/dist/types/utils/Utils.d.ts.map +1 -1
  125. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +728 -595
  126. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
  127. package/package.json +5 -5
  128. package/src/decorators/addEventListener.ts +1 -1
  129. package/src/decorators/applyAttribute.ts +74 -61
  130. package/src/decorators/applyClass.ts +91 -77
  131. package/src/decorators/applyNode.ts +16 -13
  132. package/src/decorators/applyStyle.ts +75 -61
  133. package/src/decorators/attribute.ts +55 -43
  134. package/src/decorators/changedAttributeHost.ts +49 -15
  135. package/src/decorators/elementDefine.ts +401 -340
  136. package/src/decorators/emitCustomEvent.ts +92 -62
  137. package/src/decorators/lifecycles.ts +11 -10
  138. package/src/decorators/setProperty.ts +58 -44
  139. package/src/decorators/subscribeSwcAppMessageWhileConnected.ts +2 -2
  140. package/src/decorators/subscribeSwcAppRouteChangeWhileConnected.ts +11 -11
  141. package/src/elements/SwcAppEngine.ts +19 -13
  142. package/src/elements/SwcAppMixin.ts +214 -102
  143. package/src/elements/SwcAsync.ts +28 -17
  144. package/src/elements/SwcChoose.ts +94 -36
  145. package/src/elements/SwcIf.ts +59 -22
  146. package/src/elements/SwcLoop.ts +140 -27
  147. package/src/elements/register.ts +319 -100
  148. package/src/types.ts +1 -0
  149. package/src/utils/Utils.ts +38 -10
  150. package/tsconfig.json +2 -2
@@ -1,19 +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>();
14
+ // _swc_notified_routes = new WeakMap<any, RouterEventType>();
15
15
  _routerSubscription?: Subscription;
16
16
  _lastRouterEvent?: RouterEventType;
17
+ _routeChangeInvocations = 0;
18
+ _connectedInvocations = 0;
19
+
20
+ _childrenRouteChangedInterval: any;
21
+ _childrenConnectedDoneInterval: any;
17
22
 
18
23
  /*
19
24
  사파리 is 일경우
@@ -22,92 +27,166 @@ export function SwcAppMixin<T extends { new (...args: any[]): HTMLElement }>(Bas
22
27
  저 polyfill에서는 자식부터 만들어지고 부모가 만들어진다 is일때 아 .. 이문제때문에 자식이 _connected_safari 에 강제로 자기자식넣어준다
23
28
  */
24
29
  _connected_safari = [];
30
+
25
31
  get simpleApplication() {
26
32
  return this.__swc_engine.simpleApplication;
27
33
  }
34
+
35
+ get config() {
36
+ return this.__swc_engine?.config;
37
+ }
38
+
28
39
  get router() {
29
- return this.__swc_engine.router;
40
+ return this.__swc_engine?.router;
30
41
  }
31
42
 
32
- _invokeRouteChangeSubscribers(instance: any, re: RouterEventType) {
33
- const routeChangeSubscribers = getSubscribeSwcAppRouteChangeWhileConnectedMetadata(instance);
34
- if (routeChangeSubscribers && Array.isArray(routeChangeSubscribers)) {
35
- routeChangeSubscribers.forEach((metadata: any) => {
36
- const methodName = metadata.propertyKey || metadata;
37
- const pathPattern = metadata.pathPattern;
38
- const filter = metadata.filter;
43
+ async _invokeRouteChangeSubscribers(instance: any, re: RouterEventType) {
44
+ if (instance.isConnected === false) return;
45
+
46
+ this._routeChangeInvocations++;
39
47
 
40
- // Path pattern matching (support both string and array)
41
- let pathMatched = false;
42
- let pathData: any = null;
43
-
44
- if (!pathPattern) {
45
- // pathPattern이 없으면 모든 경로 매칭 (와일드카드)
46
- pathMatched = true;
47
- pathData = {};
48
- } else if (Array.isArray(pathPattern)) {
49
- // 배열: 하나라도 매칭되면 OK
50
- for (const pattern of pathPattern) {
51
- const data = SwcUtils.parsePathPattern(pattern, re.path || '/');
52
- if (data !== null) {
53
- pathMatched = true;
54
- pathData = data;
55
- break;
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);
80
+
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
+ }
56
106
  }
107
+ } else {
108
+ pathData = SwcUtils.parsePathPattern(pathPattern, re.path || '/');
109
+ pathMatched = pathData !== null;
57
110
  }
58
- } else {
59
- // 문자열
60
- pathData = SwcUtils.parsePathPattern(pathPattern, re.path || '/');
61
- pathMatched = pathData !== null;
62
- }
63
111
 
64
- // Filter validation
65
- const filterPassed = !filter || filter(this.router!);
112
+ const filterPassed = !filter || filter(this.router!, instance);
66
113
 
67
- // Invoke method if conditions pass
68
- if (pathMatched && filterPassed) {
69
- instance[methodName]?.({...re, pathData: pathData});
70
- }
71
- });
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--;
72
122
  }
73
123
  }
74
124
 
75
- _connected(instance: any) {
76
- // console.log('appmixin--> connected', this, instance);
125
+ async _connected(instance: any) {
77
126
  if (instance) {
127
+ this._connectedInvocations++;
78
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
+
79
144
  if (this.simpleApplication) {
80
- this._invokeOnConnectedSwcAppStarted(instance);
81
- // Notify current route subscribers immediately after connection
82
- if (this.router && this._lastRouterEvent) {
83
- 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;
84
153
  }
85
154
  }
86
155
  }
87
156
  }
88
157
 
158
+ async _connectedDone(instance: any) {
159
+ try {
160
+ // 내부 연결 처리 로직이 있다면 여기에 추가
161
+ } finally {
162
+ this._connectedInvocations--;
163
+ }
164
+ }
165
+
89
166
  _disconnected(instance: any) {
167
+ // console.log('_disconnected', instance);
90
168
  if (instance) {
91
169
  this._swc_connected_instance.delete(instance);
170
+ // this._swc_notified_routes.delete(instance);
92
171
  }
93
172
  }
94
173
 
95
- _handleRouteChange(route: RouterEventType) {
96
- if (route.triggerPoint === 'end') {
97
- // Iterate through all connected component instances
98
- this._swc_connected_instance.forEach((instance: any) => {
99
- this._invokeRouteChangeSubscribers(instance, route);
100
- });
101
- }
102
-
174
+ async _handleRouteChange(route: RouterEventType) {
103
175
  // Save last router event
104
176
  this._lastRouterEvent = route;
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
+ // }
105
184
  }
106
185
 
107
186
  async connect(config?: SwcAttributeConfigType) {
108
187
  const swcConfig = {
109
188
  routeType: 'element',
110
- window: config.window,
189
+ window: config?.window,
111
190
  ...config
112
191
  } as SwcConfigType;
113
192
 
@@ -116,65 +195,98 @@ export function SwcAppMixin<T extends { new (...args: any[]): HTMLElement }>(Bas
116
195
  if (mode === 'direct') {
117
196
  await this.__swc_engine.connect(swcConfig);
118
197
  this.setAttribute('swc-connect-mode', 'direct');
119
- } else if (mode === 'swap' && !this.parentNode) {
120
- await this.__swc_engine.connect(swcConfig);
121
- this.setAttribute('swc-connect-mode', 'direct');
122
-
123
- const clonedApp = this.cloneNode(true) as any;
124
- clonedApp.style.display = 'none';
125
- this.parentNode.insertBefore(clonedApp, this.nextSibling);
126
-
127
- try {
128
- await clonedApp.connect({ ...(config || {}), connectMode: 'direct' });
129
- if (this.parentNode) {
130
- this.parentNode.removeChild(this);
131
- }
132
- clonedApp.setAttribute('swc-connect-mode', 'swap');
133
- clonedApp.style.display = '';
134
- } catch (e) {
135
- if (clonedApp.parentNode) {
136
- clonedApp.parentNode.removeChild(clonedApp);
198
+ } else if (mode === 'swap' || mode === 'clear-swap') {
199
+ if (!this.parentNode) {
200
+ // 부모가 없으면 swap을 할 수 없으므로 direct로 폴백합니다.
201
+ await this.__swc_engine.connect(swcConfig);
202
+ this.setAttribute('swc-connect-mode', 'direct');
203
+ } else {
204
+ // 1. 현재 SSR 상태(화면)를 그대로 유지한 채로, 백그라운드용 클론을 만듭니다.
205
+ const clonedApp = this.cloneNode(mode === 'swap') as any; // clear-swap 모드면 자식 노드를 클론하지 않음(false)
206
+ clonedApp.style.display = 'none';
207
+
208
+ // 2. DOM에 클론을 몰래 붙입니다.
209
+ this.parentNode.insertBefore(clonedApp, this.nextSibling);
210
+
211
+ try {
212
+ // 3. 클론을 direct 모드로 연결(초기화/렌더링) 시킵니다.
213
+ await clonedApp.connect({...(config || {}), connectMode: 'direct'});
214
+
215
+ // 4. 클론의 렌더링이 완전히 끝나면, 기존 SSR 화면(this)을 지우고 클론을 보여줍니다.
216
+ if (this.parentNode) {
217
+ this.parentNode.removeChild(this);
218
+ }
219
+ clonedApp.style.display = '';
220
+ clonedApp.setAttribute('swc-connect-mode', mode);
221
+
222
+ // ★ 매우 중요: 교체가 완료되었으므로 기존 앱(this)은 여기서 즉시 종료하여 불필요한 라우터/이벤트 구독을 막아야 합니다!
223
+ return;
224
+ } catch (e) {
225
+ // 실패 시 클론을 지우고 원본을 direct로 강제 연결합니다.
226
+ if (clonedApp.parentNode) {
227
+ clonedApp.parentNode.removeChild(clonedApp);
228
+ }
229
+ await this.__swc_engine.connect(swcConfig);
230
+ this.setAttribute('swc-connect-mode', 'direct');
137
231
  }
138
- throw e;
139
232
  }
140
233
  }
141
234
 
142
235
  // 사파리일떄 예외이다 is 일때 polyfill되는데 이떄 부모부터 만들어지는게 아니라 자식부터 만들어진다 그래서 부모가 만들어질때 자식들이 이미 만들어져있어서 부모가 자식들을 등록해주는 형태로 강제로 등록해준다
143
236
  this._connected_safari.forEach((instance: any) => {
144
- this._swc_connected_instance.add(instance);
237
+ // console.log('safari!!!!!!!!!!', instance)
238
+ this._connected(instance);
239
+ // this._swc_connected_instance.add(instance);
145
240
  });
146
241
  // Invoke @onConnectedSwcApp lifecycle methods on all connected component instances
147
242
  // const hostSet = SwcUtils.getHostSet(this as any);
148
- this._swc_connected_instance.forEach((instance: any) => {
149
- this._invokeOnConnectedSwcAppStarted(instance);
150
- });
151
243
 
244
+ // const scis = Array.from(this._swc_connected_instance);
245
+ // await Promise.allSettled(scis.map(instance => this._invokeOnConnectedSwcAppStarted(instance)));
246
+
247
+ // this._swc_connected_instance.forEach((instance: any) => {
248
+ // this._invokeOnConnectedSwcAppStarted(instance);
249
+ // });
152
250
 
153
251
  // Subscribe to router changes after connect
154
252
  if (!this._routerSubscription && this.router) {
155
- this._routerSubscription = this.router.observable.subscribe((route: RouterEventType) => {
156
- //@ts-ignore
157
- // console.log('Route changed:', route, this._swcId);
158
- this._handleRouteChange(route);
159
- });
160
- // Navigate to initial path if specified
161
253
  const config = this.__swc_engine.config;
162
- // if (config?.path) {
163
- // this.router.go(config.path);
164
- // }
165
- }
166
- }
167
254
 
168
- _invokeOnConnectedSwcAppStarted(instance: any) {
169
- const startedMethods = findAllLifecycleMetadata(instance, ON_CONNECTED_SWC_APP_METADATA_KEY);
170
- if (startedMethods) {
171
- for (const m of startedMethods) {
172
- instance._invokeLifecycleMethod(m);
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
+ }
261
+ });
262
+
263
+ // Navigate to initial path if specified
264
+ if (config?.path) {
265
+ // console.log('[DEBUG] Navigating to initial path:', config.path);
266
+ this.router.go(config.path);
173
267
  }
174
268
  }
175
269
  }
176
270
 
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
+ // }
287
+
177
288
  connectedCallback() {
289
+ // this.innerHTML='';
178
290
  // @ts-ignore
179
291
  if (super.connectedCallback) super.connectedCallback();
180
292
 
@@ -233,7 +345,7 @@ export function SwcAppMixin<T extends { new (...args: any[]): HTMLElement }>(Bas
233
345
  _invokeMessageSubscribers(instance: any, message: SwcAppMessage) {
234
346
  const messageSubscribers = getSubscribeSwcAppMessageWhileConnectedMetadata(instance);
235
347
  if (messageSubscribers && Array.isArray(messageSubscribers)) {
236
- messageSubscribers.forEach((metadata: any) => {
348
+ messageSubscribers.forEach(metadata => {
237
349
  const methodName = metadata.propertyKey;
238
350
  const messageType = metadata.messageType;
239
351
  const filter = metadata.filter;
@@ -250,7 +362,7 @@ export function SwcAppMixin<T extends { new (...args: any[]): HTMLElement }>(Bas
250
362
  // 필터 적용
251
363
  let filterMatched = true;
252
364
  if (filter && typeMatched) {
253
- filterMatched = filter(message);
365
+ filterMatched = filter(message, instance);
254
366
  }
255
367
 
256
368
  // 조건을 만족하면 메서드 호출
@@ -7,11 +7,10 @@ import { attributeHost } from '../decorators';
7
7
  class SwcAsync extends HTMLTemplateElement {
8
8
  @attributeHost('value')
9
9
  _value: any;
10
-
11
- @attributeHost('replace-wrap')
12
- _replaceWrap: string | null;
13
-
14
- resultValue?: any;
10
+ @attributeHost('replace-wrap-start')
11
+ _replaceWrapStart: string | null;
12
+ @attributeHost('replace-wrap-end')
13
+ _replaceWrapEnd: string | null; resultValue?: any;
15
14
 
16
15
  get value(): boolean {
17
16
  return this._value;
@@ -28,10 +27,10 @@ class SwcAsync extends HTMLTemplateElement {
28
27
  this.executeAsync(this._value);
29
28
  }
30
29
 
31
- @changedAttributeHost('replace-wrap')
32
- private setReplaceWrap() {
33
- this.executeAsync(this._value);
34
- }
30
+ // @changedAttributeHost('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
  }