@dooboostore/simple-web-component 1.0.44 → 1.0.46

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 (95) hide show
  1. package/README.md +25 -25
  2. package/dist/cjs/decorators/addEventListener.js.map +2 -2
  3. package/dist/cjs/decorators/applyAttribute.js +36 -15
  4. package/dist/cjs/decorators/applyAttribute.js.map +2 -2
  5. package/dist/cjs/decorators/applyClass.js +53 -22
  6. package/dist/cjs/decorators/applyClass.js.map +2 -2
  7. package/dist/cjs/decorators/applyNode.js +54 -24
  8. package/dist/cjs/decorators/applyNode.js.map +2 -2
  9. package/dist/cjs/decorators/applyProperty.js +38 -17
  10. package/dist/cjs/decorators/applyProperty.js.map +2 -2
  11. package/dist/cjs/decorators/applyStyle.js +53 -22
  12. package/dist/cjs/decorators/applyStyle.js.map +2 -2
  13. package/dist/cjs/decorators/elementDefine.js +49 -33
  14. package/dist/cjs/decorators/elementDefine.js.map +3 -3
  15. package/dist/cjs/decorators/emitCustomEvent.js +61 -47
  16. package/dist/cjs/decorators/emitCustomEvent.js.map +2 -2
  17. package/dist/cjs/decorators/lifecycles.js +11 -36
  18. package/dist/cjs/decorators/lifecycles.js.map +2 -2
  19. package/dist/cjs/decorators/query.js +91 -56
  20. package/dist/cjs/decorators/query.js.map +2 -2
  21. package/dist/cjs/decorators/queryAll.js +104 -66
  22. package/dist/cjs/decorators/queryAll.js.map +2 -2
  23. package/dist/cjs/elements/SwcAppMixin.js +6 -2
  24. package/dist/cjs/elements/SwcAppMixin.js.map +2 -2
  25. package/dist/cjs/types/window.d.js.map +1 -1
  26. package/dist/esm/decorators/addEventListener.js.map +2 -2
  27. package/dist/esm/decorators/applyAttribute.js +36 -15
  28. package/dist/esm/decorators/applyAttribute.js.map +2 -2
  29. package/dist/esm/decorators/applyClass.js +53 -22
  30. package/dist/esm/decorators/applyClass.js.map +2 -2
  31. package/dist/esm/decorators/applyNode.js +54 -24
  32. package/dist/esm/decorators/applyNode.js.map +2 -2
  33. package/dist/esm/decorators/applyProperty.js +38 -17
  34. package/dist/esm/decorators/applyProperty.js.map +2 -2
  35. package/dist/esm/decorators/applyStyle.js +53 -22
  36. package/dist/esm/decorators/applyStyle.js.map +2 -2
  37. package/dist/esm/decorators/elementDefine.js +50 -34
  38. package/dist/esm/decorators/elementDefine.js.map +2 -2
  39. package/dist/esm/decorators/emitCustomEvent.js +61 -47
  40. package/dist/esm/decorators/emitCustomEvent.js.map +2 -2
  41. package/dist/esm/decorators/lifecycles.js +11 -36
  42. package/dist/esm/decorators/lifecycles.js.map +2 -2
  43. package/dist/esm/decorators/query.js +91 -56
  44. package/dist/esm/decorators/query.js.map +2 -2
  45. package/dist/esm/decorators/queryAll.js +104 -66
  46. package/dist/esm/decorators/queryAll.js.map +2 -2
  47. package/dist/esm/elements/SwcAppMixin.js +6 -2
  48. package/dist/esm/elements/SwcAppMixin.js.map +2 -2
  49. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +572 -320
  50. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +3 -3
  51. package/dist/types/decorators/addEventListener.d.ts +7 -6
  52. package/dist/types/decorators/addEventListener.d.ts.map +1 -1
  53. package/dist/types/decorators/applyAttribute.d.ts +13 -8
  54. package/dist/types/decorators/applyAttribute.d.ts.map +1 -1
  55. package/dist/types/decorators/applyClass.d.ts +8 -7
  56. package/dist/types/decorators/applyClass.d.ts.map +1 -1
  57. package/dist/types/decorators/applyNode.d.ts +18 -17
  58. package/dist/types/decorators/applyNode.d.ts.map +1 -1
  59. package/dist/types/decorators/applyProperty.d.ts +14 -9
  60. package/dist/types/decorators/applyProperty.d.ts.map +1 -1
  61. package/dist/types/decorators/applyStyle.d.ts +6 -5
  62. package/dist/types/decorators/applyStyle.d.ts.map +1 -1
  63. package/dist/types/decorators/elementDefine.d.ts.map +1 -1
  64. package/dist/types/decorators/emitCustomEvent.d.ts +3 -2
  65. package/dist/types/decorators/emitCustomEvent.d.ts.map +1 -1
  66. package/dist/types/decorators/lifecycles.d.ts +12 -13
  67. package/dist/types/decorators/lifecycles.d.ts.map +1 -1
  68. package/dist/types/decorators/query.d.ts +15 -5
  69. package/dist/types/decorators/query.d.ts.map +1 -1
  70. package/dist/types/decorators/queryAll.d.ts +15 -5
  71. package/dist/types/decorators/queryAll.d.ts.map +1 -1
  72. package/dist/types/elements/SwcAppMixin.d.ts.map +1 -1
  73. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +572 -320
  74. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +3 -3
  75. package/package.json +3 -3
  76. package/src/decorators/addEventListener.ts +9 -7
  77. package/src/decorators/applyAttribute.ts +60 -27
  78. package/src/decorators/applyClass.ts +78 -32
  79. package/src/decorators/applyNode.ts +118 -73
  80. package/src/decorators/applyProperty.ts +63 -30
  81. package/src/decorators/applyStyle.ts +76 -30
  82. package/src/decorators/elementDefine.ts +57 -37
  83. package/src/decorators/emitCustomEvent.ts +63 -39
  84. package/src/decorators/lifecycles.ts +53 -52
  85. package/src/decorators/query.ts +111 -49
  86. package/src/decorators/queryAll.ts +121 -61
  87. package/src/elements/SwcAppMixin.ts +7 -3
  88. package/src/types/window.d.ts +3 -0
  89. package/dist/cjs/examples/RxJSOperatorsExample.js +0 -285
  90. package/dist/cjs/examples/RxJSOperatorsExample.js.map +0 -7
  91. package/dist/esm/examples/RxJSOperatorsExample.js +0 -266
  92. package/dist/esm/examples/RxJSOperatorsExample.js.map +0 -7
  93. package/dist/types/examples/RxJSOperatorsExample.d.ts +0 -94
  94. package/dist/types/examples/RxJSOperatorsExample.d.ts.map +0 -1
  95. package/src/examples/RxJSOperatorsExample.ts +0 -279
