@dooboostore/simple-web-component 1.0.21 → 1.0.22
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/README.md +771 -95
- package/dist/cjs/decorators/addEventListener.js +4 -0
- package/dist/cjs/decorators/addEventListener.js.map +2 -2
- package/dist/cjs/decorators/{appendChild.js → applyNode.js} +25 -17
- package/dist/cjs/decorators/applyNode.js.map +7 -0
- package/dist/cjs/decorators/attribute.js +31 -10
- package/dist/cjs/decorators/attribute.js.map +3 -3
- package/dist/cjs/decorators/{changedAttribute.js → changedAttributeHost.js} +6 -6
- package/dist/cjs/decorators/changedAttributeHost.js.map +7 -0
- package/dist/cjs/decorators/classList.js +11 -1
- package/dist/cjs/decorators/classList.js.map +2 -2
- package/dist/cjs/decorators/elementDefine.js +106 -55
- package/dist/cjs/decorators/elementDefine.js.map +2 -2
- package/dist/cjs/decorators/emitCustomEvent.js +4 -3
- package/dist/cjs/decorators/emitCustomEvent.js.map +2 -2
- package/dist/cjs/decorators/index.js +2 -3
- package/dist/cjs/decorators/index.js.map +2 -2
- package/dist/cjs/decorators/lifecycles.js +4 -0
- package/dist/cjs/decorators/lifecycles.js.map +2 -2
- package/dist/cjs/decorators/query.js +5 -1
- package/dist/cjs/decorators/query.js.map +2 -2
- package/dist/cjs/decorators/queryAll.js +5 -1
- package/dist/cjs/decorators/queryAll.js.map +2 -2
- package/dist/cjs/decorators/setAttribute.js +5 -1
- package/dist/cjs/decorators/setAttribute.js.map +2 -2
- package/dist/cjs/elements/SwcAppEngine.js.map +2 -2
- package/dist/cjs/elements/SwcAppMixin.js.map +2 -2
- package/dist/cjs/elements/SwcAsync.js +2 -2
- package/dist/cjs/elements/SwcAsync.js.map +2 -2
- package/dist/cjs/elements/SwcChoose.js +2 -2
- package/dist/cjs/elements/SwcChoose.js.map +2 -2
- package/dist/cjs/elements/SwcIf.js +2 -2
- package/dist/cjs/elements/SwcIf.js.map +2 -2
- package/dist/cjs/elements/SwcLoop.js +2 -2
- package/dist/cjs/elements/SwcLoop.js.map +2 -2
- package/dist/cjs/elements/register.js +6 -5
- package/dist/cjs/elements/register.js.map +2 -2
- package/dist/cjs/index.js +6 -18
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/types.js.map +2 -2
- package/dist/esm/decorators/addEventListener.js +4 -0
- package/dist/esm/decorators/addEventListener.js.map +2 -2
- package/dist/esm/decorators/{appendChild.js → applyNode.js} +22 -14
- package/dist/esm/decorators/applyNode.js.map +7 -0
- package/dist/esm/decorators/attribute.js +31 -10
- package/dist/esm/decorators/attribute.js.map +3 -3
- package/dist/esm/decorators/{changedAttribute.js → changedAttributeHost.js} +3 -3
- package/dist/esm/decorators/changedAttributeHost.js.map +7 -0
- package/dist/esm/decorators/classList.js +11 -1
- package/dist/esm/decorators/classList.js.map +2 -2
- package/dist/esm/decorators/elementDefine.js +106 -55
- package/dist/esm/decorators/elementDefine.js.map +2 -2
- package/dist/esm/decorators/emitCustomEvent.js +4 -3
- package/dist/esm/decorators/emitCustomEvent.js.map +2 -2
- package/dist/esm/decorators/index.js +2 -3
- package/dist/esm/decorators/index.js.map +2 -2
- package/dist/esm/decorators/lifecycles.js +4 -0
- package/dist/esm/decorators/lifecycles.js.map +2 -2
- package/dist/esm/decorators/query.js +5 -1
- package/dist/esm/decorators/query.js.map +2 -2
- package/dist/esm/decorators/queryAll.js +5 -1
- package/dist/esm/decorators/queryAll.js.map +2 -2
- package/dist/esm/decorators/setAttribute.js +5 -1
- package/dist/esm/decorators/setAttribute.js.map +2 -2
- package/dist/esm/elements/SwcAppEngine.js.map +2 -2
- package/dist/esm/elements/SwcAppMixin.js.map +2 -2
- package/dist/esm/elements/SwcAsync.js +2 -2
- package/dist/esm/elements/SwcAsync.js.map +2 -2
- package/dist/esm/elements/SwcChoose.js +2 -2
- package/dist/esm/elements/SwcChoose.js.map +2 -2
- package/dist/esm/elements/SwcIf.js +2 -2
- package/dist/esm/elements/SwcIf.js.map +2 -2
- package/dist/esm/elements/SwcLoop.js +2 -2
- package/dist/esm/elements/SwcLoop.js.map +2 -2
- package/dist/esm/elements/register.js +6 -5
- package/dist/esm/elements/register.js.map +2 -2
- package/dist/esm/index.js +6 -18
- package/dist/esm/index.js.map +2 -2
- package/dist/esm/types.js.map +2 -2
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +195 -139
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
- package/dist/types/decorators/addEventListener.d.ts +6 -0
- package/dist/types/decorators/addEventListener.d.ts.map +1 -1
- package/dist/types/decorators/applyNode.d.ts +38 -0
- package/dist/types/decorators/applyNode.d.ts.map +1 -0
- package/dist/types/decorators/attribute.d.ts +6 -0
- package/dist/types/decorators/attribute.d.ts.map +1 -1
- package/dist/types/decorators/{changedAttribute.d.ts → changedAttributeHost.d.ts} +6 -2
- package/dist/types/decorators/changedAttributeHost.d.ts.map +1 -0
- package/dist/types/decorators/classList.d.ts +25 -0
- package/dist/types/decorators/classList.d.ts.map +1 -1
- package/dist/types/decorators/elementDefine.d.ts.map +1 -1
- package/dist/types/decorators/emitCustomEvent.d.ts +14 -2
- package/dist/types/decorators/emitCustomEvent.d.ts.map +1 -1
- package/dist/types/decorators/index.d.ts +2 -3
- package/dist/types/decorators/index.d.ts.map +1 -1
- package/dist/types/decorators/lifecycles.d.ts +2 -0
- package/dist/types/decorators/lifecycles.d.ts.map +1 -1
- package/dist/types/decorators/query.d.ts +6 -0
- package/dist/types/decorators/query.d.ts.map +1 -1
- package/dist/types/decorators/queryAll.d.ts +6 -0
- package/dist/types/decorators/queryAll.d.ts.map +1 -1
- package/dist/types/decorators/setAttribute.d.ts +5 -0
- package/dist/types/decorators/setAttribute.d.ts.map +1 -1
- package/dist/types/elements/SwcAppEngine.d.ts.map +1 -1
- package/dist/types/elements/SwcAppMixin.d.ts.map +1 -1
- package/dist/types/elements/register.d.ts +1 -1
- package/dist/types/elements/register.d.ts.map +1 -1
- package/dist/types/index.d.ts +3 -15
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/types.d.ts +2 -1
- package/dist/types/types.d.ts.map +1 -1
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +195 -139
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
- package/package.json +3 -3
- package/src/decorators/addEventListener.ts +9 -0
- package/src/decorators/applyNode.ts +127 -0
- package/src/decorators/attribute.ts +46 -12
- package/src/decorators/{changedAttribute.ts → changedAttributeHost.ts} +5 -1
- package/src/decorators/classList.ts +32 -0
- package/src/decorators/elementDefine.ts +130 -62
- package/src/decorators/emitCustomEvent.ts +13 -5
- package/src/decorators/index.ts +2 -3
- package/src/decorators/lifecycles.ts +3 -1
- package/src/decorators/query.ts +9 -0
- package/src/decorators/queryAll.ts +9 -0
- package/src/decorators/setAttribute.ts +8 -0
- package/src/elements/SwcAppEngine.ts +1 -0
- package/src/elements/SwcAppMixin.ts +2 -1
- package/src/elements/SwcAsync.ts +2 -2
- package/src/elements/SwcChoose.ts +2 -2
- package/src/elements/SwcIf.ts +2 -2
- package/src/elements/SwcLoop.ts +2 -2
- package/src/elements/register.ts +7 -5
- package/src/index.ts +8 -17
- package/src/types.ts +2 -1
- package/dist/cjs/decorators/appendChild.js.map +0 -7
- package/dist/cjs/decorators/changedAttribute.js.map +0 -7
- package/dist/cjs/decorators/replaceChildren.js +0 -79
- package/dist/cjs/decorators/replaceChildren.js.map +0 -7
- package/dist/esm/decorators/appendChild.js.map +0 -7
- package/dist/esm/decorators/changedAttribute.js.map +0 -7
- package/dist/esm/decorators/replaceChildren.js +0 -60
- package/dist/esm/decorators/replaceChildren.js.map +0 -7
- package/dist/types/decorators/appendChild.d.ts +0 -17
- package/dist/types/decorators/appendChild.d.ts.map +0 -1
- package/dist/types/decorators/changedAttribute.d.ts.map +0 -1
- package/dist/types/decorators/replaceChildren.d.ts +0 -9
- package/dist/types/decorators/replaceChildren.d.ts.map +0 -1
- package/src/decorators/appendChild.ts +0 -86
- package/src/decorators/replaceChildren.ts +0 -64
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.22",
|
|
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-web": "1.0.10",
|
|
95
96
|
"@dooboostore/core": "1.0.30",
|
|
96
97
|
"@dooboostore/core-node": "1.0.12",
|
|
97
|
-
"@dooboostore/simple-boot": "1.0.54"
|
|
98
|
-
"@dooboostore/core-web": "1.0.10"
|
|
98
|
+
"@dooboostore/simple-boot": "1.0.54"
|
|
99
99
|
},
|
|
100
100
|
"scripts": {
|
|
101
101
|
"clean": "rm -rf dist",
|
|
@@ -44,3 +44,12 @@ export const getAddEventListenerMetadata = (target: any): AddEventListenerMetada
|
|
|
44
44
|
const constructor = target instanceof Function ? target : target.constructor;
|
|
45
45
|
return ReflectUtils.getMetadata(ADD_EVENT_LISTENER_METADATA_KEY, constructor);
|
|
46
46
|
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @addEventListenerHost decorator - simplified version of @addEventListener for :host selector
|
|
50
|
+
* Usage: @addEventListenerHost('click')
|
|
51
|
+
* Usage: @addEventListenerHost('click', { stopPropagation: true })
|
|
52
|
+
*/
|
|
53
|
+
export function addEventListenerHost(type: string, options?: AddEventListenerBaseOptions & SwcQueryOptions): MethodDecorator {
|
|
54
|
+
return addEventListener(':host', type, options);
|
|
55
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { ReflectUtils } from '@dooboostore/core';
|
|
2
|
+
import { ensureInit, getElementConfig } from './elementDefine';
|
|
3
|
+
|
|
4
|
+
export type ApplyNodePosition = 'beforeBegin' | 'afterBegin' | 'beforeEnd' | 'afterEnd' | 'replace' | 'replaceChildren' | 'innerHtml' | 'innerText';
|
|
5
|
+
|
|
6
|
+
export interface ApplyNodeOptions {
|
|
7
|
+
position?: ApplyNodePosition;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ApplyNodeMetadata {
|
|
11
|
+
propertyKey: string | symbol;
|
|
12
|
+
selector: string;
|
|
13
|
+
options: ApplyNodeOptions;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const APPLY_NODE_METADATA_KEY = Symbol('simple-web-component:apply-node');
|
|
17
|
+
|
|
18
|
+
const normalizeNodes = (res: any, doc: Document): Node[] => {
|
|
19
|
+
const items = Array.isArray(res) ? res : [res];
|
|
20
|
+
return items.map(it => {
|
|
21
|
+
if (it instanceof Node) return it;
|
|
22
|
+
return doc.createTextNode(it !== undefined && it !== null ? String(it) : '');
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @applyNode decorator to surgically add/replace nodes to a target element.
|
|
28
|
+
*
|
|
29
|
+
* Usage examples:
|
|
30
|
+
* @applyNode('#list') addItem() { return '<li>New Item</li>'; } // append at end
|
|
31
|
+
* @applyNode('#header', { position: 'afterBegin' }) prependItem() { return '<h1>Title</h1>'; } // prepend at start
|
|
32
|
+
* @applyNode('#item', { position: 'replace' }) replaceItem() { return '<div>Replaced</div>'; } // replace element
|
|
33
|
+
* @applyNode('#list', { position: 'replaceChildren' }) updateList() { return [item1, item2]; } // replace all children
|
|
34
|
+
*
|
|
35
|
+
* Positions:
|
|
36
|
+
* - 'beforeEnd' (default): Append at end of target
|
|
37
|
+
* - 'afterBegin': Prepend at start of target
|
|
38
|
+
* - 'beforeBegin': Insert before target
|
|
39
|
+
* - 'afterEnd': Insert after target
|
|
40
|
+
* - 'replace': Replace the entire target element
|
|
41
|
+
* - 'replaceChildren': Replace all children of target element
|
|
42
|
+
* - 'innerHtml': Set target's innerHTML
|
|
43
|
+
* - 'innerText': Set target's innerText
|
|
44
|
+
*/
|
|
45
|
+
export function applyNode(selector: string, options: ApplyNodeOptions = { position: 'beforeEnd' }): MethodDecorator {
|
|
46
|
+
return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
|
|
47
|
+
const constructor = target.constructor;
|
|
48
|
+
let metaList = ReflectUtils.getOwnMetadata(APPLY_NODE_METADATA_KEY, constructor) as Map<string | symbol, ApplyNodeMetadata>;
|
|
49
|
+
if (!metaList) {
|
|
50
|
+
metaList = new Map<string | symbol, ApplyNodeMetadata>();
|
|
51
|
+
ReflectUtils.defineMetadata(APPLY_NODE_METADATA_KEY, metaList, constructor);
|
|
52
|
+
}
|
|
53
|
+
metaList.set(propertyKey, { propertyKey, selector, options });
|
|
54
|
+
|
|
55
|
+
const original = descriptor.value;
|
|
56
|
+
descriptor.value = async function (...args: any[]) {
|
|
57
|
+
ensureInit(this);
|
|
58
|
+
const res = await original.apply(this, args);
|
|
59
|
+
if (res !== undefined) {
|
|
60
|
+
const conf = getElementConfig(this);
|
|
61
|
+
const currentWin = (this as any)._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as Window);
|
|
62
|
+
const currentDoc = currentWin.document;
|
|
63
|
+
|
|
64
|
+
let targetEl: HTMLElement | null = null;
|
|
65
|
+
if (selector === ':host' || !selector) {
|
|
66
|
+
targetEl = this as any;
|
|
67
|
+
} else {
|
|
68
|
+
targetEl = (this.shadowRoot || (this as any)).querySelector(selector);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (targetEl) {
|
|
72
|
+
const nodes = normalizeNodes(res, currentDoc);
|
|
73
|
+
const pos = options.position || 'beforeEnd';
|
|
74
|
+
|
|
75
|
+
if (pos === 'replace') {
|
|
76
|
+
// Replace the entire target element with new nodes
|
|
77
|
+
targetEl.replaceWith(...nodes);
|
|
78
|
+
} else if (pos === 'replaceChildren') {
|
|
79
|
+
// Replace all children of target element
|
|
80
|
+
targetEl.replaceChildren(...nodes);
|
|
81
|
+
} else if (pos === 'innerHtml') {
|
|
82
|
+
// Set innerHTML
|
|
83
|
+
targetEl.innerHTML = res !== undefined && res !== null ? String(res) : '';
|
|
84
|
+
} else if (pos === 'innerText') {
|
|
85
|
+
// Set innerText
|
|
86
|
+
targetEl.innerText = res !== undefined && res !== null ? String(res) : '';
|
|
87
|
+
} else {
|
|
88
|
+
/*
|
|
89
|
+
<!-- beforebegin -->
|
|
90
|
+
<p>
|
|
91
|
+
<!-- afterbegin -->
|
|
92
|
+
foo
|
|
93
|
+
<!-- beforeend -->
|
|
94
|
+
</p>
|
|
95
|
+
<!-- afterend -->
|
|
96
|
+
*/
|
|
97
|
+
if (pos === 'beforeEnd') targetEl.append(...nodes);
|
|
98
|
+
else if (pos === 'afterBegin') targetEl.prepend(...nodes);
|
|
99
|
+
else if (pos === 'beforeBegin') targetEl.before(...nodes);
|
|
100
|
+
else if (pos === 'afterEnd') targetEl.after(...nodes);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return res;
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export const findAllApplyNodeMetadata = (target: any): Map<string | symbol, ApplyNodeMetadata> => {
|
|
110
|
+
const result = new Map<string | symbol, ApplyNodeMetadata>();
|
|
111
|
+
const maps = ReflectUtils.findAllMetadata<Map<string | symbol, ApplyNodeMetadata>>(APPLY_NODE_METADATA_KEY, target);
|
|
112
|
+
maps.forEach(map => {
|
|
113
|
+
if (map instanceof Map) {
|
|
114
|
+
map.forEach((v, k) => result.set(k, v));
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
return result;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* @applyNodeHost decorator - simplified version of @applyNode for :host selector
|
|
122
|
+
* Usage: @applyNodeHost() addItem() { return '<li>New Item</li>'; }
|
|
123
|
+
* Usage: @applyNodeHost({ position: 'afterBegin' }) prependItem() { return '<h1>Title</h1>'; }
|
|
124
|
+
*/
|
|
125
|
+
export function applyNodeHost(options: ApplyNodeOptions = { position: 'beforeEnd' }): MethodDecorator {
|
|
126
|
+
return applyNode(':host', options);
|
|
127
|
+
}
|
|
@@ -99,6 +99,22 @@ export function attribute(selector: string, options: AttributeOptions = {}): Pro
|
|
|
99
99
|
}
|
|
100
100
|
metaList.push({ propertyKey, selector, options, privateKey });
|
|
101
101
|
|
|
102
|
+
// Helper function to apply setAttribute to targets
|
|
103
|
+
const applySetAttribute = (inst: any, targets: HTMLElement[], attrName: string, nv: any) => {
|
|
104
|
+
targets.forEach(it => {
|
|
105
|
+
console.log('----->', it)
|
|
106
|
+
if (it && typeof (it as any).setAttribute === 'function') {
|
|
107
|
+
if (nv === null) {
|
|
108
|
+
(it as any).removeAttribute(attrName);
|
|
109
|
+
} else {
|
|
110
|
+
(it as any).setAttribute(attrName, String(nv));
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
inst[privateKey] = nv;
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
|
|
102
118
|
Object.defineProperty(target, propertyKey, {
|
|
103
119
|
get(this: any) {
|
|
104
120
|
const attrName = options.name || String(propertyKey);
|
|
@@ -127,25 +143,34 @@ export function attribute(selector: string, options: AttributeOptions = {}): Pro
|
|
|
127
143
|
},
|
|
128
144
|
set(this: any, nv: any) {
|
|
129
145
|
const targetType = options.type || designType;
|
|
130
|
-
|
|
131
|
-
// console.log('---set', propertyKey, targetType, nv, convertedValue);
|
|
146
|
+
console.log('---set', propertyKey, targetType, nv, this, this.__swc_syncing_init);
|
|
132
147
|
|
|
133
148
|
const attrName = options.name || String(propertyKey);
|
|
134
149
|
const conf = getElementConfig(this);
|
|
135
150
|
const currentWin = this._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as any);
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
(it as any).setAttribute(attrName, String(nv));
|
|
144
|
-
}
|
|
151
|
+
|
|
152
|
+
// During initialization/syncing phase
|
|
153
|
+
if (this.__swc_syncing_init) {
|
|
154
|
+
// If connectedInitialize is enabled, force setAttribute (JS -> DOM)
|
|
155
|
+
if (options.connectedInitialize === true) {
|
|
156
|
+
const targets = resolveTargetEls(this, selector, options, currentWin);
|
|
157
|
+
applySetAttribute(this, targets, attrName, nv);
|
|
145
158
|
} else {
|
|
159
|
+
// Otherwise just update memory
|
|
146
160
|
this[privateKey] = nv;
|
|
147
161
|
}
|
|
148
|
-
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Before connected, save to memory only
|
|
166
|
+
if (!this.__swc_connected) {
|
|
167
|
+
this[privateKey] = nv;
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// After connected, normal setAttribute
|
|
172
|
+
const targets = resolveTargetEls(this, selector, options, currentWin);
|
|
173
|
+
applySetAttribute(this, targets, attrName, nv);
|
|
149
174
|
},
|
|
150
175
|
enumerable: true,
|
|
151
176
|
configurable: true
|
|
@@ -156,3 +181,12 @@ export function attribute(selector: string, options: AttributeOptions = {}): Pro
|
|
|
156
181
|
export const findAllAttributeMetadata = (target: any): AttributeMetadata[] => {
|
|
157
182
|
return ReflectUtils.findAllMetadata<AttributeMetadata[]>(ATTRIBUTE_METADATA_KEY, target).flat();
|
|
158
183
|
};
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* @hostAttribute decorator - simplified version of @attribute for :host selector
|
|
187
|
+
* Usage: @hostAttribute('data-product-id')
|
|
188
|
+
* Usage: @hostAttribute('disabled', { type: Boolean })
|
|
189
|
+
*/
|
|
190
|
+
export function attributeHost(attrName: string, options: AttributeOptions = {}): PropertyDecorator {
|
|
191
|
+
return attribute(':host', { ...options, name: attrName });
|
|
192
|
+
}
|
|
@@ -2,7 +2,11 @@ import { ReflectUtils } from '@dooboostore/core';
|
|
|
2
2
|
|
|
3
3
|
export const ON_ATTRIBUTE_CHANGED_METADATA_KEY = Symbol('simple-web-component:on-attribute-changed');
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* @changedAttributeHost decorator - fires when any attribute on :host changes
|
|
7
|
+
* Usage: @changedAttributeHost('data-product-id')
|
|
8
|
+
*/
|
|
9
|
+
export function changedAttributeHost(attributeName?: string): MethodDecorator {
|
|
6
10
|
return (target: Object, propertyKey: string | symbol) => {
|
|
7
11
|
const constructor = target.constructor;
|
|
8
12
|
let meta = ReflectUtils.getOwnMetadata(ON_ATTRIBUTE_CHANGED_METADATA_KEY, constructor) as Map<string, (string | symbol)[]>;
|
|
@@ -105,6 +105,38 @@ export const removeClassList = createClassListDecorator('remove');
|
|
|
105
105
|
*/
|
|
106
106
|
export const toggleClassList = createClassListDecorator('toggle');
|
|
107
107
|
|
|
108
|
+
// Host-specific versions (for :host selector)
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @setClassListHost decorator to set classes on :host element.
|
|
112
|
+
* Returns: string | string[]
|
|
113
|
+
*/
|
|
114
|
+
export const setClassListHost = createClassListDecorator('set').bind(null, ':host');
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* @updateClassListHost decorator to update specific classes on :host.
|
|
118
|
+
* Returns: Record<string, boolean> (toggle with force) | string | string[] (add)
|
|
119
|
+
*/
|
|
120
|
+
export const updateClassListHost = createClassListDecorator('update').bind(null, ':host');
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @addClassListHost decorator to add classes to :host element.
|
|
124
|
+
* Returns: string | string[]
|
|
125
|
+
*/
|
|
126
|
+
export const addClassListHost = createClassListDecorator('add').bind(null, ':host');
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* @removeClassListHost decorator to remove classes from :host element.
|
|
130
|
+
* Returns: string | string[]
|
|
131
|
+
*/
|
|
132
|
+
export const removeClassListHost = createClassListDecorator('remove').bind(null, ':host');
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* @toggleClassListHost decorator to toggle classes on :host element.
|
|
136
|
+
* Returns: string | string[]
|
|
137
|
+
*/
|
|
138
|
+
export const toggleClassListHost = createClassListDecorator('toggle').bind(null, ':host');
|
|
139
|
+
|
|
108
140
|
export const findAllClassListMetadata = (target: any): Map<string | symbol, ClassListMetadata> => {
|
|
109
141
|
const result = new Map<string | symbol, ClassListMetadata>();
|
|
110
142
|
const maps = ReflectUtils.findAllMetadata<Map<string | symbol, ClassListMetadata>>(CLASS_LIST_METADATA_KEY, target);
|
|
@@ -2,14 +2,10 @@ import { ReflectUtils } from '@dooboostore/core';
|
|
|
2
2
|
import { FunctionUtils } from '@dooboostore/core';
|
|
3
3
|
import { getOnConnectedInnerHtmlMetadata } from './onConnectedInnerHtml';
|
|
4
4
|
import { getAddEventListenerMetadata } from './addEventListener';
|
|
5
|
-
import { ON_BEFORE_CONNECTED_METADATA_KEY, ON_AFTER_CONNECTED_METADATA_KEY, ON_BEFORE_DISCONNECTED_METADATA_KEY, ON_AFTER_DISCONNECTED_METADATA_KEY, ON_BEFORE_ADOPTED_METADATA_KEY, ON_AFTER_ADOPTED_METADATA_KEY, findAllLifecycleMetadata } from './lifecycles';
|
|
5
|
+
import { ON_CONSTRUCTOR_METADATA_KEY, ON_BEFORE_CONNECTED_METADATA_KEY, ON_AFTER_CONNECTED_METADATA_KEY, ON_BEFORE_DISCONNECTED_METADATA_KEY, ON_AFTER_DISCONNECTED_METADATA_KEY, ON_BEFORE_ADOPTED_METADATA_KEY, ON_AFTER_ADOPTED_METADATA_KEY, findAllLifecycleMetadata } from './lifecycles';
|
|
6
6
|
import { getEmitCustomEventMetadataList } from './emitCustomEvent';
|
|
7
|
-
import { findAllAttributeChangedMetadata } from './
|
|
7
|
+
import { findAllAttributeChangedMetadata } from './changedAttributeHost';
|
|
8
8
|
import { findAllSetAttributeMetadata } from './setAttribute';
|
|
9
|
-
import { findAllReplaceChildrenMetadata } from './replaceChildren';
|
|
10
|
-
import { findAllAppendChildMetadata } from './appendChild';
|
|
11
|
-
import { findAllClassListMetadata } from './classList';
|
|
12
|
-
import { findAllStyleMetadata } from './style';
|
|
13
9
|
import { findAllAttributeMetadata } from './attribute';
|
|
14
10
|
import { SwcUtils } from '../utils/Utils';
|
|
15
11
|
import { HTML_TAG_ENTRIES, DOM_EVENT_NAMES } from '../config/config';
|
|
@@ -47,6 +43,12 @@ export const ensureInit = (inst: any) => {
|
|
|
47
43
|
// Call constructor script if present
|
|
48
44
|
const hostSet = SwcUtils.getHostSet(inst);
|
|
49
45
|
inst._executeSwcScript?.('swc-on-constructor', hostSet);
|
|
46
|
+
|
|
47
|
+
// Call @onConstructor lifecycle methods
|
|
48
|
+
const cMethods = findAllLifecycleMetadata(inst, ON_CONSTRUCTOR_METADATA_KEY);
|
|
49
|
+
if (cMethods) {
|
|
50
|
+
for (const m of cMethods) (inst)._invokeLifecycleMethod(m, hostSet);
|
|
51
|
+
}
|
|
50
52
|
}
|
|
51
53
|
};
|
|
52
54
|
|
|
@@ -160,7 +162,9 @@ const setupPrototype = (proto: any) => {
|
|
|
160
162
|
if (oldHandler) el.removeEventListener(eventName, oldHandler);
|
|
161
163
|
|
|
162
164
|
const handler = async (event: any) => {
|
|
163
|
-
|
|
165
|
+
console.log('execute handler', event);
|
|
166
|
+
const parent = SwcUtils.findNearestSwcHost(el);
|
|
167
|
+
const hostSet = SwcUtils.getHostSet(parent || el);
|
|
164
168
|
const conf = getElementConfig(this);
|
|
165
169
|
const currentWin = (this as any)._resolveWindow(conf);
|
|
166
170
|
const helpers = SwcUtils.getHelperSet(currentWin);
|
|
@@ -181,13 +185,19 @@ const setupPrototype = (proto: any) => {
|
|
|
181
185
|
|
|
182
186
|
proto.__swc_executeAttributeEvent = async function (el: HTMLElement, attrName: string, script: string, event: Event) {
|
|
183
187
|
ensureInit(this);
|
|
184
|
-
|
|
188
|
+
|
|
189
|
+
console.log('execute handler2', event);
|
|
190
|
+
const parent = SwcUtils.findNearestSwcHost(el);
|
|
191
|
+
const hostSet = SwcUtils.getHostSet(parent || el);
|
|
185
192
|
const conf = getElementConfig(this);
|
|
186
193
|
const currentWin = (this as any)._resolveWindow(conf);
|
|
187
194
|
const currentHelpers = SwcUtils.getHelperSet(currentWin);
|
|
195
|
+
const detail = (event as CustomEvent).detail;
|
|
188
196
|
const args = {
|
|
189
197
|
event,
|
|
190
|
-
$
|
|
198
|
+
$event: event,
|
|
199
|
+
$data: detail,
|
|
200
|
+
$detail: detail,
|
|
191
201
|
...hostSet,
|
|
192
202
|
...currentHelpers,
|
|
193
203
|
$el: el,
|
|
@@ -220,7 +230,9 @@ export const elementDefine =
|
|
|
220
230
|
}
|
|
221
231
|
|
|
222
232
|
const emitCustomEventList = getEmitCustomEventMetadataList(constructor) || [];
|
|
233
|
+
const emitHostCustomEventList = emitCustomEventList.filter(meta => meta.selector === ':host' || meta.selector === '');
|
|
223
234
|
const addEventListenerList = getAddEventListenerMetadata(constructor) || [];
|
|
235
|
+
const addHostEventListenerList = addEventListenerList.filter(meta => meta.selector === ':host' || meta.selector === '');
|
|
224
236
|
const attrChangeMap = findAllAttributeChangedMetadata(constructor);
|
|
225
237
|
const attributeList = findAllAttributeMetadata(constructor);
|
|
226
238
|
|
|
@@ -228,7 +240,7 @@ export const elementDefine =
|
|
|
228
240
|
const swcOnEvents = DOM_EVENT_NAMES.map(e => `swc-on-${e}`);
|
|
229
241
|
|
|
230
242
|
// Collect all observed attributes from all decorators
|
|
231
|
-
const mergedObservedAttributes = [...new Set([...(metadata.observedAttributes ?? []), ...attrChangeMap.keys(), ...Array.from(findAllSetAttributeMetadata(constructor).values()).map(it => it.name), ...attributeList.map(it => it.options.name || String(it.propertyKey)), ...
|
|
243
|
+
const mergedObservedAttributes = [...new Set([...(metadata.observedAttributes ?? []), ...attrChangeMap.keys(), ...Array.from(findAllSetAttributeMetadata(constructor).values()).map(it => it.name), ...attributeList.map(it => it.options.name || String(it.propertyKey)), ...emitHostCustomEventList.map(it => (it.options as any).attributeName).filter(Boolean), ...swcLifecycleAttributes, ...swcOnEvents])];
|
|
232
244
|
|
|
233
245
|
const connectedInnerHtmlList = getOnConnectedInnerHtmlMetadata(constructor) || [];
|
|
234
246
|
|
|
@@ -256,29 +268,19 @@ export const elementDefine =
|
|
|
256
268
|
// Initialize @attribute fields (DOM <-> JS Sync)
|
|
257
269
|
attributeList.forEach(meta => {
|
|
258
270
|
const attrName = meta.options.name || String(meta.propertyKey);
|
|
259
|
-
if (meta.options.connectedInitialize) {
|
|
260
|
-
// JS -> DOM (FORCE OVERWRITE)
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
(this as any).
|
|
264
|
-
|
|
271
|
+
if (meta.options.connectedInitialize === true) {
|
|
272
|
+
// JS -> DOM (FORCE OVERWRITE with JS value)
|
|
273
|
+
(this as any).__swc_syncing_init = true;
|
|
274
|
+
try {
|
|
275
|
+
const memoryVal = (this as any)[meta.privateKey];
|
|
276
|
+
if (memoryVal !== undefined) {
|
|
265
277
|
(this as any)[meta.propertyKey] = memoryVal; // Trigger setter to update DOM
|
|
266
|
-
} finally {
|
|
267
|
-
(this as any).__swc_syncing_init = false;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
} else if (meta.selector === ':host' || !meta.selector) {
|
|
271
|
-
// DOM -> JS (Pull from HTML)
|
|
272
|
-
const domVal = this.getAttribute(attrName);
|
|
273
|
-
if (domVal !== null) {
|
|
274
|
-
(this as any).__swc_syncing_init = true;
|
|
275
|
-
try {
|
|
276
|
-
(this as any)[meta.propertyKey] = domVal; // Update memory with DOM value
|
|
277
|
-
} finally {
|
|
278
|
-
(this as any).__swc_syncing_init = false;
|
|
279
278
|
}
|
|
279
|
+
} finally {
|
|
280
|
+
(this as any).__swc_syncing_init = false;
|
|
280
281
|
}
|
|
281
282
|
}
|
|
283
|
+
// else: Do NOT sync - Keep the default value from class initialization
|
|
282
284
|
});
|
|
283
285
|
|
|
284
286
|
if (connectedInnerHtmlList.length > 0) {
|
|
@@ -303,7 +305,76 @@ export const elementDefine =
|
|
|
303
305
|
globalDelegatedRoots.add(root);
|
|
304
306
|
}
|
|
305
307
|
|
|
308
|
+
// Separate delegate and non-delegate listeners
|
|
309
|
+
const delegateListeners: typeof addEventListenerList = [];
|
|
310
|
+
const nonDelegateListeners: typeof addEventListenerList = [];
|
|
311
|
+
|
|
306
312
|
addEventListenerList.forEach(meta => {
|
|
313
|
+
if (meta.options.delegate && meta.selector !== ':window' && meta.selector !== ':document' && meta.selector !== ':parentHost' && meta.selector !== ':appHost' && meta.selector !== ':firstHost' && meta.selector !== ':lastHost' && meta.selector !== ':firstAppHost' && meta.selector !== ':lastAppHost' && meta.selector !== ':hosts' && meta.selector !== ':appHosts' && meta.selector !== ':host' && meta.selector !== '') {
|
|
314
|
+
delegateListeners.push(meta);
|
|
315
|
+
} else {
|
|
316
|
+
nonDelegateListeners.push(meta);
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// Group delegate listeners by (type, root) combination
|
|
321
|
+
const delegatesByTypeAndRoot = new Map<string, any[]>();
|
|
322
|
+
delegateListeners.forEach(meta => {
|
|
323
|
+
const r = meta.options.root || 'auto';
|
|
324
|
+
const rootKey = `${meta.type}:${r}`;
|
|
325
|
+
if (!delegatesByTypeAndRoot.has(rootKey)) {
|
|
326
|
+
delegatesByTypeAndRoot.set(rootKey, []);
|
|
327
|
+
}
|
|
328
|
+
delegatesByTypeAndRoot.get(rootKey)!.push(meta);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
// Register unified handlers for delegate listeners
|
|
332
|
+
delegatesByTypeAndRoot.forEach((metaList, typeRootKey) => {
|
|
333
|
+
const [type, rStr] = typeRootKey.split(':');
|
|
334
|
+
const r = rStr === 'auto' ? 'auto' : rStr;
|
|
335
|
+
const opts = { capture: metaList[0].options.capture, once: metaList[0].options.once, passive: metaList[0].options.passive };
|
|
336
|
+
|
|
337
|
+
const bindRoots: (HTMLElement | ShadowRoot)[] = [];
|
|
338
|
+
if (r === 'auto') bindRoots.push(this.shadowRoot || (this as any));
|
|
339
|
+
else if (r === 'light') bindRoots.push(this as any);
|
|
340
|
+
else if (r === 'shadow' && this.shadowRoot) bindRoots.push(this.shadowRoot);
|
|
341
|
+
else if (r === 'all') {
|
|
342
|
+
bindRoots.push(this as any);
|
|
343
|
+
if (this.shadowRoot) bindRoots.push(this.shadowRoot);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
bindRoots.forEach(br => {
|
|
347
|
+
// Sort: stopPropagation handlers first (more specific/terminal actions)
|
|
348
|
+
const sortedMetaList = [...metaList].sort((a, b) => {
|
|
349
|
+
const aStop = a.options.stopPropagation ? 1 : 0;
|
|
350
|
+
const bStop = b.options.stopPropagation ? 1 : 0;
|
|
351
|
+
return bStop - aStop; // stopPropagation: true comes first
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
const unifiedHandler = async (event: Event) => {
|
|
355
|
+
for (const meta of sortedMetaList) {
|
|
356
|
+
const { selector, options } = meta;
|
|
357
|
+
const matchedEl = (event.target as HTMLElement).closest(selector);
|
|
358
|
+
if (matchedEl && (br as any).contains(matchedEl)) {
|
|
359
|
+
if (options.stopPropagation) event.stopPropagation();
|
|
360
|
+
if (options.stopImmediatePropagation) event.stopImmediatePropagation();
|
|
361
|
+
if (options.preventDefault) event.preventDefault();
|
|
362
|
+
const currentHostSet = SwcUtils.getHostSet(this as any);
|
|
363
|
+
const args = { event, ...currentHostSet, $el: matchedEl, $root: br };
|
|
364
|
+
await (this as any)[meta.propertyKey](event, currentHostSet, matchedEl, args);
|
|
365
|
+
|
|
366
|
+
// Stop processing if event propagation was stopped
|
|
367
|
+
if ((event as any).cancelBubble) break;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
br.addEventListener(type, unifiedHandler, opts);
|
|
372
|
+
(this as any)._boundListeners.push({ target: br, type, handler: unifiedHandler, options: opts });
|
|
373
|
+
});
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
// Process non-delegate listeners
|
|
377
|
+
nonDelegateListeners.forEach(meta => {
|
|
307
378
|
const { selector, type, options } = meta;
|
|
308
379
|
const opts = { capture: options.capture, once: options.once, passive: options.passive };
|
|
309
380
|
const bindTargets: EventTarget[] = [];
|
|
@@ -329,34 +400,7 @@ export const elementDefine =
|
|
|
329
400
|
else if (selector === ':hosts') hostSet.$hosts.forEach(applyRootOption);
|
|
330
401
|
else if (selector === ':appHosts') hostSet.$appHosts.forEach(applyRootOption);
|
|
331
402
|
else if (selector === ':host' || !selector) applyRootOption(this);
|
|
332
|
-
else
|
|
333
|
-
const bindRoots: (HTMLElement | ShadowRoot)[] = [];
|
|
334
|
-
if (r === 'auto') bindRoots.push(this.shadowRoot || (this as any));
|
|
335
|
-
else if (r === 'light') bindRoots.push(this as any);
|
|
336
|
-
else if (r === 'shadow' && this.shadowRoot) bindRoots.push(this.shadowRoot);
|
|
337
|
-
else if (r === 'all') {
|
|
338
|
-
bindRoots.push(this as any);
|
|
339
|
-
if (this.shadowRoot) bindRoots.push(this.shadowRoot);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
bindRoots.forEach(br => {
|
|
343
|
-
const handler = async (event: Event) => {
|
|
344
|
-
const matchedEl = (event.target as HTMLElement).closest(selector);
|
|
345
|
-
if (matchedEl && (br as any).contains(matchedEl)) {
|
|
346
|
-
if (options.stopPropagation) event.stopPropagation();
|
|
347
|
-
if (options.stopImmediatePropagation) event.stopImmediatePropagation();
|
|
348
|
-
if (options.preventDefault) event.preventDefault();
|
|
349
|
-
const currentHostSet = SwcUtils.getHostSet(this as any);
|
|
350
|
-
const args = { event, ...currentHostSet, $el: matchedEl, $root: br };
|
|
351
|
-
await (this as any)._invokeLifecycleMethod(meta.propertyKey, currentHostSet, [event, currentHostSet, matchedEl, args]);
|
|
352
|
-
}
|
|
353
|
-
};
|
|
354
|
-
br.addEventListener(type, handler, opts);
|
|
355
|
-
if (options.removeOnDisconnected === true || (br !== this && br !== this.shadowRoot)) {
|
|
356
|
-
(this as any)._boundListeners.push({ target: br, type, handler, options: opts });
|
|
357
|
-
}
|
|
358
|
-
});
|
|
359
|
-
} else {
|
|
403
|
+
else {
|
|
360
404
|
const searchRoots: (HTMLElement | ShadowRoot)[] = [];
|
|
361
405
|
if (r === 'auto') searchRoots.push(this.shadowRoot || (this as any));
|
|
362
406
|
else if (r === 'light') searchRoots.push(this as any);
|
|
@@ -378,7 +422,7 @@ export const elementDefine =
|
|
|
378
422
|
if (options.preventDefault) event.preventDefault();
|
|
379
423
|
const currentHostSet = SwcUtils.getHostSet(this as any);
|
|
380
424
|
const args = { event, ...currentHostSet, $el: t, $root: t };
|
|
381
|
-
await (this as any)
|
|
425
|
+
await (this as any)[meta.propertyKey](event, currentHostSet, args);
|
|
382
426
|
};
|
|
383
427
|
t.addEventListener(type, handler, opts);
|
|
384
428
|
if (options.removeOnDisconnected === true || t === currentWin || t === currentWin.document) {
|
|
@@ -387,6 +431,24 @@ export const elementDefine =
|
|
|
387
431
|
});
|
|
388
432
|
});
|
|
389
433
|
|
|
434
|
+
addHostEventListenerList.forEach(meta => {
|
|
435
|
+
const { type, options } = meta;
|
|
436
|
+
const opts = { capture: options.capture, once: options.once, passive: options.passive };
|
|
437
|
+
|
|
438
|
+
const handler = async (event: Event) => {
|
|
439
|
+
if (options.stopPropagation) event.stopPropagation();
|
|
440
|
+
if (options.stopImmediatePropagation) event.stopImmediatePropagation();
|
|
441
|
+
if (options.preventDefault) event.preventDefault();
|
|
442
|
+
const currentHostSet = SwcUtils.getHostSet(this as any);
|
|
443
|
+
const args = { event, ...currentHostSet, $el: this, $root: this.getRootNode() };
|
|
444
|
+
await (this as any)[meta.propertyKey](event, currentHostSet, args);
|
|
445
|
+
};
|
|
446
|
+
this.addEventListener(type, handler, opts);
|
|
447
|
+
if (options.removeOnDisconnected === true) {
|
|
448
|
+
(this as any)._boundListeners.push({ target: this, type, handler, options: opts });
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
|
|
390
452
|
if (originalConnected) originalConnected.apply(this);
|
|
391
453
|
|
|
392
454
|
const aMethods = findAllLifecycleMetadata(this, ON_AFTER_CONNECTED_METADATA_KEY);
|
|
@@ -446,20 +508,26 @@ export const elementDefine =
|
|
|
446
508
|
proto.attributeChangedCallback = function (name: string, old: string | null, newVal: string | null) {
|
|
447
509
|
if (originalAttributeChanged) originalAttributeChanged.apply(this, [name, old, newVal]);
|
|
448
510
|
|
|
511
|
+
const hSet = SwcUtils.getHostSet(this as any);
|
|
512
|
+
|
|
449
513
|
// Handle swc-on-* events
|
|
450
514
|
if (name.startsWith('swc-on-') && !swcLifecycleAttributes.includes(name)) {
|
|
451
515
|
if (newVal !== null) {
|
|
452
|
-
const
|
|
453
|
-
const eventName = customEventMeta ? customEventMeta.type : name.substring(7);
|
|
516
|
+
const eventName = name.substring(7);
|
|
454
517
|
(this as any)._bindAttributeEvent(this as any, name, newVal, eventName);
|
|
455
518
|
}
|
|
456
519
|
}
|
|
457
520
|
|
|
521
|
+
// Handle @emitHostCustomEvent attribute changes
|
|
522
|
+
const hostCustomEventMeta = emitHostCustomEventList.find(it => (it.options as any).attributeName === name);
|
|
523
|
+
if (hostCustomEventMeta && newVal !== null) {
|
|
524
|
+
(this as any)._bindAttributeEvent(this as any, name, newVal, hostCustomEventMeta.type);
|
|
525
|
+
}
|
|
526
|
+
|
|
458
527
|
// Handle @changedAttribute callbacks
|
|
459
528
|
const mKeys = attrChangeMap.get(name);
|
|
460
529
|
if (mKeys && Array.isArray(mKeys)) {
|
|
461
|
-
const
|
|
462
|
-
for (const key of mKeys) (this as any)._invokeLifecycleMethod(key, hSet, [newVal, old, name]);
|
|
530
|
+
for (const key of mKeys) (this as any)[key](newVal, old, name, hSet);
|
|
463
531
|
}
|
|
464
532
|
};
|
|
465
533
|
|
|
@@ -4,7 +4,6 @@ import { ensureInit, getElementConfig } from './elementDefine';
|
|
|
4
4
|
import { SwcUtils } from '../utils/Utils';
|
|
5
5
|
|
|
6
6
|
export interface EmitCustomEventBaseOptions {
|
|
7
|
-
attributeName?: string;
|
|
8
7
|
bubbles?: boolean;
|
|
9
8
|
composed?: boolean;
|
|
10
9
|
cancelable?: boolean;
|
|
@@ -14,7 +13,7 @@ export interface EmitCustomEventMetadata {
|
|
|
14
13
|
propertyKey: string | symbol;
|
|
15
14
|
selector: string;
|
|
16
15
|
type: string;
|
|
17
|
-
options: EmitCustomEventBaseOptions & SwcQueryOptions;
|
|
16
|
+
options: (EmitCustomEventBaseOptions & SwcQueryOptions) | (EmitCustomEventBaseOptions & SwcQueryOptions & { attributeName?: string });
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
export const EMIT_CUSTOM_EVENT_METADATA_KEY = Symbol('simple-web-component:emit-custom-event');
|
|
@@ -29,9 +28,6 @@ export function emitCustomEvent(selectorOrTarget: string, type: string, options:
|
|
|
29
28
|
|
|
30
29
|
const fullOptions: any = { ...options, type };
|
|
31
30
|
|
|
32
|
-
if (!fullOptions.attributeName) {
|
|
33
|
-
fullOptions.attributeName = `swc-on-${type}`;
|
|
34
|
-
}
|
|
35
31
|
if (fullOptions.bubbles === undefined) fullOptions.bubbles = true;
|
|
36
32
|
if (fullOptions.composed === undefined) fullOptions.composed = true;
|
|
37
33
|
|
|
@@ -103,3 +99,15 @@ export const getEmitCustomEventMetadataList = (target: any): EmitCustomEventMeta
|
|
|
103
99
|
const constructor = target instanceof Function ? target : target.constructor;
|
|
104
100
|
return ReflectUtils.getMetadata(EMIT_CUSTOM_EVENT_METADATA_KEY, constructor);
|
|
105
101
|
};
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* @emitCustomEventHost decorator - simplified version of @emitCustomEvent for :host selector
|
|
105
|
+
* Usage: @emitCustomEventHost('navigate')
|
|
106
|
+
* Usage: @emitCustomEventHost('navigate', { attributeName: 'on-navigate' })
|
|
107
|
+
*
|
|
108
|
+
* The attributeName option is used to automatically observe attributes for this event.
|
|
109
|
+
* For example, { attributeName: 'on-navigate' } will add 'on-navigate' to observedAttributes.
|
|
110
|
+
*/
|
|
111
|
+
export function emitCustomEventHost(type: string, options?: EmitCustomEventBaseOptions & SwcQueryOptions & { attributeName?: string }): MethodDecorator {
|
|
112
|
+
return emitCustomEvent(':host', type, options);
|
|
113
|
+
}
|
package/src/decorators/index.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
export * from './addEventListener';
|
|
2
2
|
export * from './attribute';
|
|
3
3
|
export * from './elementDefine';
|
|
4
|
-
export * from './
|
|
4
|
+
export * from './changedAttributeHost';
|
|
5
5
|
export * from './setAttribute';
|
|
6
6
|
export * from './emitCustomEvent';
|
|
7
|
-
export * from './
|
|
8
|
-
export * from './appendChild';
|
|
7
|
+
export * from './applyNode';
|
|
9
8
|
export * from './lifecycles';
|
|
10
9
|
export * from './query';
|
|
11
10
|
export * from './queryAll';
|