@dooboostore/simple-web-component 1.0.21 → 1.0.23
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 +1113 -95
- package/dist/cjs/decorators/addEventListener.js +4 -0
- package/dist/cjs/decorators/addEventListener.js.map +2 -2
- package/dist/cjs/decorators/applyNode.js +174 -0
- package/dist/cjs/decorators/applyNode.js.map +7 -0
- package/dist/cjs/decorators/attribute.js +30 -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 +45 -15
- package/dist/cjs/decorators/classList.js.map +2 -2
- package/dist/cjs/decorators/elementDefine.js +107 -57
- 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 -4
- package/dist/cjs/decorators/index.js.map +2 -2
- package/dist/cjs/decorators/lifecycles.js +29 -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/decorators/style.js +39 -13
- package/dist/cjs/decorators/style.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/cjs/utils/TemplateUtils.js +6 -0
- package/dist/cjs/utils/TemplateUtils.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/applyNode.js +155 -0
- package/dist/esm/decorators/applyNode.js.map +7 -0
- package/dist/esm/decorators/attribute.js +30 -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 +45 -15
- package/dist/esm/decorators/classList.js.map +2 -2
- package/dist/esm/decorators/elementDefine.js +106 -56
- 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 -4
- package/dist/esm/decorators/index.js.map +2 -2
- package/dist/esm/decorators/lifecycles.js +29 -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/decorators/style.js +39 -13
- package/dist/esm/decorators/style.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/utils/TemplateUtils.js +6 -0
- package/dist/esm/utils/TemplateUtils.js.map +2 -2
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +385 -206
- 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 +121 -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 +32 -5
- 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 -4
- package/dist/types/decorators/index.d.ts.map +1 -1
- package/dist/types/decorators/lifecycles.d.ts +16 -0
- package/dist/types/decorators/lifecycles.d.ts.map +1 -1
- package/dist/types/decorators/query.d.ts +6 -3
- 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/decorators/style.d.ts +28 -3
- package/dist/types/decorators/style.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/types/utils/TemplateUtils.d.ts +5 -0
- package/dist/types/utils/TemplateUtils.d.ts.map +1 -1
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +385 -206
- 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 +290 -0
- package/src/decorators/attribute.ts +46 -12
- package/src/decorators/{changedAttribute.ts → changedAttributeHost.ts} +5 -1
- package/src/decorators/classList.ts +71 -16
- package/src/decorators/elementDefine.ts +130 -63
- package/src/decorators/emitCustomEvent.ts +13 -5
- package/src/decorators/index.ts +2 -4
- package/src/decorators/lifecycles.ts +43 -1
- package/src/decorators/query.ts +9 -2
- package/src/decorators/queryAll.ts +9 -0
- package/src/decorators/setAttribute.ts +8 -0
- package/src/decorators/style.ts +64 -13
- 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/src/utils/TemplateUtils.ts +9 -0
- package/dist/cjs/decorators/appendChild.js +0 -92
- package/dist/cjs/decorators/appendChild.js.map +0 -7
- package/dist/cjs/decorators/changedAttribute.js.map +0 -7
- package/dist/cjs/decorators/onConnectedInnerHtml.js +0 -48
- package/dist/cjs/decorators/onConnectedInnerHtml.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 +0 -73
- package/dist/esm/decorators/appendChild.js.map +0 -7
- package/dist/esm/decorators/changedAttribute.js.map +0 -7
- package/dist/esm/decorators/onConnectedInnerHtml.js +0 -29
- package/dist/esm/decorators/onConnectedInnerHtml.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/onConnectedInnerHtml.d.ts +0 -15
- package/dist/types/decorators/onConnectedInnerHtml.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/onConnectedInnerHtml.ts +0 -42
- 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.23",
|
|
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.
|
|
95
|
+
"@dooboostore/core-web": "1.0.10",
|
|
96
96
|
"@dooboostore/core-node": "1.0.12",
|
|
97
97
|
"@dooboostore/simple-boot": "1.0.54",
|
|
98
|
-
"@dooboostore/core
|
|
98
|
+
"@dooboostore/core": "1.0.30"
|
|
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,290 @@
|
|
|
1
|
+
import { ReflectUtils } from '@dooboostore/core';
|
|
2
|
+
import { ensureInit, getElementConfig } from './elementDefine';
|
|
3
|
+
import { SwcRootType } from '../types';
|
|
4
|
+
|
|
5
|
+
export type ApplyNodePosition = 'beforeBegin' | 'afterBegin' | 'beforeEnd' | 'afterEnd' | 'replace' | 'replaceChildren' | 'innerHtml' | 'innerText' | 'remove';
|
|
6
|
+
|
|
7
|
+
export interface ApplyNodeOptions {
|
|
8
|
+
position?: ApplyNodePosition;
|
|
9
|
+
root?: SwcRootType;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ApplyNodeMetadata {
|
|
13
|
+
propertyKey: string | symbol;
|
|
14
|
+
selector: string;
|
|
15
|
+
options: ApplyNodeOptions;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const APPLY_NODE_METADATA_KEY = Symbol('simple-web-component:apply-node');
|
|
19
|
+
|
|
20
|
+
const normalizeNodes = (res: any, doc: Document): Node[] => {
|
|
21
|
+
const items = Array.isArray(res) ? res : [res];
|
|
22
|
+
return items.map(it => {
|
|
23
|
+
if (it instanceof Node) return it;
|
|
24
|
+
return doc.createTextNode(it !== undefined && it !== null ? String(it) : '');
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @applyNode decorator to surgically add/replace nodes to a target element.
|
|
30
|
+
*
|
|
31
|
+
* Usage examples:
|
|
32
|
+
* @applyNode('#list') addItem() { return '<li>New Item</li>'; } // append at end
|
|
33
|
+
* @applyNode('#header', { position: 'afterBegin' }) prependItem() { return '<h1>Title</h1>'; } // prepend at start
|
|
34
|
+
* @applyNode('#item', { position: 'replace' }) replaceItem() { return '<div>Replaced</div>'; } // replace element
|
|
35
|
+
* @applyNode('#list', { position: 'replaceChildren' }) updateList() { return [item1, item2]; } // replace all children
|
|
36
|
+
* @applyNode('#notification', { position: 'remove' }) dismissNotification() { return shouldDismiss; } // remove if truthy
|
|
37
|
+
* @applyNode('.items', { position: 'remove', root: 'shadow' }) clearItems() { return true; } // remove shadow DOM elements
|
|
38
|
+
*
|
|
39
|
+
* Positions:
|
|
40
|
+
* - 'beforeEnd' (default): Append at end of target
|
|
41
|
+
* - 'afterBegin': Prepend at start of target
|
|
42
|
+
* - 'beforeBegin': Insert before target
|
|
43
|
+
* - 'afterEnd': Insert after target
|
|
44
|
+
* - 'replace': Replace the entire target element
|
|
45
|
+
* - 'replaceChildren': Replace all children of target element
|
|
46
|
+
* - 'innerHtml': Set target's innerHTML
|
|
47
|
+
* - 'innerText': Set target's innerText
|
|
48
|
+
* - 'remove': Remove target element if returned value is truthy
|
|
49
|
+
*
|
|
50
|
+
* Root Options:
|
|
51
|
+
* - 'auto' (default): Search shadow DOM first, then light DOM
|
|
52
|
+
* - 'shadow': Search only in shadow DOM
|
|
53
|
+
* - 'light': Search only in light DOM
|
|
54
|
+
* - 'all': Use both (shadow preferred for query, both for remove)
|
|
55
|
+
*/
|
|
56
|
+
export function applyNode(selector: string, options: ApplyNodeOptions = { position: 'beforeEnd' }): MethodDecorator {
|
|
57
|
+
return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
|
|
58
|
+
const constructor = target.constructor;
|
|
59
|
+
let metaList = ReflectUtils.getOwnMetadata(APPLY_NODE_METADATA_KEY, constructor) as Map<string | symbol, ApplyNodeMetadata>;
|
|
60
|
+
if (!metaList) {
|
|
61
|
+
metaList = new Map<string | symbol, ApplyNodeMetadata>();
|
|
62
|
+
ReflectUtils.defineMetadata(APPLY_NODE_METADATA_KEY, metaList, constructor);
|
|
63
|
+
}
|
|
64
|
+
metaList.set(propertyKey, { propertyKey, selector, options });
|
|
65
|
+
|
|
66
|
+
const original = descriptor.value;
|
|
67
|
+
descriptor.value = async function (...args: any[]) {
|
|
68
|
+
ensureInit(this);
|
|
69
|
+
const res = await original.apply(this, args);
|
|
70
|
+
if (res !== undefined) {
|
|
71
|
+
const conf = getElementConfig(this);
|
|
72
|
+
const currentWin = (this as any)._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as Window);
|
|
73
|
+
const currentDoc = currentWin.document;
|
|
74
|
+
|
|
75
|
+
const pos = options.position || 'beforeEnd';
|
|
76
|
+
const r = options.root || 'auto';
|
|
77
|
+
|
|
78
|
+
const getTargetRoot = () => {
|
|
79
|
+
if (r === 'shadow') return this.shadowRoot;
|
|
80
|
+
if (r === 'light') return this as any;
|
|
81
|
+
if (r === 'all') return this.shadowRoot || (this as any);
|
|
82
|
+
return this.shadowRoot || (this as any); // auto
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
if (pos === 'remove') {
|
|
86
|
+
// Remove element(s) if returned value is truthy
|
|
87
|
+
if (res) {
|
|
88
|
+
if (selector === ':host' || !selector) {
|
|
89
|
+
if (r === 'shadow' && this.shadowRoot) {
|
|
90
|
+
// Remove all children from shadow DOM
|
|
91
|
+
this.shadowRoot.replaceChildren();
|
|
92
|
+
} else {
|
|
93
|
+
// Remove the component itself
|
|
94
|
+
(this as any).remove();
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
const targetRoot = getTargetRoot();
|
|
98
|
+
if (targetRoot) {
|
|
99
|
+
const targets = targetRoot.querySelectorAll(selector);
|
|
100
|
+
targets.forEach((el: Element) => el.remove());
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
} else {
|
|
105
|
+
let targetEl: any = null;
|
|
106
|
+
if (selector === ':host' || !selector) {
|
|
107
|
+
if (r === 'shadow') {
|
|
108
|
+
targetEl = this.shadowRoot; // Target shadow DOM root
|
|
109
|
+
} else {
|
|
110
|
+
targetEl = this as any; // Target the component itself
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
const targetRoot = getTargetRoot();
|
|
114
|
+
targetEl = targetRoot ? targetRoot.querySelector(selector) : null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (targetEl) {
|
|
118
|
+
const isShadowRoot = targetEl instanceof ShadowRoot;
|
|
119
|
+
const nodes = normalizeNodes(res, currentDoc);
|
|
120
|
+
|
|
121
|
+
if (pos === 'replace') {
|
|
122
|
+
// ShadowRoot doesn't support replaceWith
|
|
123
|
+
if (!isShadowRoot) {
|
|
124
|
+
targetEl.replaceWith(...nodes);
|
|
125
|
+
}
|
|
126
|
+
} else if (pos === 'replaceChildren') {
|
|
127
|
+
// Replace all children of target element
|
|
128
|
+
targetEl.replaceChildren(...nodes);
|
|
129
|
+
} else if (pos === 'innerHtml') {
|
|
130
|
+
// Set innerHTML
|
|
131
|
+
targetEl.innerHTML = res !== undefined && res !== null ? String(res) : '';
|
|
132
|
+
} else if (pos === 'innerText') {
|
|
133
|
+
// Set innerText
|
|
134
|
+
if (targetEl.innerText !== undefined) {
|
|
135
|
+
targetEl.innerText = res !== undefined && res !== null ? String(res) : '';
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
/*
|
|
139
|
+
<!-- beforebegin -->
|
|
140
|
+
<p>
|
|
141
|
+
<!-- afterbegin -->
|
|
142
|
+
foo
|
|
143
|
+
<!-- beforeend -->
|
|
144
|
+
</p>
|
|
145
|
+
<!-- afterend -->
|
|
146
|
+
*/
|
|
147
|
+
if (pos === 'beforeEnd') targetEl.append(...nodes);
|
|
148
|
+
else if (pos === 'afterBegin') targetEl.prepend(...nodes);
|
|
149
|
+
else if (pos === 'beforeBegin' && !isShadowRoot) targetEl.before(...nodes);
|
|
150
|
+
else if (pos === 'afterEnd' && !isShadowRoot) targetEl.after(...nodes);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return res;
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export const findAllApplyNodeMetadata = (target: any): Map<string | symbol, ApplyNodeMetadata> => {
|
|
161
|
+
const result = new Map<string | symbol, ApplyNodeMetadata>();
|
|
162
|
+
const maps = ReflectUtils.findAllMetadata<Map<string | symbol, ApplyNodeMetadata>>(APPLY_NODE_METADATA_KEY, target);
|
|
163
|
+
maps.forEach(map => {
|
|
164
|
+
if (map instanceof Map) {
|
|
165
|
+
map.forEach((v, k) => result.set(k, v));
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
return result;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* @applyNodeHost decorator - simplified version of @applyNode for :host selector
|
|
173
|
+
* Usage: @applyNodeHost() addItem() { return '<li>New Item</li>'; }
|
|
174
|
+
* Usage: @applyNodeHost({ position: 'afterBegin' }) prependItem() { return '<h1>Title</h1>'; }
|
|
175
|
+
*/
|
|
176
|
+
export function applyNodeHost(options: ApplyNodeOptions = { position: 'beforeEnd' }): MethodDecorator {
|
|
177
|
+
return applyNode(':host', options);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Convenience decorators for specific positions
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* @applyBeforeBeginNode - Insert before target element
|
|
184
|
+
*/
|
|
185
|
+
export const applyBeforeBeginNode = (selector: string, options: ApplyNodeOptions = {}) =>
|
|
186
|
+
applyNode(selector, { ...options, position: 'beforeBegin' });
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* @applyAfterBeginNode - Prepend to target element
|
|
190
|
+
*/
|
|
191
|
+
export const applyAfterBeginNode = (selector: string, options: ApplyNodeOptions = {}) =>
|
|
192
|
+
applyNode(selector, { ...options, position: 'afterBegin' });
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* @applyBeforeEndNode - Append to target element (default)
|
|
196
|
+
*/
|
|
197
|
+
export const applyBeforeEndNode = (selector: string, options: ApplyNodeOptions = {}) =>
|
|
198
|
+
applyNode(selector, { ...options, position: 'beforeEnd' });
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* @applyAfterEndNode - Insert after target element
|
|
202
|
+
*/
|
|
203
|
+
export const applyAfterEndNode = (selector: string, options: ApplyNodeOptions = {}) =>
|
|
204
|
+
applyNode(selector, { ...options, position: 'afterEnd' });
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* @applyReplaceNode - Replace entire target element
|
|
208
|
+
*/
|
|
209
|
+
export const applyReplaceNode = (selector: string, options: ApplyNodeOptions = {}) =>
|
|
210
|
+
applyNode(selector, { ...options, position: 'replace' });
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* @applyReplaceChildrenNode - Replace all children of target element
|
|
214
|
+
*/
|
|
215
|
+
export const applyReplaceChildrenNode = (selector: string, options: ApplyNodeOptions = {}) =>
|
|
216
|
+
applyNode(selector, { ...options, position: 'replaceChildren' });
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* @applyInnerHtmlNode - Set target's innerHTML
|
|
220
|
+
*/
|
|
221
|
+
export const applyInnerHtmlNode = (selector: string, options: ApplyNodeOptions = {}) =>
|
|
222
|
+
applyNode(selector, { ...options, position: 'innerHtml' });
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* @applyInnerTextNode - Set target's innerText
|
|
226
|
+
*/
|
|
227
|
+
export const applyInnerTextNode = (selector: string, options: ApplyNodeOptions = {}) =>
|
|
228
|
+
applyNode(selector, { ...options, position: 'innerText' });
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* @applyRemoveNode - Remove target element if truthy
|
|
232
|
+
*/
|
|
233
|
+
export const applyRemoveNode = (selector: string, options: ApplyNodeOptions = {}) =>
|
|
234
|
+
applyNode(selector, { ...options, position: 'remove' });
|
|
235
|
+
|
|
236
|
+
// Host versions
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* @applyBeforeBeginNodeHost - Insert before :host
|
|
240
|
+
*/
|
|
241
|
+
export const applyBeforeBeginNodeHost = (options: ApplyNodeOptions = {}) =>
|
|
242
|
+
applyNode(':host', { ...options, position: 'beforeBegin' });
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* @applyAfterBeginNodeHost - Prepend to :host
|
|
246
|
+
*/
|
|
247
|
+
export const applyAfterBeginNodeHost = (options: ApplyNodeOptions = {}) =>
|
|
248
|
+
applyNode(':host', { ...options, position: 'afterBegin' });
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* @applyBeforeEndNodeHost - Append to :host
|
|
252
|
+
*/
|
|
253
|
+
export const applyBeforeEndNodeHost = (options: ApplyNodeOptions = {}) =>
|
|
254
|
+
applyNode(':host', { ...options, position: 'beforeEnd' });
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* @applyAfterEndNodeHost - Insert after :host
|
|
258
|
+
*/
|
|
259
|
+
export const applyAfterEndNodeHost = (options: ApplyNodeOptions = {}) =>
|
|
260
|
+
applyNode(':host', { ...options, position: 'afterEnd' });
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* @applyReplaceNodeHost - Replace :host
|
|
264
|
+
*/
|
|
265
|
+
export const applyReplaceNodeHost = (options: ApplyNodeOptions = {}) =>
|
|
266
|
+
applyNode(':host', { ...options, position: 'replace' });
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* @applyReplaceChildrenNodeHost - Replace children of :host
|
|
270
|
+
*/
|
|
271
|
+
export const applyReplaceChildrenNodeHost = (options: ApplyNodeOptions = {}) =>
|
|
272
|
+
applyNode(':host', { ...options, position: 'replaceChildren' });
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* @applyInnerHtmlNodeHost - Set :host innerHTML
|
|
276
|
+
*/
|
|
277
|
+
export const applyInnerHtmlNodeHost = (options: ApplyNodeOptions = {}) =>
|
|
278
|
+
applyNode(':host', { ...options, position: 'innerHtml' });
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* @applyInnerTextNodeHost - Set :host innerText
|
|
282
|
+
*/
|
|
283
|
+
export const applyInnerTextNodeHost = (options: ApplyNodeOptions = {}) =>
|
|
284
|
+
applyNode(':host', { ...options, position: 'innerText' });
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* @applyRemoveNodeHost - Remove :host if truthy
|
|
288
|
+
*/
|
|
289
|
+
export const applyRemoveNodeHost = (options: ApplyNodeOptions = {}) =>
|
|
290
|
+
applyNode(':host', { ...options, position: 'remove' });
|
|
@@ -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)[]>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ReflectUtils } from '@dooboostore/core';
|
|
2
2
|
import { ensureInit } from './elementDefine';
|
|
3
3
|
import { SwcUtils } from '../utils/Utils';
|
|
4
|
+
import { SwcQueryOptions } from '../types';
|
|
4
5
|
|
|
5
6
|
export const CLASS_LIST_METADATA_KEY = Symbol('simple-web-component:class-list');
|
|
6
7
|
|
|
@@ -10,10 +11,11 @@ export interface ClassListMetadata {
|
|
|
10
11
|
propertyKey: string | symbol;
|
|
11
12
|
selector: string;
|
|
12
13
|
action: ClassListAction;
|
|
14
|
+
options: SwcQueryOptions;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
function createClassListDecorator(action: ClassListAction) {
|
|
16
|
-
return (selector: string): MethodDecorator => {
|
|
18
|
+
return (selector: string, options: SwcQueryOptions = {}): MethodDecorator => {
|
|
17
19
|
return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
|
|
18
20
|
const constructor = target.constructor;
|
|
19
21
|
let metaList = ReflectUtils.getOwnMetadata(CLASS_LIST_METADATA_KEY, constructor) as Map<string | symbol, ClassListMetadata>;
|
|
@@ -21,22 +23,43 @@ function createClassListDecorator(action: ClassListAction) {
|
|
|
21
23
|
metaList = new Map<string | symbol, ClassListMetadata>();
|
|
22
24
|
ReflectUtils.defineMetadata(CLASS_LIST_METADATA_KEY, metaList, constructor);
|
|
23
25
|
}
|
|
24
|
-
metaList.set(propertyKey, { propertyKey, selector, action });
|
|
26
|
+
metaList.set(propertyKey, { propertyKey, selector, action, options });
|
|
25
27
|
|
|
26
28
|
const original = descriptor.value;
|
|
27
29
|
descriptor.value = async function (...args: any[]) {
|
|
28
30
|
ensureInit(this);
|
|
29
31
|
const res = await original.apply(this, args);
|
|
30
32
|
if (res !== undefined) {
|
|
33
|
+
const r = options.root || 'auto';
|
|
31
34
|
const hostSet = SwcUtils.getHostSet(this as any);
|
|
35
|
+
const targetEls: HTMLElement[] = [];
|
|
32
36
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
else if (selector === ':parentHost')
|
|
36
|
-
|
|
37
|
-
else
|
|
37
|
+
if (selector === ':host' || !selector) {
|
|
38
|
+
targetEls.push(this as any);
|
|
39
|
+
} else if (selector === ':parentHost') {
|
|
40
|
+
if (hostSet.$parentHost) targetEls.push(hostSet.$parentHost);
|
|
41
|
+
} else if (selector === ':appHost') {
|
|
42
|
+
if (hostSet.$appHost) targetEls.push(hostSet.$appHost);
|
|
43
|
+
} else {
|
|
44
|
+
if (r === 'shadow') {
|
|
45
|
+
const found = this.shadowRoot?.querySelectorAll(selector);
|
|
46
|
+
if (found) targetEls.push(...found);
|
|
47
|
+
} else if (r === 'light') {
|
|
48
|
+
const found = (this as any).querySelectorAll(selector);
|
|
49
|
+
if (found) targetEls.push(...found);
|
|
50
|
+
} else if (r === 'all') {
|
|
51
|
+
const sFound = this.shadowRoot?.querySelectorAll(selector);
|
|
52
|
+
const lFound = (this as any).querySelectorAll(selector);
|
|
53
|
+
if (sFound) targetEls.push(...sFound);
|
|
54
|
+
if (lFound) targetEls.push(...lFound);
|
|
55
|
+
} else {
|
|
56
|
+
// auto
|
|
57
|
+
const found = (this.shadowRoot || (this as any)).querySelectorAll(selector);
|
|
58
|
+
if (found) targetEls.push(...found);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
38
61
|
|
|
39
|
-
|
|
62
|
+
targetEls.forEach(targetEl => {
|
|
40
63
|
if (action === 'set') {
|
|
41
64
|
let classes = '';
|
|
42
65
|
if (typeof res === 'object' && res !== null && !Array.isArray(res)) {
|
|
@@ -51,7 +74,7 @@ function createClassListDecorator(action: ClassListAction) {
|
|
|
51
74
|
} else if (action === 'update') {
|
|
52
75
|
if (typeof res === 'object' && res !== null && !Array.isArray(res)) {
|
|
53
76
|
Object.entries(res).forEach(([cls, force]) => {
|
|
54
|
-
targetEl
|
|
77
|
+
targetEl.classList.toggle(cls, !!force);
|
|
55
78
|
});
|
|
56
79
|
} else if (res !== undefined && res !== null) {
|
|
57
80
|
const classes = Array.isArray(res) ? res.map(String) : [String(res)];
|
|
@@ -65,9 +88,9 @@ function createClassListDecorator(action: ClassListAction) {
|
|
|
65
88
|
targetEl.classList.remove(...classes);
|
|
66
89
|
} else if (action === 'toggle') {
|
|
67
90
|
const classes = Array.isArray(res) ? res.map(String) : [String(res)];
|
|
68
|
-
classes.forEach(c => targetEl
|
|
91
|
+
classes.forEach(c => targetEl.classList.toggle(c));
|
|
69
92
|
}
|
|
70
|
-
}
|
|
93
|
+
});
|
|
71
94
|
}
|
|
72
95
|
return res;
|
|
73
96
|
};
|
|
@@ -79,31 +102,63 @@ function createClassListDecorator(action: ClassListAction) {
|
|
|
79
102
|
* @setClassList decorator to surgically replace all classes on a target element.
|
|
80
103
|
* Returns: string | string[]
|
|
81
104
|
*/
|
|
82
|
-
export const setClassList = createClassListDecorator('set');
|
|
105
|
+
export const setClassList = (selector: string, options: SwcQueryOptions = {}) => createClassListDecorator('set')(selector, options);
|
|
83
106
|
|
|
84
107
|
/**
|
|
85
108
|
* @updateClassList decorator to surgically update specific classes.
|
|
86
109
|
* Returns: Record<string, boolean> (toggle with force) | string | string[] (add)
|
|
87
110
|
*/
|
|
88
|
-
export const updateClassList = createClassListDecorator('update');
|
|
111
|
+
export const updateClassList = (selector: string, options: SwcQueryOptions = {}) => createClassListDecorator('update')(selector, options);
|
|
89
112
|
|
|
90
113
|
/**
|
|
91
114
|
* @addClassList decorator to surgically add classes to a target element.
|
|
92
115
|
* Returns: string | string[]
|
|
93
116
|
*/
|
|
94
|
-
export const addClassList = createClassListDecorator('add');
|
|
117
|
+
export const addClassList = (selector: string, options: SwcQueryOptions = {}) => createClassListDecorator('add')(selector, options);
|
|
95
118
|
|
|
96
119
|
/**
|
|
97
120
|
* @removeClassList decorator to surgically remove classes from a target element.
|
|
98
121
|
* Returns: string | string[]
|
|
99
122
|
*/
|
|
100
|
-
export const removeClassList = createClassListDecorator('remove');
|
|
123
|
+
export const removeClassList = (selector: string, options: SwcQueryOptions = {}) => createClassListDecorator('remove')(selector, options);
|
|
101
124
|
|
|
102
125
|
/**
|
|
103
126
|
* @toggleClassList decorator to surgically toggle classes on a target element.
|
|
104
127
|
* Returns: string | string[]
|
|
105
128
|
*/
|
|
106
|
-
export const toggleClassList = createClassListDecorator('toggle');
|
|
129
|
+
export const toggleClassList = (selector: string, options: SwcQueryOptions = {}) => createClassListDecorator('toggle')(selector, options);
|
|
130
|
+
|
|
131
|
+
// Host-specific versions (for :host selector)
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @setClassListHost decorator to set classes on :host element.
|
|
135
|
+
* Returns: string | string[]
|
|
136
|
+
*/
|
|
137
|
+
export const setClassListHost = (options: SwcQueryOptions = {}) => createClassListDecorator('set')(':host', options);
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* @updateClassListHost decorator to update specific classes on :host.
|
|
141
|
+
* Returns: Record<string, boolean> (toggle with force) | string | string[] (add)
|
|
142
|
+
*/
|
|
143
|
+
export const updateClassListHost = (options: SwcQueryOptions = {}) => createClassListDecorator('update')(':host', options);
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* @addClassListHost decorator to add classes to :host element.
|
|
147
|
+
* Returns: string | string[]
|
|
148
|
+
*/
|
|
149
|
+
export const addClassListHost = (options: SwcQueryOptions = {}) => createClassListDecorator('add')(':host', options);
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* @removeClassListHost decorator to remove classes from :host element.
|
|
153
|
+
* Returns: string | string[]
|
|
154
|
+
*/
|
|
155
|
+
export const removeClassListHost = (options: SwcQueryOptions = {}) => createClassListDecorator('remove')(':host', options);
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* @toggleClassListHost decorator to toggle classes on :host element.
|
|
159
|
+
* Returns: string | string[]
|
|
160
|
+
*/
|
|
161
|
+
export const toggleClassListHost = (options: SwcQueryOptions = {}) => createClassListDecorator('toggle')(':host', options);
|
|
107
162
|
|
|
108
163
|
export const findAllClassListMetadata = (target: any): Map<string | symbol, ClassListMetadata> => {
|
|
109
164
|
const result = new Map<string | symbol, ClassListMetadata>();
|