@dooboostore/simple-web-component 1.0.43 → 1.0.45

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 (146) hide show
  1. package/README.md +312 -63
  2. package/dist/cjs/SwcAppEngine.js +3 -1
  3. package/dist/cjs/SwcAppEngine.js.map +2 -2
  4. package/dist/cjs/decorators/addEventListener.js.map +2 -2
  5. package/dist/cjs/decorators/applyAttribute.js +66 -43
  6. package/dist/cjs/decorators/applyAttribute.js.map +2 -2
  7. package/dist/cjs/decorators/applyClass.js +110 -43
  8. package/dist/cjs/decorators/applyClass.js.map +3 -3
  9. package/dist/cjs/decorators/applyNode.js +200 -112
  10. package/dist/cjs/decorators/applyNode.js.map +2 -2
  11. package/dist/cjs/decorators/applyProperty.js +49 -45
  12. package/dist/cjs/decorators/applyProperty.js.map +2 -2
  13. package/dist/cjs/decorators/applyStyle.js +92 -37
  14. package/dist/cjs/decorators/applyStyle.js.map +3 -3
  15. package/dist/cjs/decorators/{changedAttributeThis.js → changedAttribute.js} +6 -6
  16. package/dist/cjs/decorators/changedAttribute.js.map +7 -0
  17. package/dist/cjs/decorators/elementDefine.js +81 -31
  18. package/dist/cjs/decorators/elementDefine.js.map +3 -3
  19. package/dist/cjs/decorators/emitCustomEvent.js +80 -52
  20. package/dist/cjs/decorators/emitCustomEvent.js.map +2 -2
  21. package/dist/cjs/decorators/index.js +1 -1
  22. package/dist/cjs/decorators/index.js.map +2 -2
  23. package/dist/cjs/decorators/publishSwcAppMessage.js +5 -5
  24. package/dist/cjs/decorators/publishSwcAppMessage.js.map +3 -3
  25. package/dist/cjs/decorators/query.js +133 -147
  26. package/dist/cjs/decorators/query.js.map +3 -3
  27. package/dist/cjs/decorators/queryAll.js +143 -132
  28. package/dist/cjs/decorators/queryAll.js.map +3 -3
  29. package/dist/cjs/decorators/subscribeSwcAppMessageWhileConnected.js +2 -0
  30. package/dist/cjs/decorators/subscribeSwcAppMessageWhileConnected.js.map +2 -2
  31. package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js +2 -0
  32. package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +2 -2
  33. package/dist/cjs/elements/SwcAppMixin.js +17 -2
  34. package/dist/cjs/elements/SwcAppMixin.js.map +2 -2
  35. package/dist/cjs/examples/RxJSOperatorsExample.js +285 -0
  36. package/dist/cjs/examples/RxJSOperatorsExample.js.map +7 -0
  37. package/dist/cjs/index.js +1 -0
  38. package/dist/cjs/index.js.map +2 -2
  39. package/dist/cjs/router/ElementRouter.js +4 -0
  40. package/dist/cjs/router/ElementRouter.js.map +2 -2
  41. package/dist/cjs/types/window.d.js.map +1 -1
  42. package/dist/esm/SwcAppEngine.js +3 -1
  43. package/dist/esm/SwcAppEngine.js.map +2 -2
  44. package/dist/esm/decorators/addEventListener.js.map +2 -2
  45. package/dist/esm/decorators/applyAttribute.js +66 -43
  46. package/dist/esm/decorators/applyAttribute.js.map +2 -2
  47. package/dist/esm/decorators/applyClass.js +110 -43
  48. package/dist/esm/decorators/applyClass.js.map +3 -3
  49. package/dist/esm/decorators/applyNode.js +200 -112
  50. package/dist/esm/decorators/applyNode.js.map +2 -2
  51. package/dist/esm/decorators/applyProperty.js +49 -45
  52. package/dist/esm/decorators/applyProperty.js.map +2 -2
  53. package/dist/esm/decorators/applyStyle.js +92 -37
  54. package/dist/esm/decorators/applyStyle.js.map +3 -3
  55. package/dist/esm/decorators/{changedAttributeThis.js → changedAttribute.js} +3 -3
  56. package/dist/esm/decorators/changedAttribute.js.map +7 -0
  57. package/dist/esm/decorators/elementDefine.js +79 -29
  58. package/dist/esm/decorators/elementDefine.js.map +2 -2
  59. package/dist/esm/decorators/emitCustomEvent.js +80 -52
  60. package/dist/esm/decorators/emitCustomEvent.js.map +2 -2
  61. package/dist/esm/decorators/index.js +1 -1
  62. package/dist/esm/decorators/index.js.map +1 -1
  63. package/dist/esm/decorators/publishSwcAppMessage.js +5 -5
  64. package/dist/esm/decorators/publishSwcAppMessage.js.map +3 -3
  65. package/dist/esm/decorators/query.js +133 -147
  66. package/dist/esm/decorators/query.js.map +3 -3
  67. package/dist/esm/decorators/queryAll.js +143 -132
  68. package/dist/esm/decorators/queryAll.js.map +3 -3
  69. package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js +2 -0
  70. package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js.map +2 -2
  71. package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js +2 -0
  72. package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +2 -2
  73. package/dist/esm/elements/SwcAppMixin.js +18 -3
  74. package/dist/esm/elements/SwcAppMixin.js.map +2 -2
  75. package/dist/esm/examples/RxJSOperatorsExample.js +266 -0
  76. package/dist/esm/examples/RxJSOperatorsExample.js.map +7 -0
  77. package/dist/esm/index.js +1 -0
  78. package/dist/esm/index.js.map +2 -2
  79. package/dist/esm/router/ElementRouter.js +4 -0
  80. package/dist/esm/router/ElementRouter.js.map +2 -2
  81. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +1118 -633
  82. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
  83. package/dist/types/SwcAppEngine.d.ts.map +1 -1
  84. package/dist/types/decorators/addEventListener.d.ts +19 -15
  85. package/dist/types/decorators/addEventListener.d.ts.map +1 -1
  86. package/dist/types/decorators/applyAttribute.d.ts +45 -26
  87. package/dist/types/decorators/applyAttribute.d.ts.map +1 -1
  88. package/dist/types/decorators/applyClass.d.ts +19 -38
  89. package/dist/types/decorators/applyClass.d.ts.map +1 -1
  90. package/dist/types/decorators/applyNode.d.ts +175 -32
  91. package/dist/types/decorators/applyNode.d.ts.map +1 -1
  92. package/dist/types/decorators/applyProperty.d.ts +38 -25
  93. package/dist/types/decorators/applyProperty.d.ts.map +1 -1
  94. package/dist/types/decorators/applyStyle.d.ts +10 -9
  95. package/dist/types/decorators/applyStyle.d.ts.map +1 -1
  96. package/dist/types/decorators/{changedAttributeThis.d.ts → changedAttribute.d.ts} +2 -2
  97. package/dist/types/decorators/changedAttribute.d.ts.map +1 -0
  98. package/dist/types/decorators/elementDefine.d.ts.map +1 -1
  99. package/dist/types/decorators/emitCustomEvent.d.ts +6 -12
  100. package/dist/types/decorators/emitCustomEvent.d.ts.map +1 -1
  101. package/dist/types/decorators/index.d.ts +1 -1
  102. package/dist/types/decorators/index.d.ts.map +1 -1
  103. package/dist/types/decorators/publishSwcAppMessage.d.ts +1 -1
  104. package/dist/types/decorators/publishSwcAppMessage.d.ts.map +1 -1
  105. package/dist/types/decorators/query.d.ts +16 -29
  106. package/dist/types/decorators/query.d.ts.map +1 -1
  107. package/dist/types/decorators/queryAll.d.ts +16 -23
  108. package/dist/types/decorators/queryAll.d.ts.map +1 -1
  109. package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts +1 -0
  110. package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts.map +1 -1
  111. package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts +2 -0
  112. package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts.map +1 -1
  113. package/dist/types/elements/SwcAppMixin.d.ts +4 -4
  114. package/dist/types/elements/SwcAppMixin.d.ts.map +1 -1
  115. package/dist/types/examples/RxJSOperatorsExample.d.ts +94 -0
  116. package/dist/types/examples/RxJSOperatorsExample.d.ts.map +1 -0
  117. package/dist/types/index.d.ts +1 -0
  118. package/dist/types/index.d.ts.map +1 -1
  119. package/dist/types/router/ElementRouter.d.ts.map +1 -1
  120. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +1118 -633
  121. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
  122. package/package.json +1 -1
  123. package/src/SwcAppEngine.ts +3 -1
  124. package/src/decorators/addEventListener.ts +31 -25
  125. package/src/decorators/applyAttribute.ts +164 -86
  126. package/src/decorators/applyClass.ts +161 -41
  127. package/src/decorators/applyNode.ts +408 -108
  128. package/src/decorators/applyProperty.ts +100 -89
  129. package/src/decorators/applyStyle.ts +131 -37
  130. package/src/decorators/{changedAttributeThis.ts → changedAttribute.ts} +1 -1
  131. package/src/decorators/elementDefine.ts +96 -30
  132. package/src/decorators/emitCustomEvent.ts +92 -60
  133. package/src/decorators/index.ts +1 -1
  134. package/src/decorators/publishSwcAppMessage.ts +1 -1
  135. package/src/decorators/query.ts +155 -162
  136. package/src/decorators/queryAll.ts +157 -139
  137. package/src/decorators/subscribeSwcAppMessageWhileConnected.ts +1 -0
  138. package/src/decorators/subscribeSwcAppRouteChangeWhileConnected.ts +3 -1
  139. package/src/elements/SwcAppMixin.ts +43 -24
  140. package/src/examples/RxJSOperatorsExample.ts +279 -0
  141. package/src/index.ts +2 -0
  142. package/src/router/ElementRouter.ts +4 -0
  143. package/src/types/window.d.ts +3 -0
  144. package/dist/cjs/decorators/changedAttributeThis.js.map +0 -7
  145. package/dist/esm/decorators/changedAttributeThis.js.map +0 -7
  146. package/dist/types/decorators/changedAttributeThis.d.ts.map +0 -1
