@dooboostore/simple-web-component 1.0.43 → 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 (144) hide show
  1. package/README.md +298 -49
  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 +30 -28
  6. package/dist/cjs/decorators/applyAttribute.js.map +2 -2
  7. package/dist/cjs/decorators/applyClass.js +57 -21
  8. package/dist/cjs/decorators/applyClass.js.map +3 -3
  9. package/dist/cjs/decorators/applyNode.js +165 -105
  10. package/dist/cjs/decorators/applyNode.js.map +2 -2
  11. package/dist/cjs/decorators/applyProperty.js +11 -28
  12. package/dist/cjs/decorators/applyProperty.js.map +2 -2
  13. package/dist/cjs/decorators/applyStyle.js +39 -15
  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 +37 -6
  18. package/dist/cjs/decorators/elementDefine.js.map +3 -3
  19. package/dist/cjs/decorators/emitCustomEvent.js +56 -42
  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 +96 -145
  26. package/dist/cjs/decorators/query.js.map +3 -3
  27. package/dist/cjs/decorators/queryAll.js +104 -131
  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/esm/SwcAppEngine.js +3 -1
  42. package/dist/esm/SwcAppEngine.js.map +2 -2
  43. package/dist/esm/decorators/addEventListener.js.map +2 -2
  44. package/dist/esm/decorators/applyAttribute.js +30 -28
  45. package/dist/esm/decorators/applyAttribute.js.map +2 -2
  46. package/dist/esm/decorators/applyClass.js +57 -21
  47. package/dist/esm/decorators/applyClass.js.map +3 -3
  48. package/dist/esm/decorators/applyNode.js +165 -105
  49. package/dist/esm/decorators/applyNode.js.map +2 -2
  50. package/dist/esm/decorators/applyProperty.js +11 -28
  51. package/dist/esm/decorators/applyProperty.js.map +2 -2
  52. package/dist/esm/decorators/applyStyle.js +39 -15
  53. package/dist/esm/decorators/applyStyle.js.map +3 -3
  54. package/dist/esm/decorators/{changedAttributeThis.js → changedAttribute.js} +3 -3
  55. package/dist/esm/decorators/changedAttribute.js.map +7 -0
  56. package/dist/esm/decorators/elementDefine.js +35 -4
  57. package/dist/esm/decorators/elementDefine.js.map +2 -2
  58. package/dist/esm/decorators/emitCustomEvent.js +56 -42
  59. package/dist/esm/decorators/emitCustomEvent.js.map +2 -2
  60. package/dist/esm/decorators/index.js +1 -1
  61. package/dist/esm/decorators/index.js.map +1 -1
  62. package/dist/esm/decorators/publishSwcAppMessage.js +5 -5
  63. package/dist/esm/decorators/publishSwcAppMessage.js.map +3 -3
  64. package/dist/esm/decorators/query.js +96 -145
  65. package/dist/esm/decorators/query.js.map +3 -3
  66. package/dist/esm/decorators/queryAll.js +104 -131
  67. package/dist/esm/decorators/queryAll.js.map +3 -3
  68. package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js +2 -0
  69. package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js.map +2 -2
  70. package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js +2 -0
  71. package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +2 -2
  72. package/dist/esm/elements/SwcAppMixin.js +18 -3
  73. package/dist/esm/elements/SwcAppMixin.js.map +2 -2
  74. package/dist/esm/examples/RxJSOperatorsExample.js +266 -0
  75. package/dist/esm/examples/RxJSOperatorsExample.js.map +7 -0
  76. package/dist/esm/index.js +1 -0
  77. package/dist/esm/index.js.map +2 -2
  78. package/dist/esm/router/ElementRouter.js +4 -0
  79. package/dist/esm/router/ElementRouter.js.map +2 -2
  80. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +759 -512
  81. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
  82. package/dist/types/SwcAppEngine.d.ts.map +1 -1
  83. package/dist/types/decorators/addEventListener.d.ts +17 -14
  84. package/dist/types/decorators/addEventListener.d.ts.map +1 -1
  85. package/dist/types/decorators/applyAttribute.d.ts +35 -20
  86. package/dist/types/decorators/applyAttribute.d.ts.map +1 -1
  87. package/dist/types/decorators/applyClass.d.ts +16 -36
  88. package/dist/types/decorators/applyClass.d.ts.map +1 -1
  89. package/dist/types/decorators/applyNode.d.ts +172 -30
  90. package/dist/types/decorators/applyNode.d.ts.map +1 -1
  91. package/dist/types/decorators/applyProperty.d.ts +27 -18
  92. package/dist/types/decorators/applyProperty.d.ts.map +1 -1
  93. package/dist/types/decorators/applyStyle.d.ts +7 -7
  94. package/dist/types/decorators/applyStyle.d.ts.map +1 -1
  95. package/dist/types/decorators/{changedAttributeThis.d.ts → changedAttribute.d.ts} +2 -2
  96. package/dist/types/decorators/changedAttribute.d.ts.map +1 -0
  97. package/dist/types/decorators/elementDefine.d.ts.map +1 -1
  98. package/dist/types/decorators/emitCustomEvent.d.ts +3 -10
  99. package/dist/types/decorators/emitCustomEvent.d.ts.map +1 -1
  100. package/dist/types/decorators/index.d.ts +1 -1
  101. package/dist/types/decorators/index.d.ts.map +1 -1
  102. package/dist/types/decorators/publishSwcAppMessage.d.ts +1 -1
  103. package/dist/types/decorators/publishSwcAppMessage.d.ts.map +1 -1
  104. package/dist/types/decorators/query.d.ts +3 -26
  105. package/dist/types/decorators/query.d.ts.map +1 -1
  106. package/dist/types/decorators/queryAll.d.ts +3 -20
  107. package/dist/types/decorators/queryAll.d.ts.map +1 -1
  108. package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts +1 -0
  109. package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts.map +1 -1
  110. package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts +2 -0
  111. package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts.map +1 -1
  112. package/dist/types/elements/SwcAppMixin.d.ts +4 -4
  113. package/dist/types/elements/SwcAppMixin.d.ts.map +1 -1
  114. package/dist/types/examples/RxJSOperatorsExample.d.ts +94 -0
  115. package/dist/types/examples/RxJSOperatorsExample.d.ts.map +1 -0
  116. package/dist/types/index.d.ts +1 -0
  117. package/dist/types/index.d.ts.map +1 -1
  118. package/dist/types/router/ElementRouter.d.ts.map +1 -1
  119. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +759 -512
  120. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
  121. package/package.json +3 -3
  122. package/src/SwcAppEngine.ts +3 -1
  123. package/src/decorators/addEventListener.ts +28 -24
  124. package/src/decorators/applyAttribute.ts +109 -63
  125. package/src/decorators/applyClass.ts +89 -15
  126. package/src/decorators/applyNode.ts +357 -100
  127. package/src/decorators/applyProperty.ts +42 -63
  128. package/src/decorators/applyStyle.ts +59 -11
  129. package/src/decorators/{changedAttributeThis.ts → changedAttribute.ts} +1 -1
  130. package/src/decorators/elementDefine.ts +47 -4
  131. package/src/decorators/emitCustomEvent.ts +44 -36
  132. package/src/decorators/index.ts +1 -1
  133. package/src/decorators/publishSwcAppMessage.ts +1 -1
  134. package/src/decorators/query.ts +90 -159
  135. package/src/decorators/queryAll.ts +92 -134
  136. package/src/decorators/subscribeSwcAppMessageWhileConnected.ts +1 -0
  137. package/src/decorators/subscribeSwcAppRouteChangeWhileConnected.ts +3 -1
  138. package/src/elements/SwcAppMixin.ts +43 -24
  139. package/src/examples/RxJSOperatorsExample.ts +279 -0
  140. package/src/index.ts +2 -0
  141. package/src/router/ElementRouter.ts +4 -0
  142. package/dist/cjs/decorators/changedAttributeThis.js.map +0 -7
  143. package/dist/esm/decorators/changedAttributeThis.js.map +0 -7
  144. package/dist/types/decorators/changedAttributeThis.d.ts.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dooboostore/simple-web-component",
