@dooboostore/simple-web-component 1.0.42 → 1.0.44

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 (153) hide show
  1. package/README.md +689 -85
  2. package/dist/cjs/SwcAppEngine.js +3 -1
  3. package/dist/cjs/SwcAppEngine.js.map +2 -2
  4. package/dist/cjs/decorators/addEventListener.js +10 -0
  5. package/dist/cjs/decorators/addEventListener.js.map +2 -2
  6. package/dist/cjs/decorators/applyAttribute.js +41 -30
  7. package/dist/cjs/decorators/applyAttribute.js.map +2 -2
  8. package/dist/cjs/decorators/applyClass.js +66 -23
  9. package/dist/cjs/decorators/applyClass.js.map +3 -3
  10. package/dist/cjs/decorators/applyNode.js +176 -107
  11. package/dist/cjs/decorators/applyNode.js.map +2 -2
  12. package/dist/cjs/decorators/applyProperty.js +21 -30
  13. package/dist/cjs/decorators/applyProperty.js.map +2 -2
  14. package/dist/cjs/decorators/applySlot.js +11 -2
  15. package/dist/cjs/decorators/applySlot.js.map +2 -2
  16. package/dist/cjs/decorators/applyStyle.js +48 -17
  17. package/dist/cjs/decorators/applyStyle.js.map +3 -3
  18. package/dist/cjs/decorators/{changedAttributeThis.js → changedAttribute.js} +6 -6
  19. package/dist/cjs/decorators/changedAttribute.js.map +7 -0
  20. package/dist/cjs/decorators/elementDefine.js +37 -6
  21. package/dist/cjs/decorators/elementDefine.js.map +3 -3
  22. package/dist/cjs/decorators/emitCustomEvent.js +58 -42
  23. package/dist/cjs/decorators/emitCustomEvent.js.map +2 -2
  24. package/dist/cjs/decorators/index.js +1 -1
  25. package/dist/cjs/decorators/index.js.map +2 -2
  26. package/dist/cjs/decorators/publishSwcAppMessage.js +37 -23
  27. package/dist/cjs/decorators/publishSwcAppMessage.js.map +3 -3
  28. package/dist/cjs/decorators/query.js +96 -145
  29. package/dist/cjs/decorators/query.js.map +3 -3
  30. package/dist/cjs/decorators/queryAll.js +104 -131
  31. package/dist/cjs/decorators/queryAll.js.map +3 -3
  32. package/dist/cjs/decorators/subscribeSwcAppMessageWhileConnected.js +2 -0
  33. package/dist/cjs/decorators/subscribeSwcAppMessageWhileConnected.js.map +2 -2
  34. package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js +2 -0
  35. package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +2 -2
  36. package/dist/cjs/elements/SwcAppMixin.js +17 -2
  37. package/dist/cjs/elements/SwcAppMixin.js.map +2 -2
  38. package/dist/cjs/examples/RxJSOperatorsExample.js +285 -0
  39. package/dist/cjs/examples/RxJSOperatorsExample.js.map +7 -0
  40. package/dist/cjs/index.js +1 -0
  41. package/dist/cjs/index.js.map +2 -2
  42. package/dist/cjs/router/ElementRouter.js +4 -0
  43. package/dist/cjs/router/ElementRouter.js.map +2 -2
  44. package/dist/esm/SwcAppEngine.js +3 -1
  45. package/dist/esm/SwcAppEngine.js.map +2 -2
  46. package/dist/esm/decorators/addEventListener.js +10 -0
  47. package/dist/esm/decorators/addEventListener.js.map +2 -2
  48. package/dist/esm/decorators/applyAttribute.js +41 -30
  49. package/dist/esm/decorators/applyAttribute.js.map +2 -2
  50. package/dist/esm/decorators/applyClass.js +66 -23
  51. package/dist/esm/decorators/applyClass.js.map +3 -3
  52. package/dist/esm/decorators/applyNode.js +176 -107
  53. package/dist/esm/decorators/applyNode.js.map +2 -2
  54. package/dist/esm/decorators/applyProperty.js +21 -30
  55. package/dist/esm/decorators/applyProperty.js.map +2 -2
  56. package/dist/esm/decorators/applySlot.js +11 -2
  57. package/dist/esm/decorators/applySlot.js.map +2 -2
  58. package/dist/esm/decorators/applyStyle.js +48 -17
  59. package/dist/esm/decorators/applyStyle.js.map +3 -3
  60. package/dist/esm/decorators/{changedAttributeThis.js → changedAttribute.js} +3 -3
  61. package/dist/esm/decorators/changedAttribute.js.map +7 -0
  62. package/dist/esm/decorators/elementDefine.js +35 -4
  63. package/dist/esm/decorators/elementDefine.js.map +2 -2
  64. package/dist/esm/decorators/emitCustomEvent.js +58 -42
  65. package/dist/esm/decorators/emitCustomEvent.js.map +2 -2
  66. package/dist/esm/decorators/index.js +1 -1
  67. package/dist/esm/decorators/index.js.map +1 -1
  68. package/dist/esm/decorators/publishSwcAppMessage.js +37 -23
  69. package/dist/esm/decorators/publishSwcAppMessage.js.map +3 -3
  70. package/dist/esm/decorators/query.js +96 -145
  71. package/dist/esm/decorators/query.js.map +3 -3
  72. package/dist/esm/decorators/queryAll.js +104 -131
  73. package/dist/esm/decorators/queryAll.js.map +3 -3
  74. package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js +2 -0
  75. package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js.map +2 -2
  76. package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js +2 -0
  77. package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +2 -2
  78. package/dist/esm/elements/SwcAppMixin.js +18 -3
  79. package/dist/esm/elements/SwcAppMixin.js.map +2 -2
  80. package/dist/esm/examples/RxJSOperatorsExample.js +266 -0
  81. package/dist/esm/examples/RxJSOperatorsExample.js.map +7 -0
  82. package/dist/esm/index.js +1 -0
  83. package/dist/esm/index.js.map +2 -2
  84. package/dist/esm/router/ElementRouter.js +4 -0
  85. package/dist/esm/router/ElementRouter.js.map +2 -2
  86. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +900 -578
  87. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
  88. package/dist/types/SwcAppEngine.d.ts.map +1 -1
  89. package/dist/types/decorators/addEventListener.d.ts +22 -14
  90. package/dist/types/decorators/addEventListener.d.ts.map +1 -1
  91. package/dist/types/decorators/applyAttribute.d.ts +61 -20
  92. package/dist/types/decorators/applyAttribute.d.ts.map +1 -1
  93. package/dist/types/decorators/applyClass.d.ts +22 -36
  94. package/dist/types/decorators/applyClass.d.ts.map +1 -1
  95. package/dist/types/decorators/applyNode.d.ts +178 -30
  96. package/dist/types/decorators/applyNode.d.ts.map +1 -1
  97. package/dist/types/decorators/applyProperty.d.ts +53 -18
  98. package/dist/types/decorators/applyProperty.d.ts.map +1 -1
  99. package/dist/types/decorators/applySlot.d.ts +6 -0
  100. package/dist/types/decorators/applySlot.d.ts.map +1 -1
  101. package/dist/types/decorators/applyStyle.d.ts +13 -7
  102. package/dist/types/decorators/applyStyle.d.ts.map +1 -1
  103. package/dist/types/decorators/{changedAttributeThis.d.ts → changedAttribute.d.ts} +2 -2
  104. package/dist/types/decorators/changedAttribute.d.ts.map +1 -0
  105. package/dist/types/decorators/elementDefine.d.ts.map +1 -1
  106. package/dist/types/decorators/emitCustomEvent.d.ts +20 -10
  107. package/dist/types/decorators/emitCustomEvent.d.ts.map +1 -1
  108. package/dist/types/decorators/index.d.ts +1 -1
  109. package/dist/types/decorators/index.d.ts.map +1 -1
  110. package/dist/types/decorators/publishSwcAppMessage.d.ts +19 -0
  111. package/dist/types/decorators/publishSwcAppMessage.d.ts.map +1 -1
  112. package/dist/types/decorators/query.d.ts +3 -26
  113. package/dist/types/decorators/query.d.ts.map +1 -1
  114. package/dist/types/decorators/queryAll.d.ts +3 -20
  115. package/dist/types/decorators/queryAll.d.ts.map +1 -1
  116. package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts +1 -0
  117. package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts.map +1 -1
  118. package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts +2 -0
  119. package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts.map +1 -1
  120. package/dist/types/elements/SwcAppMixin.d.ts +4 -4
  121. package/dist/types/elements/SwcAppMixin.d.ts.map +1 -1
  122. package/dist/types/examples/RxJSOperatorsExample.d.ts +94 -0
  123. package/dist/types/examples/RxJSOperatorsExample.d.ts.map +1 -0
  124. package/dist/types/index.d.ts +1 -0
  125. package/dist/types/index.d.ts.map +1 -1
  126. package/dist/types/router/ElementRouter.d.ts.map +1 -1
  127. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +900 -578
  128. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
  129. package/package.json +7 -9
  130. package/src/SwcAppEngine.ts +3 -1
  131. package/src/decorators/addEventListener.ts +35 -24
  132. package/src/decorators/applyAttribute.ts +167 -65
  133. package/src/decorators/applyClass.ts +113 -17
  134. package/src/decorators/applyNode.ts +383 -102
  135. package/src/decorators/applyProperty.ts +99 -65
  136. package/src/decorators/applySlot.ts +24 -10
  137. package/src/decorators/applyStyle.ts +83 -13
  138. package/src/decorators/{changedAttributeThis.ts → changedAttribute.ts} +1 -1
  139. package/src/decorators/elementDefine.ts +47 -4
  140. package/src/decorators/emitCustomEvent.ts +62 -35
  141. package/src/decorators/index.ts +1 -1
  142. package/src/decorators/publishSwcAppMessage.ts +71 -27
  143. package/src/decorators/query.ts +90 -159
  144. package/src/decorators/queryAll.ts +92 -134
  145. package/src/decorators/subscribeSwcAppMessageWhileConnected.ts +1 -0
  146. package/src/decorators/subscribeSwcAppRouteChangeWhileConnected.ts +3 -1
  147. package/src/elements/SwcAppMixin.ts +43 -24
  148. package/src/examples/RxJSOperatorsExample.ts +279 -0
  149. package/src/index.ts +2 -0
  150. package/src/router/ElementRouter.ts +4 -0
  151. package/dist/cjs/decorators/changedAttributeThis.js.map +0 -7
  152. package/dist/esm/decorators/changedAttributeThis.js.map +0 -7
  153. package/dist/types/decorators/changedAttributeThis.d.ts.map +0 -1
