@dooboostore/simple-web-component 1.0.39 → 1.0.41
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.
- package/LICENSE.md +7 -0
- package/README.md +235 -47
- package/dist/cjs/SwcAppEngine.js.map +2 -2
- package/dist/cjs/decorators/applyAttribute.js +194 -111
- package/dist/cjs/decorators/applyAttribute.js.map +2 -2
- package/dist/cjs/decorators/applyNode.js +58 -43
- package/dist/cjs/decorators/applyNode.js.map +2 -2
- package/dist/cjs/decorators/applyProperty.js +213 -0
- package/dist/cjs/decorators/applyProperty.js.map +7 -0
- package/dist/cjs/decorators/applySlot.js +32 -26
- package/dist/cjs/decorators/applySlot.js.map +2 -2
- package/dist/cjs/decorators/changedAttributeThis.js.map +1 -1
- package/dist/cjs/decorators/elementDefine.js +17 -30
- package/dist/cjs/decorators/elementDefine.js.map +2 -2
- package/dist/cjs/decorators/index.js +2 -2
- package/dist/cjs/decorators/index.js.map +2 -2
- package/dist/cjs/decorators/lifecycles.js +4 -4
- package/dist/cjs/decorators/lifecycles.js.map +2 -2
- package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js +9 -3
- package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +2 -2
- package/dist/cjs/elements/SwcApp.js.map +2 -2
- package/dist/cjs/elements/SwcAppMixin.js +11 -4
- package/dist/cjs/elements/SwcAppMixin.js.map +2 -2
- package/dist/cjs/types/index.js.map +1 -1
- package/dist/esm/SwcAppEngine.js.map +2 -2
- package/dist/esm/decorators/applyAttribute.js +196 -113
- package/dist/esm/decorators/applyAttribute.js.map +2 -2
- package/dist/esm/decorators/applyNode.js +58 -43
- package/dist/esm/decorators/applyNode.js.map +2 -2
- package/dist/esm/decorators/applyProperty.js +194 -0
- package/dist/esm/decorators/applyProperty.js.map +7 -0
- package/dist/esm/decorators/applySlot.js +32 -26
- package/dist/esm/decorators/applySlot.js.map +2 -2
- package/dist/esm/decorators/changedAttributeThis.js.map +1 -1
- package/dist/esm/decorators/elementDefine.js +17 -30
- package/dist/esm/decorators/elementDefine.js.map +2 -2
- package/dist/esm/decorators/index.js +2 -2
- package/dist/esm/decorators/index.js.map +1 -1
- package/dist/esm/decorators/lifecycles.js +4 -4
- package/dist/esm/decorators/lifecycles.js.map +2 -2
- package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js +9 -3
- package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +2 -2
- package/dist/esm/elements/SwcApp.js.map +2 -2
- package/dist/esm/elements/SwcAppMixin.js +11 -4
- package/dist/esm/elements/SwcAppMixin.js.map +2 -2
- package/dist/esm/types/index.js.map +1 -1
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +441 -401
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
- package/dist/types/SwcAppEngine.d.ts.map +1 -1
- package/dist/types/decorators/applyAttribute.d.ts +56 -15
- package/dist/types/decorators/applyAttribute.d.ts.map +1 -1
- package/dist/types/decorators/applyNode.d.ts +28 -24
- package/dist/types/decorators/applyNode.d.ts.map +1 -1
- package/dist/types/decorators/applyProperty.d.ts +61 -0
- package/dist/types/decorators/applyProperty.d.ts.map +1 -0
- package/dist/types/decorators/applySlot.d.ts +10 -10
- package/dist/types/decorators/applySlot.d.ts.map +1 -1
- package/dist/types/decorators/elementDefine.d.ts.map +1 -1
- package/dist/types/decorators/index.d.ts +2 -2
- package/dist/types/decorators/index.d.ts.map +1 -1
- package/dist/types/decorators/lifecycles.d.ts +4 -4
- package/dist/types/decorators/lifecycles.d.ts.map +1 -1
- package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts +2 -0
- package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts.map +1 -1
- package/dist/types/elements/SwcApp.d.ts.map +1 -1
- package/dist/types/elements/SwcAppMixin.d.ts.map +1 -1
- package/dist/types/types/index.d.ts +1 -6
- package/dist/types/types/index.d.ts.map +1 -1
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +441 -401
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
- package/package.json +3 -3
- package/src/SwcAppEngine.ts +1 -0
- package/src/decorators/applyAttribute.ts +311 -126
- package/src/decorators/applyNode.ts +68 -57
- package/src/decorators/applyProperty.ts +302 -0
- package/src/decorators/applySlot.ts +25 -18
- package/src/decorators/changedAttributeThis.ts +1 -1
- package/src/decorators/elementDefine.ts +41 -30
- package/src/decorators/index.ts +2 -3
- package/src/decorators/lifecycles.ts +6 -6
- package/src/decorators/subscribeSwcAppRouteChangeWhileConnected.ts +14 -4
- package/src/elements/SwcApp.ts +0 -1
- package/src/elements/SwcAppMixin.ts +16 -4
- package/src/types/index.ts +7 -7
- package/dist/cjs/decorators/attribute.js +0 -187
- package/dist/cjs/decorators/attribute.js.map +0 -7
- package/dist/cjs/decorators/setProperty.js +0 -109
- package/dist/cjs/decorators/setProperty.js.map +0 -7
- package/dist/esm/decorators/attribute.js +0 -168
- package/dist/esm/decorators/attribute.js.map +0 -7
- package/dist/esm/decorators/setProperty.js +0 -90
- package/dist/esm/decorators/setProperty.js.map +0 -7
- package/dist/types/decorators/attribute.d.ts +0 -31
- package/dist/types/decorators/attribute.d.ts.map +0 -1
- package/dist/types/decorators/setProperty.d.ts +0 -17
- package/dist/types/decorators/setProperty.d.ts.map +0 -1
- package/src/decorators/attribute.ts +0 -223
- 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.
|
|
3
|
+
"version": "1.0.41",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -92,10 +92,10 @@
|
|
|
92
92
|
"webpack": "^5.93.0",
|
|
93
93
|
"webpack-cli": "^5.1.4",
|
|
94
94
|
"webpack-dev-server": "^5.2.0",
|
|
95
|
+
"@dooboostore/core": "1.0.32",
|
|
95
96
|
"@dooboostore/core-node": "1.0.12",
|
|
96
97
|
"@dooboostore/core-web": "1.0.12",
|
|
97
|
-
"@dooboostore/simple-boot": "1.0.56"
|
|
98
|
-
"@dooboostore/core": "1.0.32"
|
|
98
|
+
"@dooboostore/simple-boot": "1.0.56"
|
|
99
99
|
},
|
|
100
100
|
"scripts": {
|
|
101
101
|
"clean": "rm -rf dist",
|
package/src/SwcAppEngine.ts
CHANGED
|
@@ -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 {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
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
|
-
|
|
7
|
+
// ============================================
|
|
8
|
+
// Types & Interfaces
|
|
9
|
+
// ============================================
|
|
7
10
|
|
|
8
|
-
export interface
|
|
11
|
+
export interface AttributeOptions extends SwcQueryOptions {
|
|
9
12
|
name?: string;
|
|
10
|
-
|
|
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
|
|
17
|
+
export interface AttributeMetadata {
|
|
14
18
|
propertyKey: string | symbol;
|
|
15
19
|
selector: string;
|
|
16
|
-
|
|
17
|
-
options:
|
|
20
|
+
targetAttributeName: string;
|
|
21
|
+
options: AttributeOptions;
|
|
22
|
+
type: 'property' | 'method';
|
|
18
23
|
}
|
|
19
24
|
|
|
20
|
-
export const
|
|
25
|
+
export const ATTRIBUTE_METADATA_KEY = Symbol.for('simple-web-component:attribute');
|
|
21
26
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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(
|
|
214
|
+
return res.then((v: any) => {
|
|
215
|
+
applyValueToTargets(this, v);
|
|
216
|
+
return v;
|
|
217
|
+
});
|
|
127
218
|
} else {
|
|
128
|
-
|
|
219
|
+
applyValueToTargets(this, res);
|
|
220
|
+
return res;
|
|
129
221
|
}
|
|
130
222
|
};
|
|
131
|
-
return
|
|
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
|
-
|
|
137
|
-
|
|
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
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
//
|
|
145
|
-
|
|
146
|
-
|
|
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
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
export
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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;
|