@@ -1,165 +1,183 @@
1
1
  import { ReflectUtils } from '@dooboostore/core';
2
2
  import { getElementConfig, ensureInit } from './elementDefine';
3
3
  import { SwcUtils } from '../utils/Utils';
4
- import { SpecialSelector, SwcQueryOptions, HelperHostSet } from '../types';
4
+ import { SwcQueryOptions, HelperHostSet } from '../types';
5
+
6
+ export interface QueryAllOptions extends SwcQueryOptions {
7
+ /**
8
+ * Filter function to determine whether to include the element.
9
+ * If it returns false, the element is skipped.
10
+ */
11
+ filter?: (target: HTMLElement, meta: { currentThis: any, helper: HelperHostSet }) => boolean;
12
+ }
5
13
 
6
14
  export interface QueryAllMetadata {
7
15
  propertyKey: string | symbol;
8
- selector: string;
9
- options: SwcQueryOptions;
16
+ selector: string | ((currentThis: any, helper: HelperHostSet) => NodeList | Element | Element[] | null);
17
+ options: QueryAllOptions;
10
18
  }
11
19
 
12
20
  export const QUERY_ALL_METADATA_KEY = Symbol.for('simple-web-component:query-all');
13
21
 
14
- export function queryAll(target: SpecialSelector): PropertyDecorator;
15
- export function queryAll(selector: string, options?: SwcQueryOptions): PropertyDecorator;
22
+ export function queryAll(target: Object, propertyKey: string | symbol, descriptor?: PropertyDescriptor): PropertyDescriptor | void;
23
+ export function queryAll(selector: string | ((currentThis: any, helper: HelperHostSet) => NodeList | Element | Element[] | null), options?: QueryAllOptions): PropertyDecorator;
24
+ export function queryAll(options?: QueryAllOptions): PropertyDecorator;
16
25
  /**
17
26
  * @queryAll decorator to inject a list of elements into a class property.
27
+ *
28
+ * Supports both string selectors and function-based selectors:
29
+ * - String selector: @queryAll('.item')
30
+ * - Function selector: @queryAll((currentThis, helper) => currentThis.shadowRoot?.querySelectorAll('.item'))
31
+ *
32
+ * Supports filtering:
33
+ * - @queryAll('.item', { filter: (target, meta) => target.hasAttribute('active') })
18
34
  */