@@ -6,6 +6,32 @@ import { SwcQueryOptions, HelperHostSet } from '../types';
6
6
  export interface PropertyOptions extends SwcQueryOptions {
7
7
  name?: string | symbol;
8
8
  filter?: (target: HTMLElement, value: any, meta: {currentThis: any, helper: HelperHostSet}) => boolean;
9
+ /**
10
+ * Custom key to extract value from return object.
11
+ * If not provided, uses PROPERTY_METADATA_KEY by default.
12
+ * Useful when multiple @setProperty decorators are on the same method.
13
+ *
14
+ * Example:
15
+ * @setProperty('selector1', { valueKey: 'prop1' })
16
+ * @setProperty('selector2', { valueKey: 'prop2' })
17
+ * myMethod() {
18
+ * return {
19
+ * prop1: 'value1',
20
+ * prop2: 'value2'
21
+ * };
22
+ * }
23
+ *
24
+ * Or with symbols:
25
+ * @setProperty('selector1', { valueKey: Symbol.for('prop1') })
26
+ * @setProperty('selector2', { valueKey: Symbol.for('prop2') })
27
+ * myMethod() {
28
+ * return {
29
+ * [Symbol.for('prop1')]: 'value1',
30
+ * [Symbol.for('prop2')]: 'value2'
31
+ * };
32
+ * }
33
+ */
34
+ valueKey?: symbol | string;
9
35
  }
