@dooboostore/simple-web-component 1.0.25 → 1.0.27

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 (82) hide show
  1. package/README.md +284 -68
  2. package/dist/cjs/decorators/attribute.js +32 -43
  3. package/dist/cjs/decorators/attribute.js.map +3 -3
  4. package/dist/cjs/decorators/elementDefine.js +33 -19
  5. package/dist/cjs/decorators/elementDefine.js.map +2 -2
  6. package/dist/cjs/decorators/index.js +1 -0
  7. package/dist/cjs/decorators/index.js.map +2 -2
  8. package/dist/cjs/decorators/lifecycles.js +5 -5
  9. package/dist/cjs/decorators/lifecycles.js.map +2 -2
  10. package/dist/cjs/decorators/query.js +4 -4
  11. package/dist/cjs/decorators/query.js.map +2 -2
  12. package/dist/cjs/decorators/queryAll.js +4 -4
  13. package/dist/cjs/decorators/queryAll.js.map +2 -2
  14. package/dist/cjs/decorators/subscribeSwcAppRouteChange.js +59 -0
  15. package/dist/cjs/decorators/subscribeSwcAppRouteChange.js.map +7 -0
  16. package/dist/cjs/elements/SwcAppEngine.js +18 -63
  17. package/dist/cjs/elements/SwcAppEngine.js.map +3 -3
  18. package/dist/cjs/elements/SwcAppMixin.js +103 -24
  19. package/dist/cjs/elements/SwcAppMixin.js.map +2 -2
  20. package/dist/cjs/elements/register.js +0 -1
  21. package/dist/cjs/elements/register.js.map +2 -2
  22. package/dist/cjs/utils/Utils.js +18 -0
  23. package/dist/cjs/utils/Utils.js.map +3 -3
  24. package/dist/esm/decorators/attribute.js +32 -43
  25. package/dist/esm/decorators/attribute.js.map +3 -3
  26. package/dist/esm/decorators/elementDefine.js +34 -20
  27. package/dist/esm/decorators/elementDefine.js.map +2 -2
  28. package/dist/esm/decorators/index.js +1 -0
  29. package/dist/esm/decorators/index.js.map +2 -2
  30. package/dist/esm/decorators/lifecycles.js +5 -5
  31. package/dist/esm/decorators/lifecycles.js.map +2 -2
  32. package/dist/esm/decorators/query.js +4 -4
  33. package/dist/esm/decorators/query.js.map +2 -2
  34. package/dist/esm/decorators/queryAll.js +4 -4
  35. package/dist/esm/decorators/queryAll.js.map +2 -2
  36. package/dist/esm/decorators/subscribeSwcAppRouteChange.js +40 -0
  37. package/dist/esm/decorators/subscribeSwcAppRouteChange.js.map +7 -0
  38. package/dist/esm/elements/SwcAppEngine.js +18 -63
  39. package/dist/esm/elements/SwcAppEngine.js.map +2 -2
  40. package/dist/esm/elements/SwcAppMixin.js +103 -24
  41. package/dist/esm/elements/SwcAppMixin.js.map +2 -2
  42. package/dist/esm/elements/register.js +0 -1
  43. package/dist/esm/elements/register.js.map +2 -2
  44. package/dist/esm/utils/Utils.js +18 -0
  45. package/dist/esm/utils/Utils.js.map +3 -3
  46. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +135 -2470
  47. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
  48. package/dist/types/decorators/attribute.d.ts +0 -1
  49. package/dist/types/decorators/attribute.d.ts.map +1 -1
  50. package/dist/types/decorators/elementDefine.d.ts.map +1 -1
  51. package/dist/types/decorators/index.d.ts +1 -0
  52. package/dist/types/decorators/index.d.ts.map +1 -1
  53. package/dist/types/decorators/lifecycles.d.ts +2 -2
  54. package/dist/types/decorators/lifecycles.d.ts.map +1 -1
  55. package/dist/types/decorators/query.d.ts +1 -1
  56. package/dist/types/decorators/query.d.ts.map +1 -1
  57. package/dist/types/decorators/queryAll.d.ts +1 -1
  58. package/dist/types/decorators/queryAll.d.ts.map +1 -1
  59. package/dist/types/decorators/subscribeSwcAppRouteChange.d.ts +18 -0
  60. package/dist/types/decorators/subscribeSwcAppRouteChange.d.ts.map +1 -0
  61. package/dist/types/elements/SwcAppEngine.d.ts +3 -5
  62. package/dist/types/elements/SwcAppEngine.d.ts.map +1 -1
  63. package/dist/types/elements/SwcAppMixin.d.ts +9 -0
  64. package/dist/types/elements/SwcAppMixin.d.ts.map +1 -1
  65. package/dist/types/elements/register.d.ts +1 -1
  66. package/dist/types/elements/register.d.ts.map +1 -1
  67. package/dist/types/utils/Utils.d.ts +3 -0
  68. package/dist/types/utils/Utils.d.ts.map +1 -1
  69. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +135 -2470
  70. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
  71. package/package.json +3 -3
  72. package/src/decorators/attribute.ts +62 -53
  73. package/src/decorators/elementDefine.ts +79 -30
  74. package/src/decorators/index.ts +1 -0
  75. package/src/decorators/lifecycles.ts +2 -2
  76. package/src/decorators/query.ts +5 -5
  77. package/src/decorators/queryAll.ts +8 -7
  78. package/src/decorators/subscribeSwcAppRouteChange.ts +71 -0
  79. package/src/elements/SwcAppEngine.ts +25 -81
  80. package/src/elements/SwcAppMixin.ts +143 -28
  81. package/src/elements/register.ts +0 -2
  82. package/src/utils/Utils.ts +33 -0