3
- "version": "1.0.43",
3
+ "version": "1.0.44",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",
@@ -93,9 +93,9 @@
93
93
  "webpack-cli": "^5.1.4",
94
94
  "webpack-dev-server": "^5.2.0",
95
95
  "@dooboostore/core": "1.0.32",
96
- "@dooboostore/core-node": "1.0.12",
97
96
  "@dooboostore/core-web": "1.0.12",
98
- "@dooboostore/simple-boot": "1.0.56"
97
+ "@dooboostore/simple-boot": "1.0.56",
98
+ "@dooboostore/core-node": "1.0.12"
99
99
  },
100
100
  "scripts": {
101
101
  "clean": "rm -rf dist",
@@ -78,7 +78,9 @@ export class SwcAppEngine {
78
78
 
79
79
  if (this._config.onStartedLazyDefineComponent) {
80
80
  // console.log('-------->', this._config.onStartedLazyDefineComponent)
81
- await Promise.all(this._config.onStartedLazyDefineComponent.map(it => it(this._config.window)))
81
+ await Promise.all(this._config.onStartedLazyDefineComponent.map(it => {
82
+ it(this._config.window);
83
+ }))
82
84
  }
83
85
  if (this._config.onEngineStarted) {
84
86
  await this._config.onEngineStarted(this.simpleApplication, this.host as unknown as SwcAppInterface);
@@ -1,7 +1,7 @@
1
1
  import { ReflectUtils } from '@dooboostore/core';
2
2
  import { SpecialSelector, SwcQueryOptions, HelperHostSet } from '../types';
3
3
 
4
- export interface AddEventListenerBaseOptions extends EventListenerOptions {
4
+ export interface AddEventListenerBaseOptions<TEvent extends Event = Event> extends EventListenerOptions {
5
5
  capture?: boolean;
6
6
  once?: boolean;
7
7
  passive?: boolean;
@@ -11,27 +11,31 @@ export interface AddEventListenerBaseOptions extends EventListenerOptions {
11
11
  // removeOnDisconnected?: boolean;
12
12
  delegate?: boolean;
13
13
  filter?: (target: Event | CustomEvent, meta:{currentThis: any, helper: HelperHostSet}) => boolean;
14
+ // RxJS operator options
15
+ debounceTime?: number;
16
+ throttleTime?: number;
17
+ distinctUntilChanged?: boolean | ((prev: TEvent, curr: TEvent) => boolean);
14
18
  }
15
19
 
16
- export interface AddEventListenerMetadata {
20
+ export interface AddEventListenerMetadata<TEvent extends Event = Event> {
17
21
  propertyKey: string | symbol;
18
22
  selector: string;
19
23
  type: string;
20
- options: AddEventListenerBaseOptions & SwcQueryOptions & { delegate?: boolean };
24
+ options: AddEventListenerBaseOptions<TEvent> & SwcQueryOptions & { delegate?: boolean };
21
25
  }
22
26
 
23
27
  export const ADD_EVENT_LISTENER_METADATA_KEY = Symbol.for('simple-web-component:add-event-listener');
24
28
 
25
- export function addEventListener(target: SpecialSelector, type: string, options?: AddEventListenerBaseOptions): MethodDecorator;
26
- export function addEventListener(selector: string, type: string, options?: AddEventListenerBaseOptions & SwcQueryOptions & { delegate?: boolean }): MethodDecorator;
29
+ export function addEventListener<TEvent extends Event = Event>(target: SpecialSelector, type: string, options?: AddEventListenerBaseOptions<TEvent>): MethodDecorator;
30
+ export function addEventListener<TEvent extends Event = Event>(selector: string, type: string, options?: AddEventListenerBaseOptions<TEvent> & SwcQueryOptions & { delegate?: boolean }): MethodDecorator;
27
31
  /**
28
32
  * @addEventListener decorator to bind events to elements.
29
33
  */
30
- export function addEventListener(selectorOrTarget: string, type: string, options: any = {}): MethodDecorator {
34
+ export function addEventListener<TEvent extends Event = Event>(selectorOrTarget: string, type: string, options: any = {}): MethodDecorator {
31
35
  return (targetObj: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
32
36
  const constructor = targetObj.constructor;
33
37
 
34
- let listeners = ReflectUtils.getMetadata<AddEventListenerMetadata[]>(ADD_EVENT_LISTENER_METADATA_KEY, constructor);
38
+ let listeners = ReflectUtils.getMetadata<AddEventListenerMetadata<TEvent>[]>(ADD_EVENT_LISTENER_METADATA_KEY, constructor);
35
39
  if (!listeners) {
36
40
  listeners = [];
37
41
  ReflectUtils.defineMetadata(ADD_EVENT_LISTENER_METADATA_KEY, listeners, constructor);
@@ -42,18 +46,18 @@ export function addEventListener(selectorOrTarget: string, type: string, options
42
46
  }
43
47
 
44
48
 
45
- export function addEventListenerDelegateLightDom(selector: string, type: string, options?: Omit<AddEventListenerBaseOptions, 'delegate'>): MethodDecorator {
46
- return addEventListener(selector, type, {...options??{}, root:'light', delegate: true});
49
+ export function addEventListenerDelegateLightDom<TEvent extends Event = Event>(selector: string, type: string, options?: Omit<AddEventListenerBaseOptions<TEvent>, 'delegate'>): MethodDecorator {
50
+ return addEventListener<TEvent>(selector, type, {...options??{}, root:'light', delegate: true});
47
51
  }
48
52
 
49
- export function addEventListenerDelegateShadowDom(selector: string, type: string, options?: Omit<AddEventListenerBaseOptions, 'delegate'>): MethodDecorator {
50
- return addEventListener(selector, type, {...options??{}, root:'shadow', delegate: true});
53
+ export function addEventListenerDelegateShadowDom<TEvent extends Event = Event>(selector: string, type: string, options?: Omit<AddEventListenerBaseOptions<TEvent>, 'delegate'>): MethodDecorator {
54
+ return addEventListener<TEvent>(selector, type, {...options??{}, root:'shadow', delegate: true});
51
55
  }
52
- export function addEventListenerDelegateAllDom(selector: string, type: string, options?: Omit<AddEventListenerBaseOptions, 'delegate'>): MethodDecorator {
53
- return addEventListener(selector, type, {...options??{}, root:'all', delegate: true});
56
+ export function addEventListenerDelegateAllDom<TEvent extends Event = Event>(selector: string, type: string, options?: Omit<AddEventListenerBaseOptions<TEvent>, 'delegate'>): MethodDecorator {
57
+ return addEventListener<TEvent>(selector, type, {...options??{}, root:'all', delegate: true});
54
58
  }
55
- export function addEventListenerDelegate(selector: string, type: string, options?: Omit<AddEventListenerBaseOptions, 'delegate'>): MethodDecorator {
56
- return addEventListener(selector, type, {...options??{}, root:'auto', delegate: true});
59
+ export function addEventListenerDelegate<TEvent extends Event = Event>(selector: string, type: string, options?: Omit<AddEventListenerBaseOptions<TEvent>, 'delegate'>): MethodDecorator {
60
+ return addEventListener<TEvent>(selector, type, {...options??{}, root:'auto', delegate: true});
57
61
  }
58
62
 
59
63
  /**
@@ -66,25 +70,25 @@ export const eventDelegateLightDom = addEventListenerDelegateLightDom;
66
70
  export const eventDelegateShadowDom = addEventListenerDelegateShadowDom;
67
71
  export const eventDelegateAllDom = addEventListenerDelegateAllDom;
68
72
  export const eventDelegate = addEventListenerDelegate;
69
- export function addEventListenerThis(type: string, options?: AddEventListenerBaseOptions & SwcQueryOptions): MethodDecorator {
70
- return addEventListener('$this', type, options);
73
+ export function addEventListenerThis<TEvent extends Event = Event>(type: string, options?: AddEventListenerBaseOptions<TEvent> & SwcQueryOptions): MethodDecorator {
74
+ return addEventListener<TEvent>('$this', type, options);
71
75
  }
72
76
 
73
77
  /**
74
78
  * @addEventListenerAppHost decorator - simplified version of @addEventListener for $appHost selector
75
79
  */
76
- export function addEventListenerAppHost(type: string, options?: AddEventListenerBaseOptions & SwcQueryOptions): MethodDecorator {
77
- return addEventListener('$appHost', type, options);
80
+ export function addEventListenerAppHost<TEvent extends Event = Event>(type: string, options?: AddEventListenerBaseOptions<TEvent> & SwcQueryOptions): MethodDecorator {
81
+ return addEventListener<TEvent>('$appHost', type, options);
78
82
  }
79
83
 
80
- export function addEventListenerWindow(type: string, options?: AddEventListenerBaseOptions & SwcQueryOptions): MethodDecorator {
81
- return addEventListener('$window', type, options);
84
+ export function addEventListenerWindow<TEvent extends Event = Event>(type: string, options?: AddEventListenerBaseOptions<TEvent> & SwcQueryOptions): MethodDecorator {
85
+ return addEventListener<TEvent>('$window', type, options);
82
86
  }
83
- export function addEventListenerDocument(type: string, options?: AddEventListenerBaseOptions & SwcQueryOptions): MethodDecorator {
84
- return addEventListener('$document', type, options);
87
+ export function addEventListenerDocument<TEvent extends Event = Event>(type: string, options?: AddEventListenerBaseOptions<TEvent> & SwcQueryOptions): MethodDecorator {
88
+ return addEventListener<TEvent>('$document', type, options);
85
89
  }
86
90
 
87
- export const getAddEventListenerMetadata = (target: any): AddEventListenerMetadata[] | undefined => {
91
+ export const getAddEventListenerMetadata = (target: any): AddEventListenerMetadata<Event>[] | undefined => {
88
92
  const constructor = target instanceof Function ? target : target.constructor;
89
93
  return ReflectUtils.getMetadata(ADD_EVENT_LISTENER_METADATA_KEY, constructor);
90
94
  };
@@ -54,6 +54,36 @@ export const ATTRIBUTE_METADATA_KEY = Symbol.for('simple-web-component:attribute
54
54
  // Utilities
55
55
  // ============================================
56
56
 
57
+ /**
58
+ * Determine if a string is a CSS selector or an attribute name
59
+ *
60
+ * CSS selectors typically:
61
+ * - Start with: #, ., [, :, >, +, ~
62
+ * - Contain special chars: >, +, ~, :, [, ]
63
+ * - Are special keywords: $this, $host, $parentHost, etc.
64
+ *
65
+ * Attribute names are typically:
66
+ * - kebab-case (lowercase with hyphens)
67
+ * - No special selector syntax
68
+ *
69
+ * @param str - String to check
70
+ * @returns true if it's a CSS selector, false if it's an attribute name
71
+ */
72
+ const isCssSelector = (str: string): boolean => {
73
+ if (!str) return false;
74
+
75
+ // Special keywords
76
+ if (str.startsWith('$')) return true;
77
+
78
+ // CSS selector syntax
79
+ if (/^[#.\[\:>+~]/.test(str)) return true;
80
+
81
+ // Contains CSS combinator or pseudo-selector syntax
82
+ if (/[>+~:\[\]]/.test(str)) return true;
83
+
84
+ return false;
85
+ };
86
+
57
87
  const convertValue = (val: string | null, type: any): any => {
58
88
  if (val === null || val === undefined) return val;
59
89
  if (type === Number) return Number(val);
@@ -307,77 +337,93 @@ export function applyAttribute(selector: string, targetAttributeNameOrOptions?:
307
337
  // ============================================
308
338
 
309
339
  /**
310
- * @attribute - Alias for @applyAttribute
340
+ * @attribute - Field decorator for binding element attributes (read/write)
341
+ *
342
+ * Intelligently distinguishes between attribute names and CSS selectors:
343
+ *
344
+ * Usage patterns:
345
+ * - @attribute('product-id') - Attribute name on $this (auto-detected)
346
+ * - @attribute('#user', 'product-id') - Attribute name on selector
347
+ * - @attribute('product-id', options) - Attribute name on $this with options
348
+ * - @attribute('#user', 'product-id', options) - Attribute name on selector with options
349
+ * - @attribute - Bare decorator (uses property name as attribute on $this)
350
+ *
351
+ * Note: This decorator is for FIELDS ONLY. For methods, use @setAttribute.
311
352
  */
312
- export function attribute(selector: string, targetAttributeName: string, options?: AttributeOptions): MethodDecorator & PropertyDecorator;
313
- export function attribute(selector: string, options?: AttributeOptions): MethodDecorator & PropertyDecorator;
314
- export function attribute(selector: string, targetAttributeNameOrOptions?: string | AttributeOptions, options?: AttributeOptions): MethodDecorator & PropertyDecorator {
315
- return applyAttribute(selector, targetAttributeNameOrOptions as any, options);
316
- }
317
-
318
- /**
319
- * @attributeThis - Apply attribute on $this element
320
- * Can be used as: @attributeThis or @attributeThis('attrName') or @attributeThis({ name: 'attrName' })
321
- */
322
- export function attributeThis(target: Object, propertyKey: string | symbol): void;
323
- export function attributeThis(targetAttributeName: string, options?: AttributeOptions): MethodDecorator & PropertyDecorator;
324
- export function attributeThis(options?: AttributeOptions): MethodDecorator & PropertyDecorator;
325
- export function attributeThis(targetOrOptions?: any, propertyKeyOrOptions?: any, descriptor?: PropertyDescriptor): any {
326
- // Direct decorator usage: @attributeThis
327
- if (typeof targetOrOptions === 'object' && targetOrOptions !== null && !Array.isArray(targetOrOptions) &&
328
- typeof propertyKeyOrOptions === 'string' || typeof propertyKeyOrOptions === 'symbol') {
329
- // Called as @attributeThis (target, propertyKey)
330
- return applyAttribute('$this', undefined as any, {})(targetOrOptions, propertyKeyOrOptions, descriptor);
353
+ export function attribute(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
354
+ export function attribute(attributeName: string, options?: AttributeOptions): PropertyDecorator;
355
+ export function attribute(selector: string, attributeName: string, options?: AttributeOptions): PropertyDecorator;
356
+ export function attribute(selectorOrAttributeOrTarget?: string | Object, attributeNameOrOptions?: any, optionsOrDescriptor?: any): any {
357
+ // Bare decorator: @attribute
358
+ if (optionsOrDescriptor !== undefined && (typeof attributeNameOrOptions === 'string' || typeof attributeNameOrOptions === 'symbol')) {
359
+ return applyAttribute('$this', undefined as any, {})(selectorOrAttributeOrTarget as Object, attributeNameOrOptions, optionsOrDescriptor as PropertyDescriptor);
331
360
  }
332
-
333
- // Called with parameters
334
- if (typeof targetOrOptions === 'string') {
335
- // @attributeThis('attrName', options?)
336
- return applyAttribute('$this', targetOrOptions, propertyKeyOrOptions);
337
- } else if (targetOrOptions && typeof targetOrOptions === 'object') {
338
- // @attributeThis({ name: 'attrName' })
339
- return applyAttribute('$this', undefined as any, targetOrOptions);
340
- } else {
341
- // @attributeThis() or @attributeThis
342
- return applyAttribute('$this', undefined as any, {});
361
+
362
+ // With string as first parameter
363
+ if (typeof selectorOrAttributeOrTarget === 'string') {
364
+ // Check if first parameter is a CSS selector or attribute name
365
+ const isSelector = isCssSelector(selectorOrAttributeOrTarget);
366
+
367
+ if (isSelector) {
368
+ // First param is a selector: @attribute('#user', 'product-id', options?)
369
+ return applyAttribute(selectorOrAttributeOrTarget, attributeNameOrOptions as any, optionsOrDescriptor as AttributeOptions);
370
+ } else {
371
+ // First param is an attribute name: @attribute('product-id', options?)
372
+ // Treat as attribute name on $this
373
+ const options = (typeof attributeNameOrOptions === 'object' && attributeNameOrOptions !== null)
374
+ ? attributeNameOrOptions
375
+ : {};
376
+ return applyAttribute('$this', selectorOrAttributeOrTarget, options);
377
+ }
343
378
  }
379
+
380
+ // Without selector (defaults to $this with options)
381
+ return applyAttribute('$this', undefined as any, selectorOrAttributeOrTarget as AttributeOptions);
344
382
  }
345
383
 
346
384
  /**
347
- * @setAttribute - Alias for @applyAttribute (method-decorator semantics)
348
- */
349
- export function setAttribute(selector: string, targetAttributeName: string, options?: AttributeOptions): MethodDecorator;
350
- export function setAttribute(selector: string, options?: AttributeOptions): MethodDecorator;
351
- export function setAttribute(selector: string, targetAttributeNameOrOptions?: string | AttributeOptions, options?: AttributeOptions): MethodDecorator {
352
- return applyAttribute(selector, targetAttributeNameOrOptions as any, options) as MethodDecorator;
353
- }
354
-
355
- /**
356
- * @setAttributeThis - Set attribute on $this element
357
- * Can be used as: @setAttributeThis or @setAttributeThis('attrName') or @setAttributeThis({ name: 'attrName' })
385
+ * @setAttribute - Method decorator for setting element attributes from method return value
386
+ *
387
+ * Intelligently distinguishes between attribute names and CSS selectors:
388
+ *
389
+ * Usage patterns:
390
+ * - @setAttribute('data-id') - Attribute name on $this (auto-detected)
391
+ * - @setAttribute('#user', 'data-id') - Attribute name on selector
392
+ * - @setAttribute('data-id', options) - Attribute name on $this with options
393
+ * - @setAttribute('#user', 'data-id', options) - Attribute name on selector with options
394
+ * - @setAttribute - Bare decorator (uses method name as attribute on $this)
395
+ *
396
+ * Note: This decorator is for METHODS ONLY. For fields, use @attribute.
397
+ *
398
+ * Example:
399
+ * @setAttribute('data-status')
400
+ * updateStatus() {
401
+ * return 'active';
402
+ * }
358
403
  */
359
- export function setAttributeThis(target: Object, propertyKey: string | symbol): void;
360
- export function setAttributeThis(targetAttributeName: string, options?: AttributeOptions): MethodDecorator;
361
- export function setAttributeThis(options?: AttributeOptions): MethodDecorator;
362
- export function setAttributeThis(targetOrOptions?: any, propertyKeyOrOptions?: any, descriptor?: PropertyDescriptor): any {
363
- // Direct decorator usage: @setAttributeThis
364
- if (typeof targetOrOptions === 'object' && targetOrOptions !== null && !Array.isArray(targetOrOptions) &&
365
- (typeof propertyKeyOrOptions === 'string' || typeof propertyKeyOrOptions === 'symbol')) {
366
- // Called as @setAttributeThis (target, propertyKey)
367
- return applyAttribute('$this', undefined as any, {})(targetOrOptions, propertyKeyOrOptions, descriptor);
368
- }
369
-
370
- // Called with parameters
371
- if (typeof targetOrOptions === 'string') {
372
- // @setAttributeThis('attrName', options?)
373
- return applyAttribute('$this', targetOrOptions, propertyKeyOrOptions) as MethodDecorator;
374
- } else if (targetOrOptions && typeof targetOrOptions === 'object') {
375
- // @setAttributeThis({ name: 'attrName' })
376
- return applyAttribute('$this', undefined as any, targetOrOptions) as MethodDecorator;
377
- } else {
378
- // @setAttributeThis() or @setAttributeThis
379
- return applyAttribute('$this', undefined as any, {}) as MethodDecorator;
404
+ export function setAttribute(selector: string, attributeName: string, options?: AttributeOptions): MethodDecorator;
405
+ export function setAttribute(attributeName: string, options?: AttributeOptions): MethodDecorator;
406
+ export function setAttribute(selectorOrAttributeOrOptions?: string | AttributeOptions, attributeNameOrOptions?: any, optionsOrUndefined?: AttributeOptions): MethodDecorator {
407
+ // With string as first parameter
408
+ if (typeof selectorOrAttributeOrOptions === 'string') {
409
+ // Check if first parameter is a CSS selector or attribute name
410
+ const isSelector = isCssSelector(selectorOrAttributeOrOptions);
411
+
412
+ if (isSelector) {
413
+ // First param is a selector: @setAttribute('#user', 'data-id', options?)
414
+ return applyAttribute(selectorOrAttributeOrOptions, attributeNameOrOptions as any, optionsOrUndefined as AttributeOptions) as MethodDecorator;
415
+ } else {
416
+ // First param is an attribute name: @setAttribute('data-id', options?)
417
+ // Treat as attribute name on $this
418
+ const options = (typeof attributeNameOrOptions === 'object' && attributeNameOrOptions !== null)
419
+ ? attributeNameOrOptions
420
+ : {};
421
+ return applyAttribute('$this', selectorOrAttributeOrOptions, options) as MethodDecorator;
422
+ }
380
423
  }
424
+
425
+ // Without selector (defaults to $this with options)
426
+ return applyAttribute('$this', undefined as any, selectorOrAttributeOrOptions as AttributeOptions) as MethodDecorator;
381
427
  }
382
428
 
383
429
  // ============================================
@@ -163,25 +163,99 @@ function createClassDecorator(action: ClassAction) {
163
163
  };
164
164
  }
165
165
 
166
- export function applyClass(selector: string, action: ClassAction = 'update', options: ClassApplyOptions = {}): MethodDecorator {
167
- return createClassDecorator(action)(selector, options);
166
+ export function applyClass(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
167
+ export function applyClass(selector: string, action?: ClassAction, options?: ClassApplyOptions): MethodDecorator;
168
+ export function applyClass(selectorOrTarget?: any, actionOrPropertyKey?: any, optionsOrDescriptor?: any): any {
169
+ // Bare decorator: @applyClass
170
+ if (optionsOrDescriptor !== undefined && (typeof actionOrPropertyKey === 'string' || typeof actionOrPropertyKey === 'symbol')) {
171
+ return createClassDecorator('update')('$this', {})(selectorOrTarget as Object, actionOrPropertyKey, optionsOrDescriptor as PropertyDescriptor);
172
+ }
173
+ // With selector
174
+ if (typeof selectorOrTarget === 'string') {
175
+ const action = (typeof actionOrPropertyKey === 'string' ? actionOrPropertyKey : 'update') as ClassAction;
176
+ const options = (typeof actionOrPropertyKey === 'object' ? actionOrPropertyKey : optionsOrDescriptor) as ClassApplyOptions | undefined;
177
+ return createClassDecorator(action)(selectorOrTarget, options);
178
+ }
179
+ // Without selector (defaults to $this)
180
+ const action = (typeof selectorOrTarget === 'string' ? selectorOrTarget : 'update') as ClassAction;
181
+ const options = (typeof selectorOrTarget === 'object' ? selectorOrTarget : actionOrPropertyKey) as ClassApplyOptions | undefined;
182
+ return createClassDecorator(action)('$this', options);
168
183
  }
169
184
 
170
- export const setClass = (selector: string, classMapOrOptions?: string | { [className: string]: (el: HTMLElement, value: any, helper: HelperHostSet & { $this: any }) => boolean } | ClassApplyOptions, options: ClassApplyOptions = {}) => createClassDecorator('set')(selector, classMapOrOptions, options);
171
- export const updateClass = (selector: string, classMapOrOptions?: string | { [className: string]: (el: HTMLElement, value: any, helper: HelperHostSet & { $this: any }) => boolean } | ClassApplyOptions, options: ClassApplyOptions = {}) => createClassDecorator('update')(selector, classMapOrOptions, options);
172
- export const addClass = (selector: string, classMapOrOptions?: string | { [className: string]: (el: HTMLElement, value: any, helper: HelperHostSet & { $this: any }) => boolean } | ClassApplyOptions, options: ClassApplyOptions = {}) => createClassDecorator('add')(selector, classMapOrOptions, options);
173
- export const removeClass = (selector: string, classMapOrOptions?: string | { [className: string]: (el: HTMLElement, value: any, helper: HelperHostSet & { $this: any }) => boolean } | ClassApplyOptions, options: ClassApplyOptions = {}) => createClassDecorator('remove')(selector, classMapOrOptions, options);
174
- export const toggleClass = (selector: string, classMapOrOptions?: string | { [className: string]: (el: HTMLElement, value: any, helper: HelperHostSet & { $this: any }) => boolean } | ClassApplyOptions, options: ClassApplyOptions = {}) => createClassDecorator('toggle')(selector, classMapOrOptions, options);
185
+ export function setClass(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
186
+ export function setClass(selector: string, classMapOrOptions?: string | { [className: string]: (el: HTMLElement, value: any, helper: HelperHostSet & { $this: any }) => boolean } | ClassApplyOptions, options?: ClassApplyOptions): MethodDecorator;
187
+ export function setClass(selectorOrTarget?: any, classMapOrOptionsOrPropertyKey?: any, optionsOrDescriptor?: any): any {
188
+ // Bare decorator: @setClass
189
+ if (optionsOrDescriptor !== undefined && (typeof classMapOrOptionsOrPropertyKey === 'string' || typeof classMapOrOptionsOrPropertyKey === 'symbol')) {
190
+ return createClassDecorator('set')('$this', {})(selectorOrTarget as Object, classMapOrOptionsOrPropertyKey, optionsOrDescriptor as PropertyDescriptor);
191
+ }
192
+ // With selector
193
+ if (typeof selectorOrTarget === 'string') {
194
+ return createClassDecorator('set')(selectorOrTarget, classMapOrOptionsOrPropertyKey, optionsOrDescriptor as ClassApplyOptions);
195
+ }
196
+ // Without selector (defaults to $this)
197
+ return createClassDecorator('set')('$this', selectorOrTarget as ClassApplyOptions);
198
+ }
175
199
 
176
- // This versions
177
- export function applyClassThis(action: ClassAction = 'update', options: ClassApplyOptions = {}): MethodDecorator {
178
- return createClassDecorator(action)('$this', options);
200
+ export function updateClass(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
201
+ export function updateClass(selector: string, classMapOrOptions?: string | { [className: string]: (el: HTMLElement, value: any, helper: HelperHostSet & { $this: any }) => boolean } | ClassApplyOptions, options?: ClassApplyOptions): MethodDecorator;
202
+ export function updateClass(selectorOrTarget?: any, classMapOrOptionsOrPropertyKey?: any, optionsOrDescriptor?: any): any {
203
+ // Bare decorator: @updateClass
204
+ if (optionsOrDescriptor !== undefined && (typeof classMapOrOptionsOrPropertyKey === 'string' || typeof classMapOrOptionsOrPropertyKey === 'symbol')) {
205
+ return createClassDecorator('update')('$this', {})(selectorOrTarget as Object, classMapOrOptionsOrPropertyKey, optionsOrDescriptor as PropertyDescriptor);
206
+ }
207
+ // With selector
208
+ if (typeof selectorOrTarget === 'string') {
209
+ return createClassDecorator('update')(selectorOrTarget, classMapOrOptionsOrPropertyKey, optionsOrDescriptor as ClassApplyOptions);
210
+ }
211
+ // Without selector (defaults to $this)
212
+ return createClassDecorator('update')('$this', selectorOrTarget as ClassApplyOptions);
213
+ }
214
+
215
+ export function addClass(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
216
+ export function addClass(selector: string, classMapOrOptions?: string | { [className: string]: (el: HTMLElement, value: any, helper: HelperHostSet & { $this: any }) => boolean } | ClassApplyOptions, options?: ClassApplyOptions): MethodDecorator;
217
+ export function addClass(selectorOrTarget?: any, classMapOrOptionsOrPropertyKey?: any, optionsOrDescriptor?: any): any {
218
+ // Bare decorator: @addClass
219
+ if (optionsOrDescriptor !== undefined && (typeof classMapOrOptionsOrPropertyKey === 'string' || typeof classMapOrOptionsOrPropertyKey === 'symbol')) {
220
+ return createClassDecorator('add')('$this', {})(selectorOrTarget as Object, classMapOrOptionsOrPropertyKey, optionsOrDescriptor as PropertyDescriptor);
221
+ }
222
+ // With selector
223
+ if (typeof selectorOrTarget === 'string') {
224
+ return createClassDecorator('add')(selectorOrTarget, classMapOrOptionsOrPropertyKey, optionsOrDescriptor as ClassApplyOptions);
225
+ }
226
+ // Without selector (defaults to $this)
227
+ return createClassDecorator('add')('$this', selectorOrTarget as ClassApplyOptions);
228
+ }
229
+
230
+ export function removeClass(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
231
+ export function removeClass(selector: string, classMapOrOptions?: string | { [className: string]: (el: HTMLElement, value: any, helper: HelperHostSet & { $this: any }) => boolean } | ClassApplyOptions, options?: ClassApplyOptions): MethodDecorator;
232
+ export function removeClass(selectorOrTarget?: any, classMapOrOptionsOrPropertyKey?: any, optionsOrDescriptor?: any): any {
233
+ // Bare decorator: @removeClass
234
+ if (optionsOrDescriptor !== undefined && (typeof classMapOrOptionsOrPropertyKey === 'string' || typeof classMapOrOptionsOrPropertyKey === 'symbol')) {
235
+ return createClassDecorator('remove')('$this', {})(selectorOrTarget as Object, classMapOrOptionsOrPropertyKey, optionsOrDescriptor as PropertyDescriptor);
236
+ }
237
+ // With selector
238
+ if (typeof selectorOrTarget === 'string') {
239
+ return createClassDecorator('remove')(selectorOrTarget, classMapOrOptionsOrPropertyKey, optionsOrDescriptor as ClassApplyOptions);
240
+ }
241
+ // Without selector (defaults to $this)
242
+ return createClassDecorator('remove')('$this', selectorOrTarget as ClassApplyOptions);
243
+ }
244
+
245
+ export function toggleClass(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
246
+ export function toggleClass(selector: string, classMapOrOptions?: string | { [className: string]: (el: HTMLElement, value: any, helper: HelperHostSet & { $this: any }) => boolean } | ClassApplyOptions, options?: ClassApplyOptions): MethodDecorator;
247
+ export function toggleClass(selectorOrTarget?: any, classMapOrOptionsOrPropertyKey?: any, optionsOrDescriptor?: any): any {
248
+ // Bare decorator: @toggleClass
249
+ if (optionsOrDescriptor !== undefined && (typeof classMapOrOptionsOrPropertyKey === 'string' || typeof classMapOrOptionsOrPropertyKey === 'symbol')) {
250
+ return createClassDecorator('toggle')('$this', {})(selectorOrTarget as Object, classMapOrOptionsOrPropertyKey, optionsOrDescriptor as PropertyDescriptor);
251
+ }
252
+ // With selector
253
+ if (typeof selectorOrTarget === 'string') {
254
+ return createClassDecorator('toggle')(selectorOrTarget, classMapOrOptionsOrPropertyKey, optionsOrDescriptor as ClassApplyOptions);
255
+ }
256
+ // Without selector (defaults to $this)
257
+ return createClassDecorator('toggle')('$this', selectorOrTarget as ClassApplyOptions);
179
258
  }
180
- export const setClassThis = (classMapOrOptions?: string | { [className: string]: (el: HTMLElement, value: any, helper: HelperHostSet & { $this: any }) => boolean } | ClassApplyOptions, options: ClassApplyOptions = {}) => createClassDecorator('set')('$this', classMapOrOptions, options);
181
- export const updateClassThis = (classMapOrOptions?: string | { [className: string]: (el: HTMLElement, value: any, helper: HelperHostSet & { $this: any }) => boolean } | ClassApplyOptions, options: ClassApplyOptions = {}) => createClassDecorator('update')('$this', classMapOrOptions, options);
182
- export const addClassThis = (classMapOrOptions?: string | { [className: string]: (el: HTMLElement, value: any, helper: HelperHostSet & { $this: any }) => boolean } | ClassApplyOptions, options: ClassApplyOptions = {}) => createClassDecorator('add')('$this', classMapOrOptions, options);
183
- export const removeClassThis = (classMapOrOptions?: string | { [className: string]: (el: HTMLElement, value: any, helper: HelperHostSet & { $this: any }) => boolean } | ClassApplyOptions, options: ClassApplyOptions = {}) => createClassDecorator('remove')('$this', classMapOrOptions, options);
184
- export const toggleClassThis = (classMapOrOptions?: string | { [className: string]: (el: HTMLElement, value: any, helper: HelperHostSet & { $this: any }) => boolean } | ClassApplyOptions, options: ClassApplyOptions = {}) => createClassDecorator('toggle')('$this', classMapOrOptions, options);
185
259
 
186
260
  export const findAllClassMetadata = (target: any): Map<string | symbol, ClassApplyMetadata> => {
187
261
  const result = new Map<string | symbol, ClassApplyMetadata>();