10
36
 
11
37
  export interface PropertyMetadata {
@@ -159,10 +185,39 @@ export function applyProperty(selector: string, targetPropertyKeyOrOptions?: str
159
185
  ensureInit(this);
160
186
  const res = (original as any).apply(this, args);
161
187
 
188
+ /**
189
+ * Extract value for this decorator from method return value
190
+ *
191
+ * If return value is an object with this decorator's symbol key,
192
+ * use that value. Otherwise use the entire return value.
193
+ *
194
+ * Example:
195
+ * @setProperty('selector')
196
+ * myMethod() {
197
+ * return {
198
+ * [PROPERTY_METADATA_KEY]: 'property-value',
199
+ * [OTHER_DECORATOR_KEY]: 'other-value'
200
+ * };
201
+ * }
202
+ *
203
+ * This decorator will use 'property-value'
204
+ */
205
+ const extractValue = (v: any) => {
206
+ if (v && typeof v === 'object' && PROPERTY_METADATA_KEY in v) {
207
+ return v[PROPERTY_METADATA_KEY];
208
+ }
209
+ return v;
210
+ };
211
+
162
212
  if (res instanceof Promise) {
163
- return res.then((v: any) => { applyValueToTargets(this, v); return v; });
213
+ return res.then((v: any) => {
214
+ const extracted = extractValue(v);
215
+ applyValueToTargets(this, extracted);
216
+ return v;
217
+ });
164
218
  } else {
165
- applyValueToTargets(this, res);
219
+ const extracted = extractValue(res);
220
+ applyValueToTargets(this, extracted);
166
221
  return res;
167
222
  }
168
223
  };
@@ -205,81 +260,60 @@ export function applyProperty(selector: string, targetPropertyKeyOrOptions?: str
205
260
  // ============================================
206
261
 
207
262
  /**
208
- * @property - Alias for @applyProperty
209
- */
210
- export function property(selector: string, targetPropertyKey: string | symbol, options?: PropertyOptions): MethodDecorator & PropertyDecorator;
211
- export function property(selector: string, options?: PropertyOptions): MethodDecorator & PropertyDecorator;
212
- export function property(selector: string, targetPropertyKeyOrOptions?: string | symbol | PropertyOptions, options?: PropertyOptions): MethodDecorator & PropertyDecorator {
213
- return applyProperty(selector, targetPropertyKeyOrOptions as any, options);
214
- }
215
-
216
- /**
217
- * @propertyThis - Apply property on $this element
218
- * Can be used as: @propertyThis or @propertyThis('propertyName') or @propertyThis({ name: 'propertyName' })
263
+ * @property - Field decorator for binding element properties (read/write)
264
+ *
265
+ * Usage:
266
+ * - @property('selector', 'propertyName') - Bind to specific property
267
+ * - @property('selector') - Use field name as property name
268
+ * - @property('selector', options) - Bind with options
269
+ * - @property - Bare decorator (binds to $this with field name)
270
+ *
271
+ * Note: This decorator is for FIELDS ONLY. For methods, use @setProperty.
219
272
  */
220
- export function propertyThis(target: Object, propertyKey: string | symbol): void;
221
- export function propertyThis(targetPropertyKey: string | symbol, options?: PropertyOptions): MethodDecorator & PropertyDecorator;
222
- export function propertyThis(options?: PropertyOptions): MethodDecorator & PropertyDecorator;
223
- export function propertyThis(targetOrOptions?: any, propertyKeyOrOptions?: any, descriptor?: PropertyDescriptor): any {
224
- // Direct decorator usage: @propertyThis
225
- if (typeof targetOrOptions === 'object' && targetOrOptions !== null && !Array.isArray(targetOrOptions) &&
226
- (typeof propertyKeyOrOptions === 'string' || typeof propertyKeyOrOptions === 'symbol')) {
227
- // Called as @propertyThis (target, propertyKey)
228
- return applyProperty('$this', undefined as any, {})(targetOrOptions, propertyKeyOrOptions, descriptor);
273
+ export function property(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
274
+ export function property(selector: string, targetPropertyKey: string | symbol, options?: PropertyOptions): PropertyDecorator;
275
+ export function property(selector: string, options?: PropertyOptions): PropertyDecorator;
276
+ export function property(selectorOrTarget?: string | Object, targetPropertyKeyOrOptions?: any, optionsOrDescriptor?: any): any {
277
+ // Bare decorator: @property
278
+ if (optionsOrDescriptor !== undefined && (typeof targetPropertyKeyOrOptions === 'string' || typeof targetPropertyKeyOrOptions === 'symbol')) {
279
+ return applyProperty('$this', undefined as any, {})(selectorOrTarget as Object, targetPropertyKeyOrOptions, optionsOrDescriptor as PropertyDescriptor);
229
280
  }
230
-
231
- // Called with parameters
232
- if (typeof targetOrOptions === 'string' || typeof targetOrOptions === 'symbol') {
233
- // @propertyThis('propertyName', options?)
234
- return applyProperty('$this', targetOrOptions, propertyKeyOrOptions);
235
- } else if (targetOrOptions && typeof targetOrOptions === 'object') {
236
- // @propertyThis({ name: 'propertyName' })
237
- return applyProperty('$this', undefined as any, targetOrOptions);
238
- } else {
239
- // @propertyThis() or @propertyThis
240
- return applyProperty('$this', undefined as any, {});
281
+ // With selector
282
+ if (typeof selectorOrTarget === 'string') {
283
+ return applyProperty(selectorOrTarget, targetPropertyKeyOrOptions as any, optionsOrDescriptor as PropertyOptions);
241
284
  }
285
+ // Without selector (defaults to $this)
286
+ return applyProperty('$this', undefined as any, selectorOrTarget as PropertyOptions);
242
287
  }
243
288
 
244
289
  /**
245
- * @setProperty - Alias for @applyProperty (method-decorator semantics)
290
+ * @setProperty - Method decorator for setting element properties from method return value
291
+ *
292
+ * Usage:
293
+ * - @setProperty('selector', 'propertyName') - Set specific property
294
+ * - @setProperty('selector') - Use method name as property name
295
+ * - @setProperty('selector', options) - Set with options
296
+ * - @setProperty - Bare decorator (sets on $this with method name)
297
+ *
298
+ * Note: This decorator is for METHODS ONLY. For fields, use @property.
299
+ *
300
+ * Example:
301
+ * @setProperty('selector', 'disabled')
302
+ * disableElement() {
303
+ * return true;
304
+ * }
246
305
  */
247
306
  export function setProperty(selector: string, targetPropertyKey: string | symbol, options?: PropertyOptions): MethodDecorator;
248
307
  export function setProperty(selector: string, options?: PropertyOptions): MethodDecorator;
249
- export function setProperty(selector: string, targetPropertyKeyOrOptions?: string | symbol | PropertyOptions, options?: PropertyOptions): MethodDecorator {
250
- return applyProperty(selector, targetPropertyKeyOrOptions as any, options) as MethodDecorator;
251
- }
252
-
253
- /**
254
- * @setPropertyThis - Set property on $this element
255
- * Can be used as: @setPropertyThis or @setPropertyThis('propertyName') or @setPropertyThis({ name: 'propertyName' })
256
- */
257
- export function setPropertyThis(target: Object, propertyKey: string | symbol): void;
258
- export function setPropertyThis(targetPropertyKey: string | symbol, options?: PropertyOptions): MethodDecorator;
259
- export function setPropertyThis(options?: PropertyOptions): MethodDecorator;
260
- export function setPropertyThis(targetOrOptions?: any, propertyKeyOrOptions?: any, descriptor?: PropertyDescriptor): any {
261
- // Direct decorator usage: @setPropertyThis
262
- if (typeof targetOrOptions === 'object' && targetOrOptions !== null && !Array.isArray(targetOrOptions) &&
263
- (typeof propertyKeyOrOptions === 'string' || typeof propertyKeyOrOptions === 'symbol')) {
264
- // Called as @setPropertyThis (target, propertyKey)
265
- return applyProperty('$this', undefined as any, {})(targetOrOptions, propertyKeyOrOptions, descriptor);
266
- }
267
-
268
- // Called with parameters
269
- if (typeof targetOrOptions === 'string' || typeof targetOrOptions === 'symbol') {
270
- // @setPropertyThis('propertyName', options?)
271
- return applyProperty('$this', targetOrOptions, propertyKeyOrOptions) as MethodDecorator;
272
- } else if (targetOrOptions && typeof targetOrOptions === 'object') {
273
- // @setPropertyThis({ name: 'propertyName' })
274
- return applyProperty('$this', undefined as any, targetOrOptions) as MethodDecorator;
275
- } else {
276
- // @setPropertyThis() or @setPropertyThis
277
- return applyProperty('$this', undefined as any, {}) as MethodDecorator;
308
+ export function setProperty(selectorOrOptions?: string | PropertyOptions, targetPropertyKeyOrOptions?: any, optionsOrUndefined?: PropertyOptions): MethodDecorator {
309
+ // With selector
310
+ if (typeof selectorOrOptions === 'string') {
311
+ return applyProperty(selectorOrOptions, targetPropertyKeyOrOptions as any, optionsOrUndefined as PropertyOptions) as MethodDecorator;
278
312
  }
313
+ // Without selector (defaults to $this)
314
+ return applyProperty('$this', undefined as any, selectorOrOptions as PropertyOptions) as MethodDecorator;
279
315
  }
280
316
 
281
-
282
-
283
317
  // ============================================
284
318
  // Metadata Helpers
285
319
  // ============================================
@@ -17,16 +17,12 @@ export type ApplySlotPosition = 'prepend' | 'prependHtml' | 'prependText' | 'app
17
17
  export interface ApplySlotOptions {
18
18
  position: ApplySlotPosition;
19
19
  fallback?: (helper: HelperHostSet) => string | Node;
20
- // root?: SwcRootType;
21
20
  /**
22
- * Filter function to determine whether to perform DOM operation.
23
- * If it returns false, the operation is skipped.
21
+ * Custom key to extract value from return object.
22
+ * If not provided, uses APPLY_SLOT_METADATA_KEY by default.
23
+ * Useful when multiple @applySlot decorators are on the same method.
24
24
  */
25
- // filter?: (target: HTMLElement | ShadowRoot, newValue: any, meta:{currentThis: any,helper: HelperHostSet}) => boolean;
26
- /**
27
- * Optional loading content to display while an async method is executing.
28
- */
29
- // loading?: (helper: HelperHostSet) => any;
25
+ valueKey?: symbol | string;
30
26
  }
31
27
 
32
28
  export interface ApplySlotMetadata {
@@ -144,15 +140,33 @@ export function applySlot(targetId: string, opt: OptionalType<ApplySlotOptions,
144
140
  applyToDom(swcId, targetId, options.position, nodes);
145
141
  }
146
142
 
143
+ /**
144
+ * Extract value for this decorator from method return value
145
+ *
146
+ * If return value is an object with this decorator's key,
147
+ * use that value. Otherwise use the entire return value.
148
+ *
149
+ * Uses valueKey from options if provided, otherwise uses APPLY_SLOT_METADATA_KEY.
150
+ */
151
+ const extractValue = (v: any) => {
152
+ const keyToUse = options.valueKey ?? APPLY_SLOT_METADATA_KEY;
153
+ if (v && typeof v === 'object' && keyToUse in v) {
154
+ return v[keyToUse];
155
+ }
156
+ return v;
157
+ };
158
+
147
159
  let res = original.apply(this, args);
148
160
  if (res instanceof Promise) {
149
161
  return res.then(asyncRes => {
150
- const nodes = resToNodes(asyncRes)
162
+ const extracted = extractValue(asyncRes);
163
+ const nodes = resToNodes(extracted)
151
164
  fallbackNodes.forEach((it: any) => it.remove());
152
165
  applyToDom(swcId, targetId, options.position, nodes);
153
166
  })
154
167
  } else {
155
- const nodes: Node[] = resToNodes(res);
168
+ const extracted = extractValue(res);
169
+ const nodes: Node[] = resToNodes(extracted);
156
170
  applyToDom(swcId, targetId, options.position, nodes);
157
171
  }
158
172
  };
@@ -7,6 +7,12 @@ export type StyleAction = 'set' | 'update' | 'remove';
7
7
 
8
8
  export interface StyleApplyOptions extends SwcQueryOptions {
9
9
  filter?: (target: HTMLElement, value: any, meta: {currentThis: any, helper: HelperHostSet}) => boolean;
10
+ /**
11
+ * Custom key to extract value from return object.
12
+ * If not provided, uses STYLE_METADATA_KEY by default.
13
+ * Useful when multiple @applyStyle decorators are on the same method.
14
+ */
15
+ valueKey?: symbol | string;
10
16
  }
11
17
 
12
18
  export interface StyleApplyMetadata {
@@ -34,6 +40,22 @@ function createStyleDecorator(action: StyleAction) {
34
40
  ensureInit(this);
35
41
  const res = (original as any).apply(this, args);
36
42
 
43
+ /**
44
+ * Extract value for this decorator from method return value
45
+ *
46
+ * If return value is an object with this decorator's key,
47
+ * use that value. Otherwise use the entire return value.
48
+ *
49
+ * Uses valueKey from options if provided, otherwise uses STYLE_METADATA_KEY.
50
+ */
51
+ const extractValue = (v: any) => {
52
+ const keyToUse = options.valueKey ?? STYLE_METADATA_KEY;
53
+ if (v && typeof v === 'object' && keyToUse in v) {
54
+ return v[keyToUse];
55
+ }
56
+ return v;
57
+ };
58
+
37
59
  const handleResult = (resolvedValue: any) => {
38
60
  if (resolvedValue !== undefined) {
39
61
  const win = (this as any).ownerDocument?.defaultView || window;
@@ -105,9 +127,9 @@ function createStyleDecorator(action: StyleAction) {
105
127
  };
106
128
 
107
129
  if (res instanceof Promise) {
108
- return res.then(handleResult);
130
+ return res.then((v: any) => handleResult(extractValue(v)));
109
131
  } else {
110
- return handleResult(res);
132
+ return handleResult(extractValue(res));
111
133
  }
112
134
  };
113
135
  return descriptor;
@@ -115,21 +137,69 @@ function createStyleDecorator(action: StyleAction) {
115
137
  };
116
138
  }
117
139
 
118
- export function applyStyle(selector: string, action: StyleAction = 'update', options: StyleApplyOptions = {}): MethodDecorator {
119
- return createStyleDecorator(action)(selector, options);
140
+ export function applyStyle(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
141
+ export function applyStyle(selector: string, action?: StyleAction, options?: StyleApplyOptions): MethodDecorator;
142
+ export function applyStyle(selectorOrTarget?: any, actionOrPropertyKey?: any, optionsOrDescriptor?: any): any {
143
+ // Bare decorator: @applyStyle
144
+ if (optionsOrDescriptor !== undefined && (typeof actionOrPropertyKey === 'string' || typeof actionOrPropertyKey === 'symbol')) {
145
+ return createStyleDecorator('update')('$this', {})(selectorOrTarget as Object, actionOrPropertyKey, optionsOrDescriptor as PropertyDescriptor);
146
+ }
147
+ // With selector
148
+ if (typeof selectorOrTarget === 'string') {
149
+ const action = (typeof actionOrPropertyKey === 'string' ? actionOrPropertyKey : 'update') as StyleAction;
150
+ const options = (typeof actionOrPropertyKey === 'object' ? actionOrPropertyKey : optionsOrDescriptor) as StyleApplyOptions | undefined;
151
+ return createStyleDecorator(action)(selectorOrTarget, options);
152
+ }
153
+ // Without selector (defaults to $this)
154
+ const action = (typeof selectorOrTarget === 'string' ? selectorOrTarget : 'update') as StyleAction;
155
+ const options = (typeof selectorOrTarget === 'object' ? selectorOrTarget : actionOrPropertyKey) as StyleApplyOptions | undefined;
156
+ return createStyleDecorator(action)('$this', options);
157
+ }
158
+
159
+ export function setStyle(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
160
+ export function setStyle(selector: string, options?: StyleApplyOptions): MethodDecorator;
161
+ export function setStyle(selectorOrTarget?: any, optionsOrPropertyKey?: any, descriptor?: any): any {
162
+ // Bare decorator: @setStyle
163
+ if (descriptor !== undefined && (typeof optionsOrPropertyKey === 'string' || typeof optionsOrPropertyKey === 'symbol')) {
164
+ return createStyleDecorator('set')('$this', {})(selectorOrTarget as Object, optionsOrPropertyKey, descriptor as PropertyDescriptor);
165
+ }
166
+ // With selector
167
+ if (typeof selectorOrTarget === 'string') {
168
+ return createStyleDecorator('set')(selectorOrTarget, optionsOrPropertyKey as StyleApplyOptions);
169
+ }
170
+ // Without selector (defaults to $this)
171
+ return createStyleDecorator('set')('$this', selectorOrTarget as StyleApplyOptions);
120
172
  }
121
173
 
122
- export const setStyle = (selector: string, options: StyleApplyOptions = {}) => createStyleDecorator('set')(selector, options);
123
- export const updateStyle = (selector: string, options: StyleApplyOptions = {}) => createStyleDecorator('update')(selector, options);
124
- export const removeStyle = (selector: string, options: StyleApplyOptions = {}) => createStyleDecorator('remove')(selector, options);
174
+ export function updateStyle(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
175
+ export function updateStyle(selector: string, options?: StyleApplyOptions): MethodDecorator;
176
+ export function updateStyle(selectorOrTarget?: any, optionsOrPropertyKey?: any, descriptor?: any): any {
177
+ // Bare decorator: @updateStyle
178
+ if (descriptor !== undefined && (typeof optionsOrPropertyKey === 'string' || typeof optionsOrPropertyKey === 'symbol')) {
179
+ return createStyleDecorator('update')('$this', {})(selectorOrTarget as Object, optionsOrPropertyKey, descriptor as PropertyDescriptor);
180
+ }
181
+ // With selector
182
+ if (typeof selectorOrTarget === 'string') {
183
+ return createStyleDecorator('update')(selectorOrTarget, optionsOrPropertyKey as StyleApplyOptions);
184
+ }
185
+ // Without selector (defaults to $this)
186
+ return createStyleDecorator('update')('$this', selectorOrTarget as StyleApplyOptions);
187
+ }
125
188
 
126
- // This versions
127
- export function applyStyleThis(action: StyleAction = 'update', options: StyleApplyOptions = {}): MethodDecorator {
128
- return createStyleDecorator(action)('$this', options);
189
+ export function removeStyle(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
190
+ export function removeStyle(selector: string, options?: StyleApplyOptions): MethodDecorator;
191
+ export function removeStyle(selectorOrTarget?: any, optionsOrPropertyKey?: any, descriptor?: any): any {
192
+ // Bare decorator: @removeStyle
193
+ if (descriptor !== undefined && (typeof optionsOrPropertyKey === 'string' || typeof optionsOrPropertyKey === 'symbol')) {
194
+ return createStyleDecorator('remove')('$this', {})(selectorOrTarget as Object, optionsOrPropertyKey, descriptor as PropertyDescriptor);
195
+ }
196
+ // With selector
197
+ if (typeof selectorOrTarget === 'string') {
198
+ return createStyleDecorator('remove')(selectorOrTarget, optionsOrPropertyKey as StyleApplyOptions);
199
+ }
200
+ // Without selector (defaults to $this)
201
+ return createStyleDecorator('remove')('$this', selectorOrTarget as StyleApplyOptions);
129
202
  }
130
- export const setStyleThis = (options: StyleApplyOptions = {}) => createStyleDecorator('set')('$this', options);
131
- export const updateStyleThis = (options: StyleApplyOptions = {}) => createStyleDecorator('update')('$this', options);
132
- export const removeStyleThis = (options: StyleApplyOptions = {}) => createStyleDecorator('remove')('$this', options);
133
203
 
134
204
  export const findAllStyleMetadata = (target: any): Map<string | symbol, StyleApplyMetadata> => {
135
205
  const result = new Map<string | symbol, StyleApplyMetadata>();
@@ -23,7 +23,7 @@ const convertValue = (val: any, type: any): any => {
23
23
  /**
24
24
  * @changedAttributeThis decorator - fires when any attribute on $this changes
25
25
  */
26
- export function changedAttributeThis(attributeName?: string, options: ChangedAttributeThisOptions = {}): MethodDecorator {
26
+ export function changedAttribute(attributeName?: string, options: ChangedAttributeThisOptions = {}): MethodDecorator {
27
27
  return (target: Object, propertyKey: string | symbol) => {
28
28
  const constructor = target.constructor;
29
29
  let metaList = ReflectUtils.getOwnMetadata(ON_ATTRIBUTE_CHANGED_METADATA_KEY, constructor) as ChangedAttributeThisMetadata[];
@@ -1,8 +1,10 @@
1
1
  import {ActionExpression, FunctionUtils, ReflectUtils} from '@dooboostore/core';
2
+ import {Observable, Subject} from '@dooboostore/core';
3
+ import {debounceTime, throttleTime, distinctUntilChanged} from '@dooboostore/core/message/operators';
2
4
  import {getAddEventListenerMetadata} from './addEventListener';
3
5
  import {findAllLifecycleMetadata, findAllOnConnectedAfterMetadata, findAllOnConnectedBeforeMetadata, findAllOnConnectedMetadata, ON_AFTER_ADOPTED_METADATA_KEY, ON_AFTER_DISCONNECTED_METADATA_KEY, ON_BEFORE_ADOPTED_METADATA_KEY, ON_BEFORE_DISCONNECTED_METADATA_KEY, ON_CONNECTED_COMPLETED_METADATA_KEY, ON_INITIALIZE_METADATA_KEY} from './lifecycles';
4
6
  import {getEmitCustomEventMetadataList} from './emitCustomEvent';
5
- import {convertAttributeValue, findAllAttributeChangedMetadata} from './changedAttributeThis';
7
+ import {convertAttributeValue, findAllAttributeChangedMetadata} from './changedAttribute';
6
8
  import {findAllAttributeApplyMetadata, findAllAttributeMetadata, getAttributeValue} from './applyAttribute';
7
9
  import {getQueryMetadata} from './query';
8
10
  import {getQueryAllMetadata} from './queryAll';
@@ -588,8 +590,43 @@ export const elementDefine =
588
590
  const args = {event, ...currentHostSet, $el: t, $root: t};
589
591
  await (this as any)[meta.propertyKey](event, {currentHostSet, $$matchedElement: event.currentTarget}, args);
590
592
  };
591
- t.addEventListener(type, handler, opts);
592
- (this as any)._boundListeners.push({target: t, type, handler, options: opts});
593
+
594
+ // Create event stream with Observable-based operators
595
+ const eventSubject = new Subject<Event>();
596
+ let eventStream = eventSubject as any;
597
+
598
+ // Apply operators from @dooboostore/core/operators
599
+ if (options.debounceTime !== undefined && options.debounceTime > 0) {
600
+ eventStream = eventStream.pipe(debounceTime(options.debounceTime));
601
+ }
602
+
603
+ if (options.throttleTime !== undefined && options.throttleTime > 0) {
604
+ eventStream = eventStream.pipe(throttleTime(options.throttleTime));
605
+ }
606
+
607
+ if (options.distinctUntilChanged !== undefined && options.distinctUntilChanged !== false) {
608
+ if (typeof options.distinctUntilChanged === 'function') {
609
+ eventStream = eventStream.pipe(distinctUntilChanged(options.distinctUntilChanged));
610
+ } else {
611
+ eventStream = eventStream.pipe(distinctUntilChanged());
612
+ }
613
+ }
614
+
615
+ // Subscribe to the event stream
616
+ const subscription = eventStream.subscribe({
617
+ next: (event: Event) => {
618
+ handler(event).catch((err: any) => console.error('Event handler error:', err));
619
+ },
620
+ error: (err: any) => console.error('Event stream error:', err)
621
+ });
622
+
623
+ // Create wrapper handler that emits to the subject
624
+ const wrappedHandler = (event: Event) => {
625
+ eventSubject.next(event);
626
+ };
627
+
628
+ t.addEventListener(type, wrappedHandler, opts);
629
+ (this as any)._boundListeners.push({target: t, type, handler: wrappedHandler, options: opts, subscription});
593
630
  });
594
631
  });
595
632
 
@@ -640,7 +677,13 @@ export const elementDefine =
640
677
  for (const m of bMethods) (this as any)._invokeLifecycleMethod(m.propertyKey, helperHostSet);
641
678
 
642
679
  if ((this as any)._boundListeners) {
643
- (this as any)._boundListeners.forEach((l: any) => l.target.removeEventListener(l.type, l.handler, l.options));
680
+ (this as any)._boundListeners.forEach((l: any) => {
681
+ l.target.removeEventListener(l.type, l.handler, l.options);
682
+ // Cleanup Observable subscription if present
683
+ if (l.subscription && typeof l.subscription.unsubscribe === 'function') {
684
+ l.subscription.unsubscribe();
685
+ }
686
+ });
644
687
  (this as any)._boundListeners = [];
645
688
  }
646
689
 
@@ -8,6 +8,22 @@ export interface EmitCustomEventBaseOptions {
8
8
  composed?: boolean;
9
9
  cancelable?: boolean;
10
10
  filter?: (target: EventTarget, detail: any, meta: { currentThis: any, helper: HelperHostSet }) => boolean;
11
+ /**
12
+ * Custom key to extract value from return object.
13
+ * If not provided, uses EMIT_CUSTOM_EVENT_METADATA_KEY by default.
14
+ * Useful when multiple @emitCustomEvent decorators are on the same method.
15
+ *
16
+ * Example:
17
+ * @emitCustomEvent('$appHost', 'event1', { valueKey: 'detail1' })
18
+ * @emitCustomEvent('$appHost', 'event2', { valueKey: 'detail2' })
19
+ * myMethod() {
20
+ * return {
21
+ * detail1: { type: 'event1', data: 'value1' },
22
+ * detail2: { type: 'event2', data: 'value2' }
23
+ * };
24
+ * }
25
+ */
26
+ valueKey?: symbol | string;
11
27
  }
12
28
 
13
29
  type Options = (EmitCustomEventBaseOptions & SwcQueryOptions) | (EmitCustomEventBaseOptions & SwcQueryOptions & { attributeName?: string });
@@ -21,16 +37,43 @@ export interface EmitCustomEventMetadata {
21
37
 
22
38
  export const EMIT_CUSTOM_EVENT_METADATA_KEY = Symbol.for('simple-web-component:emit-custom-event');
23
39
 
24
- export function emitCustomEvent(target: SpecialSelector, type: string, options?: Options): MethodDecorator;
40
+ export function emitCustomEvent(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
25
41
  export function emitCustomEvent(selector: string, type: string, options?: Options): MethodDecorator;
42
+ export function emitCustomEvent(type: string, options?: Options): MethodDecorator;
26
43
  /**
27
44
  * @emitCustomEvent decorator to dispatch custom events to a target.
45
+ *
46
+ * Usage:
47
+ * - @emitCustomEvent('$this', 'event-name', options) - Emit from $this
48
+ * - @emitCustomEvent('$appHost', 'event-name', options) - Emit from $appHost
49
+ * - @emitCustomEvent('event-name', options) - Emit from $this (defaults to $this)
50
+ * - @emitCustomEvent('event-name') - Emit from $this with no options
28
51
  */
29
- export function emitCustomEvent(selectorOrTarget: string, type: string, options: any = {}): MethodDecorator {
52
+ export function emitCustomEvent(selectorOrTarget: any, typeOrPropertyKey?: any, optionsOrDescriptor?: any): any {
53
+ // Case 1: Bare decorator on property
54
+ if (typeof selectorOrTarget === 'object' && typeof typeOrPropertyKey === 'string' && typeof optionsOrDescriptor === 'object' && 'value' in optionsOrDescriptor) {
55
+ throw new Error(`@emitCustomEvent decorator cannot be used on properties. (Property: ${String(typeOrPropertyKey)})`);
56
+ }
57
+
58
+ // Case 2: With selector and type - @emitCustomEvent('selector', 'event-name', options)
59
+ if (typeof selectorOrTarget === 'string' && typeof typeOrPropertyKey === 'string') {
60
+ return createEmitDecorator(selectorOrTarget, typeOrPropertyKey, optionsOrDescriptor as Options);
61
+ }
62
+
63
+ // Case 3: Without selector (type only) - @emitCustomEvent('event-name', options)
64
+ if (typeof selectorOrTarget === 'string' && typeOrPropertyKey !== 'string') {
65
+ return createEmitDecorator('$this', selectorOrTarget, typeOrPropertyKey as Options);
66
+ }
67
+
68
+ // Fallback
69
+ throw new Error('Invalid @emitCustomEvent usage');
70
+ }
71
+
72
+ function createEmitDecorator(selector: string, type: string, options?: Options) {
30
73
  return (targetObj: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
31
74
  const constructor = targetObj.constructor;
32
75
 
33
- const fullOptions: any = {...options, type};
76
+ const fullOptions: any = {...(options || {}), type};
34
77
 
35
78
  if (fullOptions.bubbles === undefined) fullOptions.bubbles = true;
36
79
  if (fullOptions.composed === undefined) fullOptions.composed = true;
@@ -40,7 +83,7 @@ export function emitCustomEvent(selectorOrTarget: string, type: string, options:
40
83
  list = [];
41
84
  ReflectUtils.defineMetadata(EMIT_CUSTOM_EVENT_METADATA_KEY, list, constructor);
42
85
  }
43
- list.push({propertyKey, selector: selectorOrTarget, type, options: fullOptions});
86
+ list.push({propertyKey, selector, type, options: fullOptions});
44
87
 
45
88
  const original = descriptor.value;
46
89
  descriptor.value = function (...args: any[]) {
@@ -60,27 +103,27 @@ export function emitCustomEvent(selectorOrTarget: string, type: string, options:
60
103
  const currentWin = (this as any)._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as Window);
61
104
 
62
105
  const eventTargets: EventTarget[] = [];
63
- if (selectorOrTarget === '$window') eventTargets.push(currentWin);
64
- else if (selectorOrTarget === '$document') eventTargets.push(currentWin.document);
65
- else if (selectorOrTarget === '$host') {
106
+ if (selector === '$window') eventTargets.push(currentWin);
107
+ else if (selector === '$document') eventTargets.push(currentWin.document);
108
+ else if (selector === '$host') {
66
109
  if (hostSet.$host) eventTargets.push(hostSet.$host);
67
- } else if (selectorOrTarget === '$parentHost') {
110
+ } else if (selector === '$parentHost') {
68
111
  if (hostSet.$parentHost) eventTargets.push(hostSet.$parentHost);
69
- } else if (selectorOrTarget === '$appHost') {
112
+ } else if (selector === '$appHost') {
70
113
  if (hostSet.$appHost) eventTargets.push(hostSet.$appHost);
71
- } else if (selectorOrTarget === '$firstHost') {
114
+ } else if (selector === '$firstHost') {
72
115
  if (hostSet.$firstHost) eventTargets.push(hostSet.$firstHost);
73
- } else if (selectorOrTarget === '$lastHost') {
116
+ } else if (selector === '$lastHost') {
74
117
  if (hostSet.$lastHost) eventTargets.push(hostSet.$lastHost);
75
- } else if (selectorOrTarget === '$firstAppHost') {
118
+ } else if (selector === '$firstAppHost') {
76
119
  if (hostSet.$firstAppHost) eventTargets.push(hostSet.$firstAppHost);
77
- } else if (selectorOrTarget === '$lastAppHost') {
120
+ } else if (selector === '$lastAppHost') {
78
121
  if (hostSet.$lastAppHost) eventTargets.push(hostSet.$lastAppHost);
79
- } else if (selectorOrTarget === '$hosts') {
122
+ } else if (selector === '$hosts') {
80
123
  hostSet.$hosts.forEach(h => eventTargets.push(h));
81
- } else if (selectorOrTarget === '$appHosts') {
124
+ } else if (selector === '$appHosts') {
82
125
  hostSet.$appHosts.forEach(h => eventTargets.push(h));
83
- } else if (selectorOrTarget === '$this' || !selectorOrTarget) {
126
+ } else if (selector === '$this' || !selector) {
84
127
  eventTargets.push(this as any);
85
128
  } else {
86
129
  const r = fullOptions.root || 'auto';
@@ -94,7 +137,7 @@ export function emitCustomEvent(selectorOrTarget: string, type: string, options:
94
137
  }
95
138
 
96
139
  searchRoots.forEach(sr => {
97
- sr.querySelectorAll(selectorOrTarget).forEach(el => eventTargets.push(el));
140
+ sr.querySelectorAll(selector).forEach(el => eventTargets.push(el));
98
141
  });
99
142
  }
100
143
 
@@ -122,21 +165,5 @@ export const getEmitCustomEventMetadataList = (target: any): EmitCustomEventMeta
122
165
  return ReflectUtils.getMetadata(EMIT_CUSTOM_EVENT_METADATA_KEY, constructor);
123
166
  };
124
167
 
125
- /**
126
- * @emitCustomEventThis decorator - simplified version of @emitCustomEvent for $this selector
127
- */
128
- export function emitCustomEventThis(type: string, options: EmitCustomEventBaseOptions & SwcQueryOptions & { attributeName?: string }): MethodDecorator ;
129
- export function emitCustomEventThis(type: string, attributeName: string): MethodDecorator ;
130
- export function emitCustomEventThis(type: string): MethodDecorator;
131
- export function emitCustomEventThis(type: string, optionsOrAttributeaName?: string | (EmitCustomEventBaseOptions & SwcQueryOptions & { attributeName?: string })): MethodDecorator {
132
- if (optionsOrAttributeaName && typeof optionsOrAttributeaName === 'string') {
133
- return emitCustomEventThis(type, {attributeName: optionsOrAttributeaName});
134
- } else if (optionsOrAttributeaName && typeof optionsOrAttributeaName === 'object') {
135
- if (!optionsOrAttributeaName.attributeName) {
136
- optionsOrAttributeaName.attributeName = `on-emit-${type}`;
137
- }
138
- return emitCustomEvent('$this', type, optionsOrAttributeaName);
139
- } else {
140
- return emitCustomEvent('$this', type, {attributeName: `on-emit-${type}`});
141
- }
142
- }
168
+ // --- Aliases: emit... ---
169
+ export const emit = emitCustomEvent;
@@ -1,7 +1,7 @@
1
1
  export * from './addEventListener';
2
2
  export * from './applyAttribute';
3
3
  export * from './elementDefine';
4
- export * from './changedAttributeThis';
4
+ export * from './changedAttribute';
5
5
  export * from './emitCustomEvent';
6
6
  export * from './applyNode';
7
7
  export * from './lifecycles';