@@ -1,9 +1,16 @@
1
- import { SwcAppEngine, SwcAttributeConfigType } from './SwcAppEngine';
2
- import {SwcAppInterface} from "../types";
1
+ import { SwcAppEngine, SwcAttributeConfigType, SwcConfigType } from './SwcAppEngine';
2
+ import { SwcAppInterface } from '../types';
3
+ import { SwcUtils } from '../utils/Utils';
4
+ import { FunctionUtils, Subscription } from '@dooboostore/core';
5
+ import { RouterEventType } from '@dooboostore/core-web';
6
+ import { getSubscribeSwcAppRouteChangeMetadata } from '../decorators/subscribeSwcAppRouteChange';
3
7
 
4
8
  export function SwcAppMixin<T extends { new (...args: any[]): HTMLElement }>(Base: T) {
5
- return class extends Base implements SwcAppInterface{
9
+ return class extends Base implements SwcAppInterface {
6
10
  __swc_engine = new SwcAppEngine(this as any);
11
+ _swc_connected_instance = new Set<any>();
12
+ _routerSubscription?: Subscription;
13
+ _lastRouterEvent?: RouterEventType;
7
14
 
8
15
  get simpleApplication() {
9
16
  return this.__swc_engine.simpleApplication;
@@ -12,51 +19,159 @@ export function SwcAppMixin<T extends { new (...args: any[]): HTMLElement }>(Bas
12
19
  return this.__swc_engine.router;
13
20
  }
14
21
 
22
+ _invokeRouteChangeSubscribers(instance: any, re: RouterEventType) {
23
+ const routeChangeSubscribers = getSubscribeSwcAppRouteChangeMetadata(instance);
24
+ if (routeChangeSubscribers && Array.isArray(routeChangeSubscribers)) {
25
+ routeChangeSubscribers.forEach((metadata: any) => {
26
+ const methodName = metadata.propertyKey || metadata;
27
+ const pathPattern = metadata.pathPattern;
28
+ const filter = metadata.filter;
29
+
30
+ // Path pattern matching (support both string and array)
31
+ let pathMatched = false;
32
+ let pathData: any = null;
33
+
34
+ if (!pathPattern) {
35
+ // pathPattern이 없으면 모든 경로 매칭 (와일드카드)
36
+ pathMatched = true;
37
+ pathData = {};
38
+ } else if (Array.isArray(pathPattern)) {
39
+ // 배열: 하나라도 매칭되면 OK
40
+ for (const pattern of pathPattern) {
41
+ const data = SwcUtils.parsePathPattern(pattern, re.path || '/');
42
+ if (data !== null) {
43
+ pathMatched = true;
44
+ pathData = data;
45
+ break;
46
+ }
47
+ }
48
+ } else {
49
+ // 문자열
50
+ pathData = SwcUtils.parsePathPattern(pathPattern, re.path || '/');
51
+ pathMatched = pathData !== null;
52
+ }
53
+
54
+ // Filter validation
55
+ const filterPassed = !filter || filter(this.router!);
56
+
57
+ // Invoke method if conditions pass
58
+ if (pathMatched && filterPassed) {
59
+ instance[methodName]?.(re, pathData || {});
60
+ }
61
+ });
62
+ }
63
+ }
64
+
65
+ _connected(instance: any) {
66
+ // console.log('------------------>', instance);
67
+ if (instance) {
68
+ this._swc_connected_instance.add(instance);
69
+
70
+ // Notify current route subscribers immediately after connection
71
+ if (this.router && this._lastRouterEvent) {
72
+ this._invokeRouteChangeSubscribers(instance, this._lastRouterEvent);
73
+ }
74
+ }
75
+ }
76
+
77
+ _disconnected(instance: any) {
78
+ if (instance) {
79
+ this._swc_connected_instance.delete(instance);
80
+ }
81
+ }
82
+
83
+ _handleRouteChange(route: RouterEventType) {
84
+ if (route.triggerPoint === 'end') {
85
+ // Iterate through all connected component instances
86
+ this._swc_connected_instance.forEach((instance: any) => {
87
+ this._invokeRouteChangeSubscribers(instance, route);
88
+ });
89
+ }
90
+
91
+ // Save last router event
92
+ this._lastRouterEvent = route;
93
+ }
94
+
15
95
  async connect(config?: SwcAttributeConfigType) {
96
+ const swcConfig = {
97
+ routeType: 'element',
98
+ window: config.window,
99
+ ...config
100
+ } as SwcConfigType;
101
+
16
102
  const mode = config?.connectMode || 'direct';
17
103
 
18
- if (mode !== 'swap') {
19
- await this.__swc_engine.connect(config);
104
+ if (mode === 'direct') {
105
+ await this.__swc_engine.connect(swcConfig);
20
106
  this.setAttribute('swc-connect-mode', 'direct');
21
- return;
22
- }
23
-
24
- const parent = this.parentNode;
25
- if (!parent) {
26
- await this.__swc_engine.connect(config);
107
+ } else if (mode === 'swap' && !this.parentNode) {
108
+ await this.__swc_engine.connect(swcConfig);
27
109
  this.setAttribute('swc-connect-mode', 'direct');
28
- return;
29
- }
30
110
 
31
- const clonedApp = this.cloneNode(true) as any;
32
- clonedApp.style.display = 'none';
33
- parent.insertBefore(clonedApp, this.nextSibling);
111
+ const clonedApp = this.cloneNode(true) as any;
112
+ clonedApp.style.display = 'none';
113
+ this.parentNode.insertBefore(clonedApp, this.nextSibling);
34
114
 
35
- try {
36
- await clonedApp.connect({ ...(config || {}), connectMode: 'direct' });
37
- if (this.parentNode) {
38
- this.parentNode.removeChild(this);
39
- }
40
- clonedApp.setAttribute('swc-connect-mode', 'swap');
41
- clonedApp.style.display = '';
42
- } catch (e) {
43
- if (clonedApp.parentNode) {
44
- clonedApp.parentNode.removeChild(clonedApp);
115
+ try {
116
+ await clonedApp.connect({ ...(config || {}), connectMode: 'direct' });
117
+ if (this.parentNode) {
118
+ this.parentNode.removeChild(this);
119
+ }
120
+ clonedApp.setAttribute('swc-connect-mode', 'swap');
121
+ clonedApp.style.display = '';
122
+ } catch (e) {
123
+ if (clonedApp.parentNode) {
124
+ clonedApp.parentNode.removeChild(clonedApp);
125
+ }
126
+ throw e;
45
127
  }
46
- throw e;
128
+ }
129
+
130
+ // console.log('vvvvvvv222222', this.router);
131
+ // Subscribe to router changes after connect
132
+ if (!this._routerSubscription && this.router) {
133
+ this._routerSubscription = this.router.observable.subscribe((route: RouterEventType) => {
134
+ // console.log('Route changed:', route);
135
+ this._handleRouteChange(route);
136
+ });
137
+
138
+ // Navigate to initial path if specified
139
+ // const config = this.__swc_engine.config;
140
+ // if (config?.path) {
141
+ // this.router.go(config.path);
142
+ // }
47
143
  }
48
144
  }
49
145
 
50
146
  connectedCallback() {
51
147
  // @ts-ignore
52
148
  if (super.connectedCallback) super.connectedCallback();
53
- this.connect();
149
+
150
+ const configStr = this.getAttribute('swc-get-application-config');
151
+ const win = this.ownerDocument?.defaultView || window;
152
+ if (configStr && win) {
153
+ try {
154
+ // console.log('vvvvvvvvvvvvvvvv->>>>', SwcUtils.findNearestSwcHost(this.host), SwcUtils.getHostSet(this.host))
155
+ const userConfig = FunctionUtils.executeReturn({
156
+ script: configStr,
157
+ context: this,
158
+ args: SwcUtils.getHelperAndHostSet(win, SwcUtils.findNearestSwcHost(this))
159
+ });
160
+ this.connect(userConfig);
161
+ } catch (e) {
162
+ console.error('[SWC-APP-ENGINE] Script execution failed:', e);
163
+ }
164
+ }
165
+
54
166
  this.__swc_engine?.config?.onConnected?.(this);
55
167
  }
56
168
 
57
169
  disconnectedCallback() {
58
170
  // @ts-ignore
59
171
  if (super.disconnectedCallback) super.disconnectedCallback();
172
+ this._routerSubscription?.unsubscribe();
173
+ this._routerSubscription = undefined;
174
+ this._lastRouterEvent = undefined;
60
175
  this.__swc_engine.disconnect();
61
176
  this.__swc_engine?.config?.onDisconnected?.(this);
62
177
  }
@@ -732,6 +732,4 @@ export const registerAllElements = (w: any) => {
732
732
  @elementDefine('swc-app-body', { extends: 'body', window: w })
733
733
  class SwcAppBody extends SwcAppMixin(HTMLBodyElement) {}
734
734
 
735
-
736
- return []
737
735
  };
@@ -282,4 +282,37 @@ export namespace SwcUtils {
282
282
  ...loopContext
283
283
  } as any;
284
284
  };
285
+
286
+ export const parsePathPattern = (pattern: string | undefined, currentPath: string): { [key: string]: string } | null => {
287
+ // pattern이 null/undefined면 와일드카드 (모든 경로 매칭)
288
+ if (pattern === null || pattern === undefined) return {};
289
+
290
+ // 공백만 있는 패턴도 와일드카드
291
+ const trimmedPattern = pattern.trim();
292
+ if (trimmedPattern === '' && pattern !== '') return {}; // 공백 문자만 있는 경우
293
+
294
+ // 패턴을 정규식으로 변환
295
+ // 지원 형식:
296
+ // {id} → ([^/]+) 기본 (/ 제외한 모든 문자)
297
+ // {tail:.*} → (.*) 정규표현식 직접 지정
298
+ // {slug:[a-z0-9-]+} → ([a-z0-9-]+)
299
+ const paramNames: string[] = [];
300
+ const regexPattern = trimmedPattern.replace(/{(\w+)(?::(.+?))?}/g, (match, paramName, customRegex) => {
301
+ paramNames.push(paramName);
302
+ // customRegex가 있으면 사용, 없으면 기본값 ([^/]+)
303
+ return `(${customRegex || '[^/]+'})`;
304
+ });
305
+
306
+ const regex = new RegExp(`^${regexPattern}$`);
307
+ const match = currentPath.match(regex);
308
+
309
+ if (!match) return null;
310
+
311
+ const result: { [key: string]: string } = {};
312
+ paramNames.forEach((name, index) => {
313
+ result[name] = match[index + 1];
314
+ });
315
+
316
+ return result;
317
+ };
285
318
  }