@dooboostore/simple-web-component 1.0.38 → 1.0.40

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 (91) hide show
  1. package/LICENSE.md +7 -0
  2. package/README.md +88 -871
  3. package/dist/cjs/SwcAppEngine.js.map +2 -2
  4. package/dist/cjs/decorators/applyAttribute.js +194 -111
  5. package/dist/cjs/decorators/applyAttribute.js.map +2 -2
  6. package/dist/cjs/decorators/applyNode.js +82 -80
  7. package/dist/cjs/decorators/applyNode.js.map +2 -2
  8. package/dist/cjs/decorators/applyProperty.js +213 -0
  9. package/dist/cjs/decorators/applyProperty.js.map +7 -0
  10. package/dist/cjs/decorators/applySlot.js +93 -82
  11. package/dist/cjs/decorators/applySlot.js.map +3 -3
  12. package/dist/cjs/decorators/changedAttributeThis.js.map +1 -1
  13. package/dist/cjs/decorators/elementDefine.js +14 -34
  14. package/dist/cjs/decorators/elementDefine.js.map +2 -2
  15. package/dist/cjs/decorators/index.js +2 -2
  16. package/dist/cjs/decorators/index.js.map +2 -2
  17. package/dist/cjs/decorators/lifecycles.js +4 -4
  18. package/dist/cjs/decorators/lifecycles.js.map +2 -2
  19. package/dist/cjs/decorators/state.js +0 -1
  20. package/dist/cjs/decorators/state.js.map +2 -2
  21. package/dist/cjs/elements/SwcApp.js.map +2 -2
  22. package/dist/cjs/types/index.js.map +1 -1
  23. package/dist/esm/SwcAppEngine.js.map +2 -2
  24. package/dist/esm/decorators/applyAttribute.js +196 -113
  25. package/dist/esm/decorators/applyAttribute.js.map +2 -2
  26. package/dist/esm/decorators/applyNode.js +82 -80
  27. package/dist/esm/decorators/applyNode.js.map +2 -2
  28. package/dist/esm/decorators/applyProperty.js +194 -0
  29. package/dist/esm/decorators/applyProperty.js.map +7 -0
  30. package/dist/esm/decorators/applySlot.js +93 -82
  31. package/dist/esm/decorators/applySlot.js.map +3 -3
  32. package/dist/esm/decorators/changedAttributeThis.js.map +1 -1
  33. package/dist/esm/decorators/elementDefine.js +14 -34
  34. package/dist/esm/decorators/elementDefine.js.map +2 -2
  35. package/dist/esm/decorators/index.js +2 -2
  36. package/dist/esm/decorators/index.js.map +1 -1
  37. package/dist/esm/decorators/lifecycles.js +4 -4
  38. package/dist/esm/decorators/lifecycles.js.map +2 -2
  39. package/dist/esm/decorators/state.js +0 -1
  40. package/dist/esm/decorators/state.js.map +2 -2
  41. package/dist/esm/elements/SwcApp.js.map +2 -2
  42. package/dist/esm/types/index.js.map +1 -1
  43. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +525 -513
  44. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
  45. package/dist/types/SwcAppEngine.d.ts.map +1 -1
  46. package/dist/types/decorators/applyAttribute.d.ts +56 -15
  47. package/dist/types/decorators/applyAttribute.d.ts.map +1 -1
  48. package/dist/types/decorators/applyNode.d.ts +28 -24
  49. package/dist/types/decorators/applyNode.d.ts.map +1 -1
  50. package/dist/types/decorators/applyProperty.d.ts +61 -0
  51. package/dist/types/decorators/applyProperty.d.ts.map +1 -0
  52. package/dist/types/decorators/applySlot.d.ts +17 -15
  53. package/dist/types/decorators/applySlot.d.ts.map +1 -1
  54. package/dist/types/decorators/elementDefine.d.ts.map +1 -1
  55. package/dist/types/decorators/index.d.ts +2 -2
  56. package/dist/types/decorators/index.d.ts.map +1 -1
  57. package/dist/types/decorators/lifecycles.d.ts +4 -4
  58. package/dist/types/decorators/lifecycles.d.ts.map +1 -1
  59. package/dist/types/decorators/state.d.ts.map +1 -1
  60. package/dist/types/elements/SwcApp.d.ts.map +1 -1
  61. package/dist/types/types/index.d.ts +1 -6
  62. package/dist/types/types/index.d.ts.map +1 -1
  63. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +525 -513
  64. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
  65. package/package.json +1 -1
  66. package/src/SwcAppEngine.ts +1 -0
  67. package/src/decorators/applyAttribute.ts +311 -126
  68. package/src/decorators/applyNode.ts +108 -105
  69. package/src/decorators/applyProperty.ts +302 -0
  70. package/src/decorators/applySlot.ts +112 -94
  71. package/src/decorators/changedAttributeThis.ts +1 -1
  72. package/src/decorators/elementDefine.ts +44 -33
  73. package/src/decorators/index.ts +2 -3
  74. package/src/decorators/lifecycles.ts +6 -6
  75. package/src/decorators/state.ts +0 -1
  76. package/src/elements/SwcApp.ts +0 -1
  77. package/src/types/index.ts +7 -7
  78. package/dist/cjs/decorators/attribute.js +0 -187
  79. package/dist/cjs/decorators/attribute.js.map +0 -7
  80. package/dist/cjs/decorators/setProperty.js +0 -109
  81. package/dist/cjs/decorators/setProperty.js.map +0 -7
  82. package/dist/esm/decorators/attribute.js +0 -168
  83. package/dist/esm/decorators/attribute.js.map +0 -7
  84. package/dist/esm/decorators/setProperty.js +0 -90
  85. package/dist/esm/decorators/setProperty.js.map +0 -7
  86. package/dist/types/decorators/attribute.d.ts +0 -31
  87. package/dist/types/decorators/attribute.d.ts.map +0 -1
  88. package/dist/types/decorators/setProperty.d.ts +0 -17
  89. package/dist/types/decorators/setProperty.d.ts.map +0 -1
  90. package/src/decorators/attribute.ts +0 -223
  91. package/src/decorators/setProperty.ts +0 -112
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dooboostore/simple-web-component",
3
- "version": "1.0.38",
3
+ "version": "1.0.40",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",
@@ -77,6 +77,7 @@ export class SwcAppEngine {
77
77
 
78
78
 
79
79
  if (this._config.onStartedLazyDefineComponent) {
80
+ // console.log('-------->', this._config.onStartedLazyDefineComponent)
80
81
  await Promise.all(this._config.onStartedLazyDefineComponent.map(it => it(this._config.window)))
81
82
  }
82
83
  if (this._config.onEngineStarted) {
@@ -1,161 +1,346 @@
1
- import { ReflectUtils } from '@dooboostore/core';
2
- import { ensureInit } from './elementDefine';
3
- import { SwcUtils } from '../utils/Utils';
4
- import { SpecialSelector, SwcQueryOptions, HelperHostSet } from '../types';
1
+ import {ReflectUtils, FunctionUtils, ActionExpression} from '@dooboostore/core';
2
+ import {ensureInit, getElementConfig} from './elementDefine';
3
+ import {SwcUtils} from '../utils/Utils';
4
+ import {SwcQueryOptions, HelperHostSet} from '../types';
5
+ import {ConvertUtils} from '@dooboostore/core-web';
5
6
 
6
- export type AttributeAction = 'set' | 'update' | 'remove';
7
+ // ============================================
8
+ // Types & Interfaces
9
+ // ============================================
7
10
 
8
- export interface AttributeApplyOptions extends SwcQueryOptions {
11
+ export interface AttributeOptions extends SwcQueryOptions {
9
12
  name?: string;
10
- filter?: (target: HTMLElement, value: any, meta: {currentThis: any, helper: HelperHostSet}) => boolean;
13
+ type?: typeof Number | typeof Boolean | typeof String;
14
+ filter?: (target: HTMLElement, value: any, meta: { currentThis: any, helper: HelperHostSet }) => boolean;
11
15
  }
12
16
 
13
- export interface AttributeApplyMetadata {
17
+ export interface AttributeMetadata {
14
18
  propertyKey: string | symbol;
15
19
  selector: string;
16
- action: AttributeAction;
17
- options: AttributeApplyOptions;
20
+ targetAttributeName: string;
21
+ options: AttributeOptions;
22
+ type: 'property' | 'method';
18
23
  }
19
24
 
20
- export const ATTRIBUTE_APPLY_METADATA_KEY = Symbol.for('simple-web-component:attribute-apply');
25
+ export const ATTRIBUTE_METADATA_KEY = Symbol.for('simple-web-component:attribute');
21
26
 
22
- function createAttributeDecorator(action: AttributeAction) {
23
- return (selector: string, nameOrOptions?: string | AttributeApplyOptions, options: AttributeApplyOptions = {}): MethodDecorator => {
24
- return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
25
- const constructor = target.constructor;
26
- let metaList = ReflectUtils.getOwnMetadata(ATTRIBUTE_APPLY_METADATA_KEY, constructor) as Map<string | symbol, AttributeApplyMetadata>;
27
- if (!metaList) {
28
- metaList = new Map<string | symbol, AttributeApplyMetadata>();
29
- ReflectUtils.defineMetadata(ATTRIBUTE_APPLY_METADATA_KEY, metaList, constructor);
27
+ // ============================================
28
+ // Utilities
29
+ // ============================================
30
+
31
+ const convertValue = (val: string | null, type: any): any => {
32
+ if (val === null || val === undefined) return val;
33
+ if (type === Number) return Number(val);
34
+ if (type === Boolean) return val === 'false' || val === '0' ? false : true;
35
+ return val;
36
+ };
37
+
38
+ export {convertValue};
39
+
40
+ export const getAttributeValue = (inst: any, attrName: string, options?: AttributeOptions & { selector?: string }): any => {
41
+ const conf = getElementConfig(inst);
42
+ const currentWin = inst._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as any);
43
+
44
+ // If selector is not provided, use inst itself
45
+ const targets = options?.selector ? resolveAttributeTargets(inst, options.selector, options) : [inst];
46
+
47
+ const primaryTarget = targets[0];
48
+
49
+ if (primaryTarget && typeof (primaryTarget as any).hasAttribute === 'function' && (primaryTarget as any).hasAttribute(attrName)) {
50
+ let domVal = (primaryTarget as any).getAttribute(attrName);
51
+
52
+ // 표현식 체크
53
+ const ae = new ActionExpression(domVal);
54
+ const expr = ae.getFirstExpression('callReturn');
55
+ if (expr) {
56
+ try {
57
+ const result = FunctionUtils.executeReturn({
58
+ script: ConvertUtils.decodeHtmlEntity(expr.script, currentWin.document),
59
+ context: inst,
60
+ args: SwcUtils.getHelperAndHostSet(currentWin, inst)
61
+ });
62
+ return convertValue(result, options?.type);
63
+ } catch (err) {
64
+ console.error(`[SWC] Failed to execute directive {{= ${expr.script} }}:`, err);
65
+ return convertValue(domVal, options?.type);
30
66
  }
67
+ }
31
68
 
32
- let attributeName = typeof nameOrOptions === 'string' ? nameOrOptions : undefined;
33
- let finalOptions = options;
34
-
35
- if (typeof nameOrOptions === 'object' && nameOrOptions !== null) {
36
- finalOptions = nameOrOptions as AttributeApplyOptions;
69
+ return convertValue(domVal, options?.type);
70
+ }
71
+
72
+ // If no target found, return null
73
+ return null;
74
+ };
75
+
76
+ /**
77
+ * Resolve target elements based on selector and options
78
+ * Handles special selectors ($this, $host, etc.) and CSS selectors
79
+ * Returns HTMLElement[] for attribute operations
80
+ */
81
+ export const resolveAttributeTargets = (inst: any, selector: string, options: AttributeOptions): HTMLElement[] => {
82
+ const conf = getElementConfig(inst);
83
+ const currentWin = conf.window;
84
+ const r = options.root || 'auto';
85
+ const results: HTMLElement[] = [];
86
+
87
+ const applyRoot = (target: any) => {
88
+ if (!target) return;
89
+ if (r === 'auto') {
90
+ results.push(target);
91
+ } else {
92
+ if (r === 'light' || r === 'all') results.push(target);
93
+ if ((r === 'shadow' || r === 'all') && target.shadowRoot) results.push(target.shadowRoot);
94
+ }
95
+ };
96
+
97
+ if (selector === '$this' || !selector) {
98
+ applyRoot(inst);
99
+ } else {
100
+ const hostSet = SwcUtils.getHostSet(inst);
101
+ if (selector === '$host') applyRoot(hostSet.$host);
102
+ else if (selector === '$parentHost') applyRoot(hostSet.$parentHost);
103
+ else if (selector === '$appHost') applyRoot(hostSet.$appHost as any);
104
+ else if (selector === '$firstHost') applyRoot(hostSet.$firstHost);
105
+ else if (selector === '$lastHost') applyRoot(hostSet.$lastHost);
106
+ else if (selector === '$firstAppHost') applyRoot(hostSet.$firstAppHost as any);
107
+ else if (selector === '$lastAppHost') applyRoot(hostSet.$lastAppHost as any);
108
+ else if (selector === '$hosts') hostSet.$hosts.forEach(applyRoot);
109
+ else if (selector === '$appHosts') hostSet.$appHosts.forEach(applyRoot);
110
+ else {
111
+ if (r === 'shadow') {
112
+ const found = inst.shadowRoot?.querySelectorAll(selector);
113
+ if (found) results.push(...found);
114
+ } else if (r === 'light') {
115
+ const found = inst.querySelectorAll(selector);
116
+ if (found) results.push(...found);
117
+ } else if (r === 'all') {
118
+ const sMatch = inst.shadowRoot?.querySelectorAll(selector);
119
+ const lMatch = inst.querySelectorAll(selector);
120
+ if (sMatch) results.push(...sMatch);
121
+ if (lMatch) results.push(...lMatch);
122
+ } else {
123
+ const found = (inst.shadowRoot || inst).querySelectorAll(selector);
124
+ if (found) results.push(...found);
37
125
  }
126
+ }
127
+ }
128
+ return results;
129
+ };
130
+
131
+ /**
132
+ * @applyAttribute decorator - set/get element attributes
133
+ *
134
+ * Usage:
135
+ * - @applyAttribute('selector', 'attrName') - Set attribute with explicit name
136
+ * - @applyAttribute('selector') - Use property name as attribute name
137
+ * - @applyAttribute('selector', { name: 'attrName' }) - Set attribute via options
138
+ * - Return null to remove attribute
139
+ */
140
+ export function applyAttribute(selector: string, targetAttributeName: string, options?: AttributeOptions): MethodDecorator & PropertyDecorator;
141
+ export function applyAttribute(selector: string, options?: AttributeOptions): MethodDecorator & PropertyDecorator;
142
+ export function applyAttribute(selector: string, targetAttributeNameOrOptions?: string | AttributeOptions, options?: AttributeOptions): MethodDecorator & PropertyDecorator {
143
+ return (target: Object, propertyKey: string | symbol, descriptor?: PropertyDescriptor) => {
144
+ // ensureInit(target as any);
145
+
146
+ const constructor = target.constructor;
147
+ const designType = (Reflect as any).getMetadata('design:type', target, propertyKey);
148
+ const metaType: 'property' | 'method' = descriptor && typeof descriptor.value === 'function' ? 'method' : 'property';
149
+
150
+ // Parse arguments
151
+ let finalOptions: AttributeOptions = {};
152
+ let targetAttributeName: string;
153
+
154
+ if (typeof targetAttributeNameOrOptions === 'string') {
155
+ // applyAttribute('selector', 'attrName', options?)
156
+ targetAttributeName = targetAttributeNameOrOptions;
157
+ finalOptions = options || {};
158
+ } else if (targetAttributeNameOrOptions) {
159
+ // applyAttribute('selector', options)
160
+ finalOptions = targetAttributeNameOrOptions;
161
+ targetAttributeName = finalOptions.name || String(propertyKey);
162
+ } else {
163
+ // applyAttribute('selector')
164
+ targetAttributeName = String(propertyKey);
165
+ }
166
+
167
+ // Store metadata
168
+ let metaList = ReflectUtils.getOwnMetadata(ATTRIBUTE_METADATA_KEY, constructor) as AttributeMetadata[];
169
+ if (!metaList) {
170
+ metaList = [];
171
+ ReflectUtils.defineMetadata(ATTRIBUTE_METADATA_KEY, metaList, constructor);
172
+ }
173
+ metaList.push({
174
+ propertyKey,
175
+ selector,
176
+ targetAttributeName,
177
+ options: finalOptions,
178
+ type: metaType
179
+ });
180
+
181
+ // Helper: Apply resolved value to targets
182
+ const applyValueToTargets = (inst: any, resolvedValue: any) => {
183
+ const conf = getElementConfig(inst);
184
+ const currentWin = conf.window;
185
+ const targetEls = resolveAttributeTargets(inst, selector, finalOptions);
186
+ const hostSet = SwcUtils.getHelperAndHostSet(currentWin, inst);
187
+
188
+ targetEls.forEach(targetEl => {
189
+ // Apply filter if provided
190
+ if (finalOptions.filter && !finalOptions.filter(targetEl, resolvedValue, {currentThis: inst, helper: hostSet})) {
191
+ return;
192
+ }
38
193
 
39
- metaList.set(propertyKey, {
40
- propertyKey,
41
- selector,
42
- action,
43
- options: { ...finalOptions, name: attributeName }
194
+ if (resolvedValue === null) {
195
+ // Remove attribute if value is null
196
+ targetEl.removeAttribute(targetAttributeName);
197
+ } else if (resolvedValue !== undefined) {
198
+ // Set attribute
199
+ targetEl.setAttribute(targetAttributeName, resolvedValue === true ? '' : String(resolvedValue));
200
+ }
44
201
  });
45
202
 
203
+ return resolvedValue;
204
+ };
205
+
206
+ // Method decorator: wrap method to apply its return value to attributes
207
+ if (descriptor && typeof descriptor.value === 'function') {
46
208
  const original = descriptor.value;
47
209
  descriptor.value = function (...args: any[]) {
48
210
  ensureInit(this);
49
211
  const res = (original as any).apply(this, args);
50
212
 
51
- const handleResult = (resolvedValue: any) => {
52
- if (resolvedValue !== undefined) {
53
- const win = (this as any).ownerDocument?.defaultView || window;
54
- const host = this as unknown as HTMLElement;
55
- const hostSet = { ...SwcUtils.getHelperAndHostSet(win, host), $this: this };
56
- const r = finalOptions.root || 'auto';
57
- const targetEls: HTMLElement[] = [];
58
-
59
- const applyRoot = (t: any) => {
60
- if (!t || !(t instanceof win.HTMLElement)) return;
61
- targetEls.push(t);
62
- };
63
-
64
- if (selector === '$this' || !selector) applyRoot(host);
65
- else if (selector === '$host') applyRoot(hostSet.$host);
66
- else if (selector === '$parentHost') applyRoot(hostSet.$parentHost);
67
- else if (selector === '$appHost') applyRoot(hostSet.$appHost);
68
- else if (selector === '$firstHost') applyRoot(hostSet.$firstHost);
69
- else if (selector === '$lastHost') applyRoot(hostSet.$lastHost);
70
- else if (selector === '$firstAppHost') applyRoot(hostSet.$firstAppHost);
71
- else if (selector === '$lastAppHost') applyRoot(hostSet.$lastAppHost);
72
- else if (selector === '$hosts') hostSet.$hosts.forEach(applyRoot);
73
- else if (selector === '$appHosts') hostSet.$appHosts.forEach(applyRoot);
74
- else {
75
- const targetRoot = r === 'auto' ? (host.shadowRoot || host) : (r === 'shadow' ? host.shadowRoot : host);
76
- if (targetRoot) {
77
- const found = targetRoot.querySelectorAll(selector);
78
- if (found) targetEls.push(...(Array.from(found) as HTMLElement[]));
79
- }
80
- }
81
-
82
- targetEls.forEach(targetEl => {
83
- if (finalOptions.filter && !finalOptions.filter(targetEl, resolvedValue, {currentThis: this, helper: hostSet})) {
84
- return;
85
- }
86
- const resolvedRes = typeof resolvedValue === 'function' ? (resolvedValue as any)(targetEl, hostSet) : resolvedValue;
87
-
88
- if (action === 'set' || action === 'update') {
89
- if (attributeName) {
90
- // Case: @setAttribute(selector, 'name')
91
- if (resolvedRes === null || resolvedRes === undefined || resolvedRes === false) {
92
- targetEl.removeAttribute(attributeName);
93
- } else {
94
- targetEl.setAttribute(attributeName, resolvedRes === true ? '' : String(resolvedRes));
95
- }
96
- } else if (typeof resolvedRes === 'object' && resolvedRes !== null && !Array.isArray(resolvedRes)) {
97
- // Case: @applyAttribute(selector) with Object return
98
- Object.entries(resolvedRes as any).forEach(([attr, val]) => {
99
- const finalVal = typeof val === 'function' ? val(targetEl, hostSet) : val;
100
- if (finalVal === null || finalVal === undefined || finalVal === false) {
101
- targetEl.removeAttribute(attr);
102
- } else {
103
- targetEl.setAttribute(attr, finalVal === true ? '' : String(finalVal));
104
- }
105
- });
106
- }
107
- } else if (action === 'remove') {
108
- if (attributeName) {
109
- targetEl.removeAttribute(attributeName);
110
- } else if (typeof resolvedRes === 'object' && resolvedRes !== null && !Array.isArray(resolvedRes)) {
111
- Object.entries(resolvedRes as any).forEach(([attr, val]) => {
112
- const shouldRemove = typeof val === 'function' ? val(targetEl, hostSet) : !!val;
113
- if (shouldRemove) targetEl.removeAttribute(attr);
114
- });
115
- } else {
116
- const attrs = Array.isArray(resolvedRes) ? resolvedRes : [resolvedRes];
117
- attrs.forEach(a => targetEl.removeAttribute(String(a)));
118
- }
119
- }
120
- });
121
- }
122
- return resolvedValue;
123
- };
124
-
125
213
  if (res instanceof Promise) {
126
- return res.then(handleResult);
214
+ return res.then((v: any) => {
215
+ applyValueToTargets(this, v);
216
+ return v;
217
+ });
127
218
  } else {
128
- return handleResult(res);
219
+ applyValueToTargets(this, res);
220
+ return res;
129
221
  }
130
222
  };
131
- return descriptor;
132
- };
223
+ return;
224
+ }
225
+
226
+ // Property decorator: define getter/setter to proxy to element attributes
227
+ Object.defineProperty(target, propertyKey, {
228
+ configurable: true,
229
+ enumerable: true,
230
+ get(this: any) {
231
+ ensureInit(this);
232
+ const mergedOptions = {...finalOptions, selector, type: finalOptions.type || designType};
233
+ return getAttributeValue(this, targetAttributeName, mergedOptions);
234
+ },
235
+ set(this: any, value: any) {
236
+ ensureInit(this);
237
+
238
+ if (value instanceof Promise) {
239
+ value.then((v: any) => applyValueToTargets(this, v)).catch(() => { /* swallow */
240
+ });
241
+ } else {
242
+ applyValueToTargets(this, value);
243
+ }
244
+ }
245
+ });
133
246
  };
134
247
  }
135
248
 
136
- export function applyAttribute(selector: string, action: AttributeAction = 'update', options: AttributeApplyOptions = {}): MethodDecorator {
137
- return createAttributeDecorator(action)(selector, options);
249
+ // ============================================
250
+ // Convenience Aliases
251
+ // ============================================
252
+
253
+ /**
254
+ * @attribute - Alias for @applyAttribute
255
+ */
256
+ export function attribute(selector: string, targetAttributeName: string, options?: AttributeOptions): MethodDecorator & PropertyDecorator;
257
+ export function attribute(selector: string, options?: AttributeOptions): MethodDecorator & PropertyDecorator;
258
+ export function attribute(selector: string, targetAttributeNameOrOptions?: string | AttributeOptions, options?: AttributeOptions): MethodDecorator & PropertyDecorator {
259
+ return applyAttribute(selector, targetAttributeNameOrOptions as any, options);
138
260
  }
139
261
 
140
- export const setAttribute = (selector: string, nameOrOptions?: string | AttributeApplyOptions, options: AttributeApplyOptions = {}) => createAttributeDecorator('set')(selector, nameOrOptions, options);
141
- export const updateAttribute = (selector: string, nameOrOptions?: string | AttributeApplyOptions, options: AttributeApplyOptions = {}) => createAttributeDecorator('update')(selector, nameOrOptions, options);
142
- export const removeAttribute = (selector: string, nameOrOptions?: string | AttributeApplyOptions, options: AttributeApplyOptions = {}) => createAttributeDecorator('remove')(selector, nameOrOptions, options);
262
+ /**
263
+ * @attributeThis - Apply attribute on $this element
264
+ * Can be used as: @attributeThis or @attributeThis('attrName') or @attributeThis({ name: 'attrName' })
265
+ */
266
+ export function attributeThis(target: Object, propertyKey: string | symbol): void;
267
+ export function attributeThis(targetAttributeName: string, options?: AttributeOptions): MethodDecorator & PropertyDecorator;
268
+ export function attributeThis(options?: AttributeOptions): MethodDecorator & PropertyDecorator;
269
+ export function attributeThis(targetOrOptions?: any, propertyKeyOrOptions?: any, descriptor?: PropertyDescriptor): any {
270
+ // Direct decorator usage: @attributeThis
271
+ if (typeof targetOrOptions === 'object' && targetOrOptions !== null && !Array.isArray(targetOrOptions) &&
272
+ typeof propertyKeyOrOptions === 'string' || typeof propertyKeyOrOptions === 'symbol') {
273
+ // Called as @attributeThis (target, propertyKey)
274
+ return applyAttribute('$this', undefined as any, {})(targetOrOptions, propertyKeyOrOptions, descriptor);
275
+ }
143
276
 
144
- // This versions
145
- export function applyAttributeThis(action: AttributeAction = 'update', options: AttributeApplyOptions = {}): MethodDecorator {
146
- return createAttributeDecorator(action)('$this', options);
277
+ // Called with parameters
278
+ if (typeof targetOrOptions === 'string') {
279
+ // @attributeThis('attrName', options?)
280
+ return applyAttribute('$this', targetOrOptions, propertyKeyOrOptions);
281
+ } else if (targetOrOptions && typeof targetOrOptions === 'object') {
282
+ // @attributeThis({ name: 'attrName' })
283
+ return applyAttribute('$this', undefined as any, targetOrOptions);
284
+ } else {
285
+ // @attributeThis() or @attributeThis
286
+ return applyAttribute('$this', undefined as any, {});
287
+ }
147
288
  }
148
- export const setAttributeThis = (nameOrOptions: string | AttributeApplyOptions, options: AttributeApplyOptions = {}) => createAttributeDecorator('set')('$this', nameOrOptions, options);
149
- export const updateAttributeThis = (nameOrOptions: string | AttributeApplyOptions, options: AttributeApplyOptions = {}) => createAttributeDecorator('update')('$this', nameOrOptions, options);
150
- export const removeAttributeThis = (nameOrOptions?: string | AttributeApplyOptions, options: AttributeApplyOptions = {}) => createAttributeDecorator('remove')('$this', nameOrOptions, options);
151
-
152
- export const findAllAttributeApplyMetadata = (target: any): Map<string | symbol, AttributeApplyMetadata> => {
153
- const result = new Map<string | symbol, AttributeApplyMetadata>();
154
- const maps = ReflectUtils.findAllMetadata<Map<string | symbol, AttributeApplyMetadata>>(ATTRIBUTE_APPLY_METADATA_KEY, target);
155
- maps.forEach(map => {
156
- if (map instanceof Map) {
157
- map.forEach((v, k) => result.set(k, v));
158
- }
289
+
290
+ /**
291
+ * @setAttribute - Alias for @applyAttribute (method-decorator semantics)
292
+ */
293
+ export function setAttribute(selector: string, targetAttributeName: string, options?: AttributeOptions): MethodDecorator;
294
+ export function setAttribute(selector: string, options?: AttributeOptions): MethodDecorator;
295
+ export function setAttribute(selector: string, targetAttributeNameOrOptions?: string | AttributeOptions, options?: AttributeOptions): MethodDecorator {
296
+ return applyAttribute(selector, targetAttributeNameOrOptions as any, options) as MethodDecorator;
297
+ }
298
+
299
+ /**
300
+ * @setAttributeThis - Set attribute on $this element
301
+ * Can be used as: @setAttributeThis or @setAttributeThis('attrName') or @setAttributeThis({ name: 'attrName' })
302
+ */
303
+ export function setAttributeThis(target: Object, propertyKey: string | symbol): void;
304
+ export function setAttributeThis(targetAttributeName: string, options?: AttributeOptions): MethodDecorator;
305
+ export function setAttributeThis(options?: AttributeOptions): MethodDecorator;
306
+ export function setAttributeThis(targetOrOptions?: any, propertyKeyOrOptions?: any, descriptor?: PropertyDescriptor): any {
307
+ // Direct decorator usage: @setAttributeThis
308
+ if (typeof targetOrOptions === 'object' && targetOrOptions !== null && !Array.isArray(targetOrOptions) &&
309
+ (typeof propertyKeyOrOptions === 'string' || typeof propertyKeyOrOptions === 'symbol')) {
310
+ // Called as @setAttributeThis (target, propertyKey)
311
+ return applyAttribute('$this', undefined as any, {})(targetOrOptions, propertyKeyOrOptions, descriptor);
312
+ }
313
+
314
+ // Called with parameters
315
+ if (typeof targetOrOptions === 'string') {
316
+ // @setAttributeThis('attrName', options?)
317
+ return applyAttribute('$this', targetOrOptions, propertyKeyOrOptions) as MethodDecorator;
318
+ } else if (targetOrOptions && typeof targetOrOptions === 'object') {
319
+ // @setAttributeThis({ name: 'attrName' })
320
+ return applyAttribute('$this', undefined as any, targetOrOptions) as MethodDecorator;
321
+ } else {
322
+ // @setAttributeThis() or @setAttributeThis
323
+ return applyAttribute('$this', undefined as any, {}) as MethodDecorator;
324
+ }
325
+ }
326
+
327
+ // ============================================
328
+ // Metadata Helpers
329
+ // ============================================
330
+
331
+ export const findAllAttributeMetadata = (target: any): AttributeMetadata[] => {
332
+ const actualTarget = target instanceof Function ? target : target.constructor;
333
+ return ReflectUtils.findAllMetadata<AttributeMetadata[]>(ATTRIBUTE_METADATA_KEY, actualTarget).flat();
334
+ };
335
+
336
+ // Backward compatibility alias
337
+ export const findAllAttributeApplyMetadata = (target: any): Map<string | symbol, AttributeMetadata> => {
338
+ const result = new Map<string | symbol, AttributeMetadata>();
339
+ findAllAttributeMetadata(target).forEach(meta => {
340
+ result.set(meta.propertyKey, meta);
159
341
  });
160
342
  return result;
161
343
  };
344
+
345
+
346
+ export default applyAttribute;