@@ -3,6 +3,8 @@ import { SpecialSelector, SwcQueryOptions, HelperHostSet } from '../types';
3
3
  import {ensureInit, getElementConfig} from './elementDefine';
4
4
  import {SwcUtils} from '../utils/Utils';
5
5
 
6
+ export type EmitCustomEventSelector = string | ((currentThis: any, helper: HelperHostSet) => NodeList | Element | Element[] | null);
7
+
6
8
  export interface EmitCustomEventBaseOptions {
7
9
  bubbles?: boolean;
8
10
  composed?: boolean;
@@ -30,7 +32,7 @@ type Options = (EmitCustomEventBaseOptions & SwcQueryOptions) | (EmitCustomEvent
30
32
 
31
33
  export interface EmitCustomEventMetadata {
32
34
  propertyKey: string | symbol;
33
- selector: string;
35
+ selector: EmitCustomEventSelector;
34
36
  type: string;
35
37
  options: Options;
36
38
  }
@@ -38,7 +40,7 @@ export interface EmitCustomEventMetadata {
38
40
  export const EMIT_CUSTOM_EVENT_METADATA_KEY = Symbol.for('simple-web-component:emit-custom-event');
39
41
 
40
42
  export function emitCustomEvent(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
41
- export function emitCustomEvent(selector: string, type: string, options?: Options): MethodDecorator;
43
+ export function emitCustomEvent(selector: EmitCustomEventSelector, type: string, options?: Options): MethodDecorator;
42
44
  export function emitCustomEvent(type: string, options?: Options): MethodDecorator;
43
45
  /**
44
46
  * @emitCustomEvent decorator to dispatch custom events to a target.
@@ -46,6 +48,7 @@ export function emitCustomEvent(type: string, options?: Options): MethodDecorato
46
48
  * Usage:
47
49
  * - @emitCustomEvent('$this', 'event-name', options) - Emit from $this
48
50
  * - @emitCustomEvent('$appHost', 'event-name', options) - Emit from $appHost
51
+ * - @emitCustomEvent((this, helper) => '.button', 'event-name', options) - Function-based selector
49
52
  * - @emitCustomEvent('event-name', options) - Emit from $this (defaults to $this)
50
53
  * - @emitCustomEvent('event-name') - Emit from $this with no options
51
54
  */
@@ -56,7 +59,7 @@ export function emitCustomEvent(selectorOrTarget: any, typeOrPropertyKey?: any,
56
59
  }
57
60
 
58
61
  // Case 2: With selector and type - @emitCustomEvent('selector', 'event-name', options)
59
- if (typeof selectorOrTarget === 'string' && typeof typeOrPropertyKey === 'string') {
62
+ if ((typeof selectorOrTarget === 'string' || typeof selectorOrTarget === 'function') && typeof typeOrPropertyKey === 'string') {
60
63
  return createEmitDecorator(selectorOrTarget, typeOrPropertyKey, optionsOrDescriptor as Options);
61
64
  }
62
65
 
@@ -69,7 +72,7 @@ export function emitCustomEvent(selectorOrTarget: any, typeOrPropertyKey?: any,
69
72
  throw new Error('Invalid @emitCustomEvent usage');
70
73
  }
71
74
 
72
- function createEmitDecorator(selector: string, type: string, options?: Options) {
75
+ function createEmitDecorator(selector: EmitCustomEventSelector, type: string, options?: Options) {
73
76
  return (targetObj: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
74
77
  const constructor = targetObj.constructor;
75
78
 
@@ -98,47 +101,68 @@ function createEmitDecorator(selector: string, type: string, options?: Options)
98
101
  cancelable: fullOptions.cancelable
99
102
  });
100
103
 
101
- const hostSet = SwcUtils.getHostSet(this as any);
102
104
  const conf = getElementConfig(this);
103
105
  const currentWin = (this as any)._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as Window);
106
+ const hostSet = SwcUtils.getHelperAndHostSet(currentWin, this as any);
104
107
 
105
108
  const eventTargets: EventTarget[] = [];
106
- if (selector === '$window') eventTargets.push(currentWin);
107
- else if (selector === '$document') eventTargets.push(currentWin.document);
108
- else if (selector === '$host') {
109
- if (hostSet.$host) eventTargets.push(hostSet.$host);
110
- } else if (selector === '$parentHost') {
111
- if (hostSet.$parentHost) eventTargets.push(hostSet.$parentHost);
112
- } else if (selector === '$appHost') {
113
- if (hostSet.$appHost) eventTargets.push(hostSet.$appHost);
114
- } else if (selector === '$firstHost') {
115
- if (hostSet.$firstHost) eventTargets.push(hostSet.$firstHost);
116
- } else if (selector === '$lastHost') {
117
- if (hostSet.$lastHost) eventTargets.push(hostSet.$lastHost);
118
- } else if (selector === '$firstAppHost') {
119
- if (hostSet.$firstAppHost) eventTargets.push(hostSet.$firstAppHost);
120
- } else if (selector === '$lastAppHost') {
121
- if (hostSet.$lastAppHost) eventTargets.push(hostSet.$lastAppHost);
122
- } else if (selector === '$hosts') {
123
- hostSet.$hosts.forEach(h => eventTargets.push(h));
124
- } else if (selector === '$appHosts') {
125
- hostSet.$appHosts.forEach(h => eventTargets.push(h));
126
- } else if (selector === '$this' || !selector) {
127
- eventTargets.push(this as any);
109
+
110
+ // Resolve selector if it's a function
111
+ let resolvedSelector: string | Element | NodeList | Element[] | null = selector as any;
112
+ if (typeof selector === 'function') {
113
+ resolvedSelector = selector(this, hostSet);
114
+ }
115
+
116
+ // If selector function returned elements directly, use them
117
+ if (resolvedSelector instanceof currentWin.Element) {
118
+ eventTargets.push(resolvedSelector as EventTarget);
119
+ } else if (resolvedSelector instanceof currentWin.NodeList) {
120
+ eventTargets.push(...Array.from(resolvedSelector as EventTarget[]));
121
+ } else if (Array.isArray(resolvedSelector)) {
122
+ eventTargets.push(...(resolvedSelector as EventTarget[]));
123
+ } else if (resolvedSelector === null) {
124
+ // No targets
128
125
  } else {
129
- const r = fullOptions.root || 'auto';
130
- const searchRoots: (HTMLElement | ShadowRoot)[] = [];
131
- if (r === 'auto') searchRoots.push(this.shadowRoot || (this as any));
132
- else if (r === 'light') searchRoots.push(this as any);
133
- else if (r === 'shadow' && this.shadowRoot) searchRoots.push(this.shadowRoot);
134
- else if (r === 'all') {
135
- searchRoots.push(this as any);
136
- if (this.shadowRoot) searchRoots.push(this.shadowRoot);
126
+ // Handle string selector
127
+ const stringSelector = resolvedSelector as string;
128
+
129
+ if (stringSelector === '$window') eventTargets.push(currentWin);
130
+ else if (stringSelector === '$document') eventTargets.push(currentWin.document);
131
+ else if (stringSelector === '$host') {
132
+ if (hostSet.$host) eventTargets.push(hostSet.$host);
133
+ } else if (stringSelector === '$parentHost') {
134
+ if (hostSet.$parentHost) eventTargets.push(hostSet.$parentHost);
135
+ } else if (stringSelector === '$appHost') {
136
+ if (hostSet.$appHost) eventTargets.push(hostSet.$appHost);
137
+ } else if (stringSelector === '$firstHost') {
138
+ if (hostSet.$firstHost) eventTargets.push(hostSet.$firstHost);
139
+ } else if (stringSelector === '$lastHost') {
140
+ if (hostSet.$lastHost) eventTargets.push(hostSet.$lastHost);
141
+ } else if (stringSelector === '$firstAppHost') {
142
+ if (hostSet.$firstAppHost) eventTargets.push(hostSet.$firstAppHost);
143
+ } else if (stringSelector === '$lastAppHost') {
144
+ if (hostSet.$lastAppHost) eventTargets.push(hostSet.$lastAppHost);
145
+ } else if (stringSelector === '$hosts') {
146
+ hostSet.$hosts.forEach(h => eventTargets.push(h));
147
+ } else if (stringSelector === '$appHosts') {
148
+ hostSet.$appHosts.forEach(h => eventTargets.push(h));
149
+ } else if (stringSelector === '$this' || !stringSelector) {
150
+ eventTargets.push(this as any);
151
+ } else {
152
+ const r = fullOptions.root || 'auto';
153
+ const searchRoots: (HTMLElement | ShadowRoot)[] = [];
154
+ if (r === 'auto') searchRoots.push(this.shadowRoot || (this as any));
155
+ else if (r === 'light') searchRoots.push(this as any);
156
+ else if (r === 'shadow' && this.shadowRoot) searchRoots.push(this.shadowRoot);
157
+ else if (r === 'all') {
158
+ searchRoots.push(this as any);
159
+ if (this.shadowRoot) searchRoots.push(this.shadowRoot);
160
+ }
161
+
162
+ searchRoots.forEach(sr => {
163
+ sr.querySelectorAll(stringSelector).forEach(el => eventTargets.push(el));
164
+ });
137
165
  }
138
-
139
- searchRoots.forEach(sr => {
140
- sr.querySelectorAll(selector).forEach(el => eventTargets.push(el));
141
- });
142
166
  }
143
167
 
144
168
  eventTargets.forEach(t => {
@@ -8,24 +8,25 @@ export const ON_AFTER_DISCONNECTED_METADATA_KEY = Symbol.for('simple-web-compone
8
8
  export const ON_BEFORE_ADOPTED_METADATA_KEY = Symbol.for('simple-web-component:on-before-adopted');
9
9
  export const ON_AFTER_ADOPTED_METADATA_KEY = Symbol.for('simple-web-component:on-after-adopted');
10
10
  export const ON_ADD_EVENT_LISTENER_METADATA_KEY = Symbol.for('simple-web-component:on-add-event-listener');
11
- export const ON_CONNECTED_METADATA_KEY = Symbol.for('simple-web-component');
11
+ export const ON_CONNECTED_BODY_METADATA_KEY = Symbol.for('simple-web-component:on-connected-body');
12
12
  export const ON_CONNECTED_SWC_APP_METADATA_KEY = Symbol.for('simple-web-component:on-connected-swc-app');
13
13
  export const ON_CONNECTED_COMPLETED_METADATA_KEY = Symbol.for('simple-web-component:on-completed');
14
14
 
15
15
  export const ATTRIBUTE_CHANGED_WILDCARD = '*';
16
16
 
17
- export interface InnerHtmlOptions {
18
- ssrFirst?: boolean;
17
+ export interface OnConnectedAppendChildOptions {
18
+ // ssrFirst?: boolean;
19
19
  // replaceWrap?:{ start: string, end:string},
20
20
  useShadow?: boolean;
21
+ order?: number;
21
22
  }
22
- export interface InnerHtmlMetadata {
23
+ export interface OnConnectedAppendChildOptionsMetadata {
23
24
  propertyKey: string | symbol;
24
- options: InnerHtmlOptions;
25
+ options: OnConnectedAppendChildOptions;
25
26
  }
26
27
 
27
28
  export interface OnConnectedOptions {
28
- ssrFirst?: boolean;
29
+ // ssrFirst?: boolean;
29
30
  order?: number;
30
31
  }
31
32
  export interface OnConnectedMetadata {
@@ -87,33 +88,33 @@ export function onConnectedAfter(arg1?: OnConnectedOptions | Object, arg2?: stri
87
88
  }
88
89
 
89
90
 
90
- function createLifecycleDecorator(metadataKey: symbol): ((options?: LifecycleOptions) => MethodDecorator) & MethodDecorator {
91
- const decorator = (options?: LifecycleOptions): MethodDecorator => {
92
- return (target: Object, propertyKey: string | symbol) => {
93
- const constructor = target.constructor;
94
- let list = ReflectUtils.getOwnMetadata(metadataKey, constructor) as LifecycleMetadata[];
95
- if (!list) {
96
- list = [];
97
- ReflectUtils.defineMetadata(metadataKey, list, constructor);
98
- }
99
- list.push({ propertyKey, order: options?.order ?? 0 });
100
- };
101
- };
102
-
103
- // Support both @decorator and @decorator() syntax
104
- return Object.assign(
105
- (target: Object, propertyKey: string | symbol) => {
106
- const constructor = target.constructor;
107
- let list = ReflectUtils.getOwnMetadata(metadataKey, constructor) as LifecycleMetadata[];
108
- if (!list) {
109
- list = [];
110
- ReflectUtils.defineMetadata(metadataKey, list, constructor);
111
- }
112
- list.push({ propertyKey, order: 0 });
113
- },
114
- { __isDecorator: true, __decorator: decorator }
115
- ) as any;
116
- }
91
+ // function createLifecycleDecorator(metadataKey: symbol): ((options?: LifecycleOptions) => MethodDecorator) & MethodDecorator {
92
+ // const decorator = (options?: LifecycleOptions): MethodDecorator => {
93
+ // return (target: Object, propertyKey: string | symbol) => {
94
+ // const constructor = target.constructor;
95
+ // let list = ReflectUtils.getOwnMetadata(metadataKey, constructor) as LifecycleMetadata[];
96
+ // if (!list) {
97
+ // list = [];
98
+ // ReflectUtils.defineMetadata(metadataKey, list, constructor);
99
+ // }
100
+ // list.push({ propertyKey, order: options?.order ?? 0 });
101
+ // };
102
+ // };
103
+ //
104
+ // // Support both @decorator and @decorator() syntax
105
+ // return Object.assign(
106
+ // (target: Object, propertyKey: string | symbol) => {
107
+ // const constructor = target.constructor;
108
+ // let list = ReflectUtils.getOwnMetadata(metadataKey, constructor) as LifecycleMetadata[];
109
+ // if (!list) {
110
+ // list = [];
111
+ // ReflectUtils.defineMetadata(metadataKey, list, constructor);
112
+ // }
113
+ // list.push({ propertyKey, order: 0 });
114
+ // },
115
+ // { __isDecorator: true, __decorator: decorator }
116
+ // ) as any;
117
+ // }
117
118
 
118
119
  // Helper to handle both @decorator and @decorator() syntax
119
120
  function createLifecycleDecoratorWithOptions(metadataKey: symbol) {
@@ -193,19 +194,19 @@ export function onConnectedCompleted(optionOrTarget?: LifecycleOptions | Object,
193
194
 
194
195
 
195
196
 
196
- const decorator = (options: InnerHtmlOptions, target: Object, propertyKey: string | symbol) => {
197
+ const decorator = (options: OnConnectedAppendChildOptions, target: Object, propertyKey: string | symbol) => {
197
198
  const constructor = target.constructor;
198
- let list = ReflectUtils.getMetadata<InnerHtmlMetadata[]>(ON_CONNECTED_METADATA_KEY, constructor);
199
+ let list = ReflectUtils.getMetadata<OnConnectedAppendChildOptionsMetadata[]>(ON_CONNECTED_BODY_METADATA_KEY, constructor);
199
200
  if (!list) {
200
201
  list = [];
201
- ReflectUtils.defineMetadata(ON_CONNECTED_METADATA_KEY, list, constructor);
202
+ ReflectUtils.defineMetadata(ON_CONNECTED_BODY_METADATA_KEY, list, constructor);
202
203
  }
203
204
  list.push({ propertyKey, options });
204
205
  };
205
206
 
206
- export function onConnectedShadow(options: Omit<InnerHtmlOptions, 'useShadow'>): MethodDecorator; // 파라미터있음
207
- export function onConnectedShadow(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void; // 파라미터없음
208
- export function onConnectedShadow(optionOrTarget: Omit<InnerHtmlOptions, 'useShadow'> | Object, propertyKey?: string | symbol, arg3?: PropertyDescriptor): MethodDecorator | void {
207
+ export function onConnectedBodyShadow(options: Omit<OnConnectedAppendChildOptions, 'useShadow'>): MethodDecorator; // 파라미터있음
208
+ export function onConnectedBodyShadow(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void; // 파라미터없음
209
+ export function onConnectedBodyShadow(optionOrTarget: Omit<OnConnectedAppendChildOptions, 'useShadow'> | Object, propertyKey?: string | symbol, arg3?: PropertyDescriptor): MethodDecorator | void {
209
210
  if (propertyKey) { // no parameter option @decorator
210
211
  return decorator({useShadow: true}, optionOrTarget!, propertyKey);
211
212
  }
@@ -215,9 +216,9 @@ export function onConnectedShadow(optionOrTarget: Omit<InnerHtmlOptions, 'useSha
215
216
  };
216
217
  }
217
218
 
218
- export function onConnectedLight(options: Omit<InnerHtmlOptions, 'useShadow'>): MethodDecorator; // 파라미터있음
219
- export function onConnectedLight(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void; // 파라미터없음
220
- export function onConnectedLight(optionOrTarget: Omit<InnerHtmlOptions, 'useShadow'> | Object, propertyKey?: string | symbol, arg3?: PropertyDescriptor): MethodDecorator | void {
219
+ export function onConnectedBodyLight(options: Omit<OnConnectedAppendChildOptions, 'useShadow'>): MethodDecorator; // 파라미터있음
220
+ export function onConnectedBodyLight(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void; // 파라미터없음
221
+ export function onConnectedBodyLight(optionOrTarget: Omit<OnConnectedAppendChildOptions, 'useShadow'> | Object, propertyKey?: string | symbol, arg3?: PropertyDescriptor): MethodDecorator | void {
221
222
  if (propertyKey) { // no parameter option @decorator
222
223
  return decorator({useShadow: false}, optionOrTarget!, propertyKey);
223
224
  }
@@ -226,15 +227,15 @@ export function onConnectedLight(optionOrTarget: Omit<InnerHtmlOptions, 'useShad
226
227
  decorator({...optionOrTarget??{}, useShadow: false}, target, propertyKey);
227
228
  };
228
229
  }
229
- export function onConnected(options: InnerHtmlOptions): MethodDecorator;
230
- export function onConnected(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
231
- export function onConnected(optionOrTarget: InnerHtmlOptions | Object, propertyKey?: string | symbol, arg3?: PropertyDescriptor): MethodDecorator | void {
230
+ export function onConnectedBody(options: OnConnectedAppendChildOptions): MethodDecorator;
231
+ export function onConnectedBody(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
232
+ export function onConnectedBody(optionOrTarget: OnConnectedAppendChildOptions | Object, propertyKey?: string | symbol, arg3?: PropertyDescriptor): MethodDecorator | void {
232
233
  if (propertyKey) { // no parameter option @decorator
233
234
  return decorator({}, optionOrTarget!, propertyKey);
234
235
  }
235
236
  // parameter option @decorator()
236
237
  return (target: Object, propertyKey: string | symbol) => {
237
- decorator((optionOrTarget as InnerHtmlOptions) || {}, target, propertyKey);
238
+ decorator((optionOrTarget as OnConnectedAppendChildOptions) || {}, target, propertyKey);
238
239
  };
239
240
  }
240
241
 
@@ -248,27 +249,27 @@ export const findAllLifecycleMetadata = (target: any, metadataKey: symbol): Life
248
249
  return [...results].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
249
250
  };
250
251
 
251
- export const findAllOnConnectedMetadata = (target: any): InnerHtmlMetadata[] => {
252
+ export const findAllOnConnectedMetadata = (target: any): OnConnectedAppendChildOptionsMetadata[] => {
252
253
  const constructor = target instanceof Function ? target : target.constructor;
253
- const results = ReflectUtils.getMetadata(ON_CONNECTED_METADATA_KEY, constructor) ?? [];
254
+ const results = ReflectUtils.getMetadata<OnConnectedAppendChildOptionsMetadata[]>(ON_CONNECTED_BODY_METADATA_KEY, constructor) ?? [];
254
255
  // Sort by order (default 0 if not specified)
255
256
  return [...results].sort((a, b) => {
256
- const orderA = (a.options as any)?.order ?? 0;
257
- const orderB = (b.options as any)?.order ?? 0;
257
+ const orderA = a.options?.order ?? 0;
258
+ const orderB = b.options?.order ?? 0;
258
259
  return orderA - orderB;
259
260
  });
260
261
  };
261
262
 
262
263
  export const findAllOnConnectedBeforeMetadata = (target: any): OnConnectedMetadata[] => {
263
264
  const constructor = target instanceof Function ? target : target.constructor;
264
- const results = ReflectUtils.getMetadata(ON_BEFORE_CONNECTED_METADATA_KEY, constructor) ?? [];
265
+ const results = ReflectUtils.getMetadata<OnConnectedMetadata[]>(ON_BEFORE_CONNECTED_METADATA_KEY, constructor) ?? [];
265
266
  // Sort by order
266
267
  return [...results].sort((a, b) => (a.options?.order ?? 0) - (b.options?.order ?? 0));
267
268
  };
268
269
 
269
270
  export const findAllOnConnectedAfterMetadata = (target: any): OnConnectedMetadata[] => {
270
271
  const constructor = target instanceof Function ? target : target.constructor;
271
- const results = ReflectUtils.getMetadata(ON_AFTER_CONNECTED_METADATA_KEY, constructor) ?? [];
272
+ const results = ReflectUtils.getMetadata<OnConnectedMetadata[]>(ON_AFTER_CONNECTED_METADATA_KEY, constructor) ?? [];
272
273
  // Sort by order
273
274
  return [...results].sort((a, b) => (a.options?.order ?? 0) - (b.options?.order ?? 0));
274
275
  };
@@ -1,29 +1,44 @@
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 QueryOptions 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 QueryMetadata {
7
15
  propertyKey: string | symbol;
8
- selector: string;
9
- options: SwcQueryOptions ;
16
+ selector: string | ((currentThis: any, helper: HelperHostSet) => Node | NodeList | Element | Element[] | null);
17
+ options: QueryOptions ;
10
18
  }
11
19
 
12
20
  export const QUERY_METADATA_KEY = Symbol.for('simple-web-component:query');
13
21
 
14
22
  export function query(target: Object, propertyKey: string | symbol, descriptor?: PropertyDescriptor): PropertyDescriptor | void;
15
- export function query(selector: string, options?: SwcQueryOptions): PropertyDecorator;
16
- export function query(options?: SwcQueryOptions): PropertyDecorator;
23
+ export function query(selector: string | ((currentThis: any, helper: HelperHostSet) => Node | NodeList | Element | Element[] | null), options?: QueryOptions): PropertyDecorator;
24
+ export function query(options?: QueryOptions): PropertyDecorator;
17
25
  /**
18
26
  * @query decorator to inject a single element into a class property.
27
+ *
28
+ * Supports both string selectors and function-based selectors:
29
+ * - String selector: @query('#my-element')
30
+ * - Function selector: @query((currentThis, helper) => currentThis.shadowRoot?.querySelector('.item'))
31
+ *
32
+ * Supports filtering:
33
+ * - @query('#my-element', { filter: (target, meta) => target.hasAttribute('active') })
19
34
  */
20
- export function query(selectorOrTarget?: string | Object, optionsOrPropertyKey?: SwcQueryOptions | string | symbol, descriptor?: PropertyDescriptor): any {
35
+ export function query(selectorOrTarget?: string | ((currentThis: any, helper: HelperHostSet) => Node | NodeList | Element | Element[] | null) | Object, optionsOrPropertyKey?: QueryOptions | string | symbol, descriptor?: PropertyDescriptor): any {
21
36
  // Bare decorator: @query
22
37
  if (descriptor !== undefined && (typeof optionsOrPropertyKey === 'string' || typeof optionsOrPropertyKey === 'symbol')) {
23
38
  throw new Error(`@query decorator cannot be used on methods. (Method: ${String(optionsOrPropertyKey)})`);
24
39
  }
25
40
  // With selector
26
- if (typeof selectorOrTarget === 'string') {
41
+ if (typeof selectorOrTarget === 'string' || typeof selectorOrTarget === 'function') {
27
42
  return (targetObj: Object, propertyKey: string | symbol, descriptor?: never): void => {
28
43
  if (descriptor !== undefined) {
29
44
  throw new Error(`@query decorator cannot be used on methods. (Method: ${String(propertyKey)})`);
@@ -35,67 +50,114 @@ export function query(selectorOrTarget?: string | Object, optionsOrPropertyKey?:
35
50
  queries = [];
36
51
  ReflectUtils.defineMetadata(QUERY_METADATA_KEY, queries, constructor);
37
52
  }
38
- queries.push({ propertyKey, selector: selectorOrTarget, options: optionsOrPropertyKey as SwcQueryOptions || {} });
53
+ queries.push({ propertyKey, selector: selectorOrTarget as any, options: optionsOrPropertyKey as QueryOptions || {} });
39
54
 
40
55
  Object.defineProperty(targetObj, propertyKey, {
41
56
  get(this: HTMLElement) {
42
57
  ensureInit(this);
43
- const selector = selectorOrTarget;
44
-
45
- const r = (optionsOrPropertyKey as SwcQueryOptions)?.root || 'auto';
46
- const applyRoot = (t: any) => {
47
- if (!t || !(t instanceof HTMLElement)) return t;
48
- if (r === 'auto') return t.shadowRoot || t;
49
- if (r === 'shadow') return t.shadowRoot;
50
- if (r === 'light') return t;
51
- if (r === 'all') return t.shadowRoot || t;
52
- return t;
53
- };
54
-
55
- // --- Special Selectors: HostSet ---
56
- const hostSet = SwcUtils.getHostSet(this);
57
- if (selector === '$this') return applyRoot(this);
58
- if (selector === '$host') return applyRoot(hostSet.$host);
59
- if (selector === '$parentHost') return applyRoot(hostSet.$parentHost);
60
- if (selector === '$appHost') return applyRoot(hostSet.$appHost);
61
- if (selector === '$firstHost') return applyRoot(hostSet.$firstHost);
62
- if (selector === '$lastHost') return applyRoot(hostSet.$lastHost);
63
- if (selector === '$firstAppHost') return applyRoot(hostSet.$firstAppHost);
64
- if (selector === '$lastAppHost') return applyRoot(hostSet.$lastAppHost);
65
-
66
- // --- Special Selectors: Env ---
67
58
  const config = getElementConfig(this);
68
59
  const win = config?.window || window;
69
- if (selector === '$window') return win;
70
- if (selector === '$document') return win.document;
60
+ const hostSet = SwcUtils.getHelperAndHostSet(win, this);
61
+
62
+ // Resolve selector - can be string or function
63
+ let resolvedSelector: string;
64
+ let resolvedElement: HTMLElement | null = null;
65
+
66
+ if (typeof selectorOrTarget === 'function') {
67
+ const result = (selectorOrTarget as any)(this, hostSet);
68
+ // If function returns a Node/Element, return it directly
69
+ if (result instanceof win.Node || result instanceof win.Element) {
70
+ resolvedElement = result instanceof win.HTMLElement ? (result as HTMLElement) : null;
71
+ }
72
+ // If function returns NodeList or Element[], return first element
73
+ else if (result instanceof win.NodeList || Array.isArray(result)) {
74
+ resolvedElement = result.length > 0 && result[0] instanceof win.HTMLElement ? (result[0] as HTMLElement) : null;
75
+ }
76
+ } else {
77
+ resolvedSelector = selectorOrTarget;
71
78
 
72
- // --- Standard Selectors ---
73
- if (r === 'shadow') return this.shadowRoot ? this.shadowRoot.querySelector(selector) : null;
74
- if (r === 'light') return this.querySelector(selector);
75
- if (r === 'all') {
76
- const shadowMatch = this.shadowRoot ? this.shadowRoot.querySelector(selector) : null;
77
- return shadowMatch || this.querySelector(selector);
79
+ const r = (optionsOrPropertyKey as QueryOptions)?.root || 'auto';
80
+ const applyRoot = (t: any) => {
81
+ if (!t || !(t instanceof HTMLElement)) return t;
82
+ if (r === 'auto') return t.shadowRoot || t;
83
+ if (r === 'shadow') return t.shadowRoot;
84
+ if (r === 'light') return t;
85
+ if (r === 'all') return t.shadowRoot || t;
86
+ return t;
87
+ };
88
+
89
+ // --- Special Selectors: HostSet ---
90
+ if (resolvedSelector === '$this') resolvedElement = applyRoot(this);
91
+ else if (resolvedSelector === '$host') resolvedElement = applyRoot(hostSet.$host);
92
+ else if (resolvedSelector === '$parentHost') resolvedElement = applyRoot(hostSet.$parentHost);
93
+ else if (resolvedSelector === '$appHost') resolvedElement = applyRoot(hostSet.$appHost);
94
+ else if (resolvedSelector === '$firstHost') resolvedElement = applyRoot(hostSet.$firstHost);
95
+ else if (resolvedSelector === '$lastHost') resolvedElement = applyRoot(hostSet.$lastHost);
96
+ else if (resolvedSelector === '$firstAppHost') resolvedElement = applyRoot(hostSet.$firstAppHost);
97
+ else if (resolvedSelector === '$lastAppHost') resolvedElement = applyRoot(hostSet.$lastAppHost);
98
+ // --- Special Selectors: Env ---
99
+ else if (resolvedSelector === '$window') return win;
100
+ else if (resolvedSelector === '$document') return win.document;
101
+ // --- Standard Selectors ---
102
+ else {
103
+ if (r === 'shadow') resolvedElement = this.shadowRoot ? (this.shadowRoot.querySelector(resolvedSelector) as HTMLElement | null) : null;
104
+ else if (r === 'light') resolvedElement = this.querySelector(resolvedSelector) as HTMLElement | null;
105
+ else if (r === 'all') {
106
+ const shadowMatch = this.shadowRoot ? (this.shadowRoot.querySelector(resolvedSelector) as HTMLElement | null) : null;
107
+ resolvedElement = shadowMatch || (this.querySelector(resolvedSelector) as HTMLElement | null);
108
+ }
109
+ else resolvedElement = ((this.shadowRoot || this).querySelector(resolvedSelector) as HTMLElement | null);
110
+ }
78
111
  }
79
- return (this.shadowRoot || this).querySelector(selector);
112
+
113
+ // Apply filter if provided
114
+ if (resolvedElement instanceof win.HTMLElement && (optionsOrPropertyKey as QueryOptions)?.filter) {
115
+ const shouldInclude = (optionsOrPropertyKey as QueryOptions).filter!(resolvedElement, { currentThis: this, helper: hostSet });
116
+ if (!shouldInclude) {
117
+ return null;
118
+ }
119
+ }
120
+
121
+ return resolvedElement;
80
122
  },
81
123
  set(this: HTMLElement, nv: any) {
82
124
  ensureInit(this);
83
125
  if (nv === null || nv === undefined) {
84
- const selector = selectorOrTarget;
85
- if (selector.startsWith('$') && selector !== '$this') return;
126
+ const config = getElementConfig(this);
127
+ const win = config?.window || window;
128
+ const hostSet = SwcUtils.getHelperAndHostSet(win, this);
129
+
130
+ // Resolve selector - can be string or function
131
+ if (typeof selectorOrTarget === 'function') {
132
+ // Get the element from function and remove it
133
+ const result = (selectorOrTarget as any)(this, hostSet);
134
+ if (result instanceof win.Element) {
135
+ (result as Element).remove();
136
+ } else if (result instanceof win.NodeList || Array.isArray(result)) {
137
+ const el = result.length > 0 ? result[0] : null;
138
+ if (el instanceof win.Element) {
139
+ (el as Element).remove();
140
+ }
141
+ }
142
+ return;
143
+ }
144
+
145
+ const resolvedSelector = selectorOrTarget;
146
+
147
+ if (resolvedSelector.startsWith('$') && resolvedSelector !== '$this') return;
86
148
 
87
- const r = (optionsOrPropertyKey as SwcQueryOptions)?.root || 'auto';
149
+ const r = (optionsOrPropertyKey as QueryOptions)?.root || 'auto';
88
150
  const targets: Element[] = [];
89
151
 
90
152
  if (r === 'shadow') {
91
- if (this.shadowRoot?.querySelector(selector)) targets.push(this.shadowRoot.querySelector(selector)!);
153
+ if (this.shadowRoot?.querySelector(resolvedSelector)) targets.push(this.shadowRoot.querySelector(resolvedSelector)!);
92
154
  } else if (r === 'light') {
93
- if (this.querySelector(selector)) targets.push(this.querySelector(selector)!);
155
+ if (this.querySelector(resolvedSelector)) targets.push(this.querySelector(resolvedSelector)!);
94
156
  } else if (r === 'all') {
95
- if (this.shadowRoot?.querySelector(selector)) targets.push(this.shadowRoot.querySelector(selector)!);
96
- if (this.querySelector(selector)) targets.push(this.querySelector(selector)!);
157
+ if (this.shadowRoot?.querySelector(resolvedSelector)) targets.push(this.shadowRoot.querySelector(resolvedSelector)!);
158
+ if (this.querySelector(resolvedSelector)) targets.push(this.querySelector(resolvedSelector)!);
97
159
  } else {
98
- const el = (this.shadowRoot || this).querySelector(selector);
160
+ const el = (this.shadowRoot || this).querySelector(resolvedSelector);
99
161
  if (el) targets.push(el);
100
162
  }
101
163