19
- export function queryAll(selectorOrTarget: string, options: any = {}): PropertyDecorator {
20
- return (targetObj: Object, propertyKey: string | symbol, descriptor?: never): void => {
21
- if (descriptor !== undefined) {
22
- throw new Error(`@queryAll decorator cannot be used on methods. (Method: ${String(propertyKey)})`);
23
- }
24
-
25
- const constructor = targetObj.constructor;
26
- let queries = ReflectUtils.getMetadata<QueryAllMetadata[]>(QUERY_ALL_METADATA_KEY, constructor);
27
- if (!queries) {
28
- queries = [];
29
- ReflectUtils.defineMetadata(QUERY_ALL_METADATA_KEY, queries, constructor);
30
- }
31
- queries.push({ propertyKey, selector: selectorOrTarget, options });
35
+ export function queryAll(selectorOrTarget?: string | ((currentThis: any, helper: HelperHostSet) => NodeList | Element | Element[] | null) | Object, optionsOrPropertyKey?: QueryAllOptions | string | symbol, descriptor?: PropertyDescriptor): any {
36
+ // Bare decorator: @queryAll
37
+ if (descriptor !== undefined && (typeof optionsOrPropertyKey === 'string' || typeof optionsOrPropertyKey === 'symbol')) {
38
+ throw new Error(`@queryAll decorator cannot be used on methods. (Method: ${String(optionsOrPropertyKey)})`);
39
+ }
40
+ // With selector
41
+ if (typeof selectorOrTarget === 'string' || typeof selectorOrTarget === 'function') {
42
+ return (targetObj: Object, propertyKey: string | symbol, descriptor?: never): void => {
43
+ if (descriptor !== undefined) {
44
+ throw new Error(`@queryAll decorator cannot be used on methods. (Method: ${String(propertyKey)})`);
45
+ }
32
46
 
33
- Object.defineProperty(targetObj, propertyKey, {
34
- get(this: HTMLElement) {
35
- ensureInit(this);
36
- const selector = selectorOrTarget;
47
+ const constructor = targetObj.constructor;
48
+ let queries = ReflectUtils.getMetadata<QueryAllMetadata[]>(QUERY_ALL_METADATA_KEY, constructor);
49
+ if (!queries) {
50
+ queries = [];
51
+ ReflectUtils.defineMetadata(QUERY_ALL_METADATA_KEY, queries, constructor);
52
+ }
53
+ queries.push({ propertyKey, selector: selectorOrTarget as any, options: optionsOrPropertyKey as QueryAllOptions || {} });
37
54
 
38
- const r = options.root || 'auto';
39
- const applyRoot = (t: any): any[] => {
40
- if (!t) return [];
41
- const items = Array.isArray(t) ? t : [t];
42
- const results: any[] = [];
43
- items.forEach(it => {
44
- if (!(it instanceof HTMLElement)) {
45
- results.push(it);
46
- return;
55
+ Object.defineProperty(targetObj, propertyKey, {
56
+ get(this: HTMLElement) {
57
+ ensureInit(this);
58
+ const config = getElementConfig(this);
59
+ const win = config?.window || window;
60
+ const hostSet = SwcUtils.getHelperAndHostSet(win, this);
61
+
62
+ // Resolve selector - can be string or function
63
+ let resolvedSelector: string;
64
+ let resolvedElements: HTMLElement[] = [];
65
+
66
+ if (typeof selectorOrTarget === 'function') {
67
+ const result = (selectorOrTarget as any)(this, hostSet);
68
+ // If function returns NodeList or Element[], convert to array
69
+ if (result instanceof win.NodeList) {
70
+ resolvedElements = Array.from(result).filter(el => el instanceof win.HTMLElement) as HTMLElement[];
71
+ } else if (Array.isArray(result)) {
72
+ resolvedElements = result.filter(el => el instanceof win.HTMLElement) as HTMLElement[];
47
73
  }
48
- if (r === 'auto') results.push(it.shadowRoot || it);
49
- else {
50
- if (r === 'light' || r === 'all') results.push(it);
51
- if ((r === 'shadow' || r === 'all') && it.shadowRoot) results.push(it.shadowRoot);
52
- }
53
- });
54
- return results;
55
- };
56
-
57
- // --- Special Selectors: HostSet ---
58
- const hostSet = SwcUtils.getHostSet(this);
59
- if (selector === '$hosts') return applyRoot(hostSet.$hosts);
60
- if (selector === '$appHosts') return applyRoot(hostSet.$appHosts);
61
- if (selector === '$host') return applyRoot(hostSet.$host);
62
- if (selector === '$parentHost') return applyRoot(hostSet.$parentHost);
63
- if (selector === '$appHost') return applyRoot(hostSet.$appHost);
64
- if (selector === '$firstHost') return applyRoot(hostSet.$firstHost);
65
- if (selector === '$lastHost') return applyRoot(hostSet.$lastHost);
66
- if (selector === '$firstAppHost') return applyRoot(hostSet.$firstAppHost);
67
- if (selector === '$lastAppHost') return applyRoot(hostSet.$lastAppHost);
68
-
69
- // --- Special Selectors: Env ---
70
- const config = getElementConfig(this);
71
- const win = config?.window || window;
72
- if (selector === '$window') return [win];
73
- if (selector === '$document') return [win.document];
74
- if (selector === '$this') return applyRoot(this);
74
+ } else {
75
+ resolvedSelector = selectorOrTarget;
75
76
 
76
- // --- Standard Selectors ---
77
- if (r === 'shadow') return this.shadowRoot ? Array.from(this.shadowRoot.querySelectorAll(selector)) : [];
78
- if (r === 'light') return Array.from(this.querySelectorAll(selector));
79
- if (r === 'all') {
80
- const sNodes = this.shadowRoot ? Array.from(this.shadowRoot.querySelectorAll(selector)) : [];
81
- const lNodes = Array.from(this.querySelectorAll(selector));
82
- return [...sNodes, ...lNodes];
83
- }
84
- const root = this.shadowRoot || this;
85
- return Array.from(root.querySelectorAll(selector));
86
- },
87
- set(this: HTMLElement, nv: any) {
88
- ensureInit(this);
89
- if (nv === null || nv === undefined || (Array.isArray(nv) && nv.length === 0)) {
90
- const selector = selectorOrTarget;
91
- if (selector.startsWith('$') && selector !== '$this') return;
77
+ const r = (optionsOrPropertyKey as QueryAllOptions)?.root || 'auto';
78
+ const applyRoot = (t: any): any[] => {
79
+ if (!t) return [];
80
+ const items = Array.isArray(t) ? t : [t];
81
+ const results: any[] = [];
82
+ items.forEach(it => {
83
+ if (!(it instanceof HTMLElement)) {
84
+ results.push(it);
85
+ return;
86
+ }
87
+ if (r === 'auto') results.push(it.shadowRoot || it);
88
+ else {
89
+ if (r === 'light' || r === 'all') results.push(it);
90
+ if ((r === 'shadow' || r === 'all') && it.shadowRoot) results.push(it.shadowRoot);
91
+ }
92
+ });
93
+ return results;
94
+ };
92
95
 
93
- const r = options.root || 'auto';
94
- let targets: (Element | Node)[] = [];
95
- if (r === 'shadow') targets = this.shadowRoot ? Array.from(this.shadowRoot.querySelectorAll(selector)) : [];
96
- else if (r === 'light') targets = Array.from(this.querySelectorAll(selector));
97
- else if (r === 'all') {
98
- const sNodes = this.shadowRoot ? Array.from(this.shadowRoot.querySelectorAll(selector)) : [];
99
- const lNodes = Array.from(this.querySelectorAll(selector));
100
- targets = [...sNodes, ...lNodes];
101
- } else {
102
- targets = Array.from((this.shadowRoot || this).querySelectorAll(selector));
96
+ // --- Special Selectors: HostSet ---
97
+ if (resolvedSelector === '$hosts') resolvedElements = applyRoot(hostSet.$hosts).filter(el => el instanceof HTMLElement);
98
+ else if (resolvedSelector === '$appHosts') resolvedElements = applyRoot(hostSet.$appHosts).filter(el => el instanceof HTMLElement);
99
+ else if (resolvedSelector === '$host') resolvedElements = applyRoot(hostSet.$host).filter(el => el instanceof HTMLElement);
100
+ else if (resolvedSelector === '$parentHost') resolvedElements = applyRoot(hostSet.$parentHost).filter(el => el instanceof HTMLElement);
101
+ else if (resolvedSelector === '$appHost') resolvedElements = applyRoot(hostSet.$appHost).filter(el => el instanceof HTMLElement);
102
+ else if (resolvedSelector === '$firstHost') resolvedElements = applyRoot(hostSet.$firstHost).filter(el => el instanceof HTMLElement);
103
+ else if (resolvedSelector === '$lastHost') resolvedElements = applyRoot(hostSet.$lastHost).filter(el => el instanceof HTMLElement);
104
+ else if (resolvedSelector === '$firstAppHost') resolvedElements = applyRoot(hostSet.$firstAppHost).filter(el => el instanceof HTMLElement);
105
+ else if (resolvedSelector === '$lastAppHost') resolvedElements = applyRoot(hostSet.$lastAppHost).filter(el => el instanceof HTMLElement);
106
+ // --- Special Selectors: Env ---
107
+ else if (resolvedSelector === '$window') return [win];
108
+ else if (resolvedSelector === '$document') return [win.document];
109
+ else if (resolvedSelector === '$this') resolvedElements = applyRoot(this).filter(el => el instanceof HTMLElement);
110
+ // --- Standard Selectors ---
111
+ else {
112
+ if (r === 'shadow') resolvedElements = this.shadowRoot ? (Array.from(this.shadowRoot.querySelectorAll(resolvedSelector)) as HTMLElement[]) : [];
113
+ else if (r === 'light') resolvedElements = Array.from(this.querySelectorAll(resolvedSelector)) as HTMLElement[];
114
+ else if (r === 'all') {
115
+ const sNodes = this.shadowRoot ? (Array.from(this.shadowRoot.querySelectorAll(resolvedSelector)) as HTMLElement[]) : [];
116
+ const lNodes = Array.from(this.querySelectorAll(resolvedSelector)) as HTMLElement[];
117
+ resolvedElements = [...sNodes, ...lNodes];
118
+ }
119
+ else resolvedElements = (Array.from((this.shadowRoot || this).querySelectorAll(resolvedSelector)) as HTMLElement[]);
120
+ }
103
121
  }
104
- targets.forEach(t => (t as Element).remove());
105
- }
106
- },
107
- enumerable: true,
108
- configurable: true
109
- });
110
- };
111
- }
112
122
 
113
- /**
114
- * @queryAllThis decorator - simplified version of @queryAll for $this selector
115
- */
116
- export function queryAllThis(target: Object, propertyKey: string | symbol): void;
117
- export function queryAllThis(): PropertyDecorator;
118
- export function queryAllThis(options: SwcQueryOptions): PropertyDecorator;
119
- export function queryAllThis(targetOrOptions?: any, propertyKey?: string | symbol): any {
120
- if (propertyKey !== undefined && (typeof propertyKey === 'string' || typeof propertyKey === 'symbol')) {
121
- return queryAll('$this', {})(targetOrOptions, propertyKey);
122
- }
123
-
124
- if (typeof targetOrOptions === 'object' && targetOrOptions !== null) {
125
- return queryAll('$this', targetOrOptions as SwcQueryOptions);
126
- } else {
127
- return queryAll('$this', {});
128
- }
129
- }
123
+ // Apply filter if provided
124
+ if ((optionsOrPropertyKey as QueryAllOptions)?.filter) {
125
+ resolvedElements = resolvedElements.filter(el => {
126
+ if (!(el instanceof win.HTMLElement)) return true;
127
+ return (optionsOrPropertyKey as QueryAllOptions).filter!(el, { currentThis: this, helper: hostSet });
128
+ });
129
+ }
130
130
 
131
- /**
132
- * @allParentHost - Query all parent SWC components
133
- */
134
- export function allParentHost(target: Object, propertyKey: string | symbol): void;
135
- export function allParentHost(): PropertyDecorator;
136
- export function allParentHost(options: SwcQueryOptions): PropertyDecorator;
137
- export function allParentHost(targetOrOptions?: any, propertyKey?: string | symbol): any {
138
- if (propertyKey !== undefined && (typeof propertyKey === 'string' || typeof propertyKey === 'symbol')) {
139
- return queryAll('$host', {})(targetOrOptions, propertyKey);
140
- }
141
- if (typeof targetOrOptions === 'object' && targetOrOptions !== null) {
142
- return queryAll('$host', targetOrOptions as SwcQueryOptions);
143
- } else {
144
- return queryAll('$host', {});
145
- }
146
- }
131
+ return resolvedElements;
132
+ },
133
+ set(this: HTMLElement, nv: any) {
134
+ ensureInit(this);
135
+ if (nv === null || nv === undefined || (Array.isArray(nv) && nv.length === 0)) {
136
+ const config = getElementConfig(this);
137
+ const win = config?.window || window;
138
+ const hostSet = SwcUtils.getHelperAndHostSet(win, this);
139
+
140
+ // Resolve selector - can be string or function
141
+ if (typeof selectorOrTarget === 'function') {
142
+ // Get elements from function and remove them
143
+ const result = (selectorOrTarget as any)(this, hostSet);
144
+ if (result instanceof win.NodeList) {
145
+ Array.from(result).forEach(el => {
146
+ if (el instanceof win.Element) (el as Element).remove();
147
+ });
148
+ } else if (Array.isArray(result)) {
149
+ result.forEach(el => {
150
+ if (el instanceof win.Element) (el as Element).remove();
151
+ });
152
+ }
153
+ return;
154
+ }
155
+
156
+ const resolvedSelector = selectorOrTarget;
157
+
158
+ if (resolvedSelector.startsWith('$') && resolvedSelector !== '$this') return;
147
159
 
148
- /**
149
- * @allAppHost - Query all $appHost (All <swc-app> instances)
150
- */
151
- export function allAppHost(target: Object, propertyKey: string | symbol): void;
152
- export function allAppHost(): PropertyDecorator;
153
- export function allAppHost(options: SwcQueryOptions): PropertyDecorator;
154
- export function allAppHost(targetOrOptions?: any, propertyKey?: string | symbol): any {
155
- if (propertyKey !== undefined && (typeof propertyKey === 'string' || typeof propertyKey === 'symbol')) {
156
- return queryAll('$appHost', {})(targetOrOptions, propertyKey);
157
- }
158
- if (typeof targetOrOptions === 'object' && targetOrOptions !== null) {
159
- return queryAll('$appHost', targetOrOptions as SwcQueryOptions);
160
- } else {
161
- return queryAll('$appHost', {});
160
+ const r = (optionsOrPropertyKey as SwcQueryOptions)?.root || 'auto';
161
+ let targets: (Element | Node)[] = [];
162
+ if (r === 'shadow') targets = this.shadowRoot ? Array.from(this.shadowRoot.querySelectorAll(resolvedSelector)) : [];
163
+ else if (r === 'light') targets = Array.from(this.querySelectorAll(resolvedSelector));
164
+ else if (r === 'all') {
165
+ const sNodes = this.shadowRoot ? Array.from(this.shadowRoot.querySelectorAll(resolvedSelector)) : [];
166
+ const lNodes = Array.from(this.querySelectorAll(resolvedSelector));
167
+ targets = [...sNodes, ...lNodes];
168
+ } else {
169
+ targets = Array.from((this.shadowRoot || this).querySelectorAll(resolvedSelector));
170
+ }
171
+ targets.forEach(t => (t as Element).remove());
172
+ }
173
+ },
174
+ enumerable: true,
175
+ configurable: true
176
+ });
177
+ };
162
178
  }
179
+ // Without selector (defaults to $this)
180
+ return queryAll('$this', selectorOrTarget as SwcQueryOptions);
163
181
  }
164
182
 
165
183
  export const getQueryAllMetadata = (target: any): QueryAllMetadata[] | undefined => {
@@ -66,6 +66,7 @@ export function subscribeSwcAppMessageWhileConnected(targetOrMessageTypeOrOption
66
66
  return createSubscribeSwcAppMessageWhileConnected(options, messageType);
67
67
  }
68
68
 
69
+ export const receiveMessage = subscribeSwcAppMessageWhileConnected;
69
70
  // Helper function to retrieve message subscribers metadata
70
71
  export const getSubscribeSwcAppMessageWhileConnectedMetadata = (target: any): SwcAppMessageSubscriberMetadata[] | undefined => {
71
72
  const constructor = target instanceof Function ? target : target.constructor;
@@ -13,8 +13,9 @@ export interface SwcAppRouteChangeSubscriberMetadata {
13
13
 
14
14
  export interface SwcAppRouteChangeOptions {
15
15
  path?: RoutePathType;
16
- filter?: (router: Router, meta: {currentThis: any, helper: HelperHostSet}) => boolean;
16
+ filter?: (router: Router, meta: { currentThis: any; helper: HelperHostSet }) => boolean;
17
17
  order?: number;
18
+ valueKey?: symbol | string;
18
19
  }
19
20
 
20
21
  function createSubscribeSwcAppRouteChangeWhileConnected(options?: SwcAppRouteChangeOptions): MethodDecorator {
@@ -74,6 +75,7 @@ export function subscribeSwcAppRouteChangeWhileConnected(targetOrOptions?: any,
74
75
 
75
76
  return createSubscribeSwcAppRouteChangeWhileConnected(options);
76
77
  }
78
+ export const changedRoute = subscribeSwcAppRouteChangeWhileConnected;
77
79
 
78
80
  // Helper function to retrieve route change subscribers metadata
79
81
  export const getSubscribeSwcAppRouteChangeWhileConnectedMetadata = (target: any): SwcAppRouteChangeSubscriberMetadata[] => {
@@ -1,30 +1,30 @@
1
- import {SwcAppInterface, SwcAppMessage} from "../types";
2
- import {findAllLifecycleMetadata, getSubscribeSwcAppMessageWhileConnectedMetadata, getSubscribeSwcAppRouteChangeWhileConnectedMetadata, ON_CONNECTED_SWC_APP_METADATA_KEY} from "../decorators";
3
- import {SwcAppEngine, SwcAttributeConfigType, SwcConfigType} from "../SwcAppEngine";
4
- import {debounceTimeIntervalLock, FunctionUtils, Subscription} from "@dooboostore/core";
5
- import {RouterEventType} from "@dooboostore/core-web";
6
- import {SwcUtils} from "../utils/Utils";
1
+ import { SwcAppInterface, SwcAppMessage } from '../types';
2
+ import { APPLY_NODE_METADATA_KEY, findAllLifecycleMetadata, getSubscribeSwcAppMessageWhileConnectedMetadata, getSubscribeSwcAppRouteChangeWhileConnectedMetadata, ON_CONNECTED_SWC_APP_METADATA_KEY, SUBSCRIBE_SWC_APP_ROUTE_CHANGE_WHILE_CONNECTED_METADATA_KEY } from '../decorators';
3
+ import { SwcAppEngine, SwcAttributeConfigType, SwcConfigType } from '../SwcAppEngine';
4
+ import { debounceTimeIntervalLock, FunctionUtils, Subscription } from '@dooboostore/core';
5
+ import { RouterEventType } from '@dooboostore/core-web';
6
+ import { SwcUtils } from '../utils/Utils';
7
7
 
8
8
  export const isSSR = (i: HTMLElement) => {
9
9
  return i.hasAttribute('swc-use-ssr');
10
- }
10
+ };
11
11
  export const setSSRAttribute = (i: HTMLElement) => {
12
12
  i.setAttribute('swc-use-ssr', (i as any)._swcId ?? '');
13
- }
13
+ };
14
14
  export const removeSSRAttribute = (i: HTMLElement) => {
15
15
  i.removeAttribute('swc-use-ssr');
16
- }
16
+ };
17
17
 
18
18
  /**
19
19
  * SwcAppMixin: SwcApp 기능을 모든 HTMLElement에 추가할 수 있는 Mixin
20
- *
20
+ *
21
21
  * 사용 예:
22
22
  * @elementDefine('custom-app', { window: w })
23
23
  * class CustomApp extends SwcAppMixin(w.HTMLElement) implements SwcAppInterface {
24
24
  * // 추가 기능 구현
25
25
  * }
26
26
  */
27
- export function SwcAppMixin<T extends { new(...args: any[]): HTMLElement }>(Base: T) {
27
+ export function SwcAppMixin<T extends { new (...args: any[]): HTMLElement }>(Base: T) {
28
28
  return class SwcAppMixinClass extends Base implements SwcAppInterface {
29
29
  __swc_engine = new SwcAppEngine(this as any);
30
30
  _swc_connected_instance = new Set<any>();
@@ -45,7 +45,7 @@ export function SwcAppMixin<T extends { new(...args: any[]): HTMLElement }>(Base
45
45
 
46
46
  constructor(...args: any[]) {
47
47
  super(...args);
48
- console.log('[SWC-APP-MIXIN] constructor')
48
+ console.log('[SWC-APP-MIXIN] constructor');
49
49
  }
50
50
 
51
51
  get simpleApplication() {
@@ -68,12 +68,12 @@ export function SwcAppMixin<T extends { new(...args: any[]): HTMLElement }>(Base
68
68
  if (this._childrenRouteChangedInterval) {
69
69
  this.config.window.clearInterval(this._childrenRouteChangedInterval);
70
70
  }
71
- const intervalConfig = {setInterval: this.config.window.setInterval.bind(this.config.window), clearInterval: this.config.window.clearInterval.bind(this.config.window)};
71
+ const intervalConfig = { setInterval: this.config.window.setInterval.bind(this.config.window), clearInterval: this.config.window.clearInterval.bind(this.config.window) };
72
72
  this._childrenRouteChangedInterval = debounceTimeIntervalLock(
73
73
  () => this._routeChangeInvocations === 0,
74
74
  () => {
75
75
  this._childrenRouteChangedInterval = null;
76
- this.config.onChildrenRouteChanged?.(re, this)
76
+ this.config.onChildrenRouteChanged?.(re, this);
77
77
  },
78
78
  this.config?.childrenConnectedDoneCheckIntervalTime ?? 30,
79
79
  intervalConfig
@@ -81,15 +81,23 @@ export function SwcAppMixin<T extends { new(...args: any[]): HTMLElement }>(Base
81
81
 
82
82
  try {
83
83
  const routeChangeSubscribers = getSubscribeSwcAppRouteChangeWhileConnectedMetadata(instance);
84
+
84
85
  if (routeChangeSubscribers.length > 0) {
85
- console.log('[SWC-MIXIN] Route change subscribers found')
86
-
86
+ console.log('[SWC-MIXIN] Route change subscribers found');
87
+
87
88
  // Subscribers are already sorted by order from getSubscribeSwcAppRouteChangeWhileConnectedMetadata
88
89
  // Execute subscribers in order, stop if one returns a value
89
90
  for (const metadata of routeChangeSubscribers) {
90
91
  const methodName = metadata.propertyKey;
91
92
  let pathPattern = metadata.options?.path as any;
92
93
  const filter = metadata.options?.filter;
94
+ const extractValue = (v: any) => {
95
+ const keyToUse = metadata.options?.valueKey ?? SUBSCRIBE_SWC_APP_ROUTE_CHANGE_WHILE_CONNECTED_METADATA_KEY;
96
+ if (v && typeof v === 'object' && keyToUse in v) {
97
+ return v[keyToUse];
98
+ }
99
+ return v;
100
+ };
93
101
 
94
102
  if (typeof pathPattern === 'function') {
95
103
  pathPattern = (pathPattern as Function)(instance);
@@ -116,10 +124,11 @@ export function SwcAppMixin<T extends { new(...args: any[]): HTMLElement }>(Base
116
124
  }
117
125
 
118
126
  const hostSet = SwcUtils.getHelperAndHostSet(this.config.window, this);
119
- const filterPassed = !filter || filter(this.router!, {helper:hostSet, currentThis:instance});
127
+ const filterPassed = !filter || filter(this.router!, { helper: hostSet, currentThis: instance });
120
128
 
121
129
  if (pathMatched && filterPassed && instance[methodName]) {
122
- const result = await instance[methodName]({...re, pathData: pathData});
130
+ const result = extractValue(await instance[methodName]({ ...re, pathData: pathData }));
131
+ // if (typeof result === 'object'
123
132
  // If handler returns a value, stop propagation to next handlers
124
133
  if (result !== undefined && result !== null) {
125
134
  break;
@@ -158,12 +167,12 @@ export function SwcAppMixin<T extends { new(...args: any[]): HTMLElement }>(Base
158
167
  if (this._childrenConnectedDoneInterval) {
159
168
  this.config.window.clearInterval(this._childrenConnectedDoneInterval);
160
169
  }
161
- const intervalConfig = {setInterval: this.config.window.setInterval.bind(this.config.window), clearInterval: this.config.window.clearInterval.bind(this.config.window)};
170
+ const intervalConfig = { setInterval: this.config.window.setInterval.bind(this.config.window), clearInterval: this.config.window.clearInterval.bind(this.config.window) };
162
171
  this._childrenConnectedDoneInterval = debounceTimeIntervalLock(
163
172
  () => this._connectedInvocations === 0,
164
173
  () => {
165
174
  this._childrenConnectedDoneInterval = null;
166
- this.config.onChildrenConnectedDone?.(this)
175
+ this.config.onChildrenConnectedDone?.(this);
167
176
  },
168
177
  this.config?.childrenConnectedDoneCheckIntervalTime ?? 30,
169
178
  intervalConfig
@@ -213,7 +222,7 @@ export function SwcAppMixin<T extends { new(...args: any[]): HTMLElement }>(Base
213
222
  }
214
223
 
215
224
  async connect(config?: SwcAttributeConfigType) {
216
- console.log('[SWC-MIXIN] connect')
225
+ console.log('[SWC-MIXIN] connect');
217
226
  const swcConfig = {
218
227
  routeType: 'element',
219
228
  window: config?.window,
@@ -224,7 +233,7 @@ export function SwcAppMixin<T extends { new(...args: any[]): HTMLElement }>(Base
224
233
 
225
234
  // Safari is 속성 처리
226
235
  this._connected_safari_and_standby.forEach((instance: any) => {
227
- this._connected(instance, {noIncrements: true});
236
+ this._connected(instance, { noIncrements: true });
228
237
  });
229
238
 
230
239
  // 라우터 변경 구독
@@ -258,7 +267,17 @@ export function SwcAppMixin<T extends { new(...args: any[]): HTMLElement }>(Base
258
267
  context: this,
259
268
  args: SwcUtils.getHelperAndHostSet(win, this)
260
269
  });
261
- this.connect(userConfig);
270
+ if (userConfig instanceof Promise) {
271
+ userConfig
272
+ .then(resolvedConfig => {
273
+ this.connect(resolvedConfig);
274
+ })
275
+ .catch(e => {
276
+ console.error('[SWC-MIXIN] Script execution failed:', e);
277
+ });
278
+ } else {
279
+ this.connect(userConfig);
280
+ }
262
281
  } catch (e) {
263
282
  console.error('[SWC-MIXIN] Script execution failed:', e);
264
283
  }
@@ -273,7 +292,7 @@ export function SwcAppMixin<T extends { new(...args: any[]): HTMLElement }>(Base
273
292
  // 부모 클래스의 disconnectedCallback 호출
274
293
  // @ts-ignore
275
294
  super.disconnectedCallback?.();
276
-
295
+
277
296
  this._routerSubscription?.unsubscribe();
278
297
  this._routerSubscription = undefined;
279
298
  this._lastRouterEvent = undefined;