@dooboostore/simple-web-component 1.0.22 → 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 +361 -19
- package/dist/cjs/decorators/applyNode.js +98 -24
- package/dist/cjs/decorators/applyNode.js.map +2 -2
- package/dist/cjs/decorators/attribute.js +0 -1
- package/dist/cjs/decorators/attribute.js.map +2 -2
- package/dist/cjs/decorators/classList.js +39 -19
- package/dist/cjs/decorators/classList.js.map +2 -2
- package/dist/cjs/decorators/elementDefine.js +1 -2
- package/dist/cjs/decorators/elementDefine.js.map +2 -2
- package/dist/cjs/decorators/index.js +0 -1
- package/dist/cjs/decorators/index.js.map +2 -2
- package/dist/cjs/decorators/lifecycles.js +25 -0
- package/dist/cjs/decorators/lifecycles.js.map +2 -2
- package/dist/cjs/decorators/query.js.map +2 -2
- package/dist/cjs/decorators/style.js +39 -13
- package/dist/cjs/decorators/style.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/applyNode.js +98 -24
- package/dist/esm/decorators/applyNode.js.map +2 -2
- package/dist/esm/decorators/attribute.js +0 -1
- package/dist/esm/decorators/attribute.js.map +2 -2
- package/dist/esm/decorators/classList.js +39 -19
- package/dist/esm/decorators/classList.js.map +2 -2
- package/dist/esm/decorators/elementDefine.js +1 -2
- package/dist/esm/decorators/elementDefine.js.map +2 -2
- package/dist/esm/decorators/index.js +0 -1
- package/dist/esm/decorators/index.js.map +2 -2
- package/dist/esm/decorators/lifecycles.js +25 -0
- package/dist/esm/decorators/lifecycles.js.map +2 -2
- package/dist/esm/decorators/query.js.map +2 -2
- package/dist/esm/decorators/style.js +39 -13
- package/dist/esm/decorators/style.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 +204 -81
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +3 -3
- package/dist/types/decorators/applyNode.d.ts +84 -1
- package/dist/types/decorators/applyNode.d.ts.map +1 -1
- package/dist/types/decorators/classList.d.ts +12 -10
- package/dist/types/decorators/classList.d.ts.map +1 -1
- package/dist/types/decorators/elementDefine.d.ts.map +1 -1
- package/dist/types/decorators/index.d.ts +0 -1
- package/dist/types/decorators/index.d.ts.map +1 -1
- package/dist/types/decorators/lifecycles.d.ts +14 -0
- package/dist/types/decorators/lifecycles.d.ts.map +1 -1
- package/dist/types/decorators/query.d.ts +0 -3
- package/dist/types/decorators/query.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/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 +204 -81
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +3 -3
- package/package.json +3 -3
- package/src/decorators/applyNode.ts +199 -36
- package/src/decorators/attribute.ts +1 -1
- package/src/decorators/classList.ts +45 -22
- package/src/decorators/elementDefine.ts +1 -2
- package/src/decorators/index.ts +0 -1
- package/src/decorators/lifecycles.ts +40 -0
- package/src/decorators/query.ts +0 -2
- package/src/decorators/style.ts +64 -13
- package/src/utils/TemplateUtils.ts +9 -0
- package/dist/cjs/decorators/onConnectedInnerHtml.js +0 -48
- package/dist/cjs/decorators/onConnectedInnerHtml.js.map +0 -7
- package/dist/esm/decorators/onConnectedInnerHtml.js +0 -29
- package/dist/esm/decorators/onConnectedInnerHtml.js.map +0 -7
- package/dist/types/decorators/onConnectedInnerHtml.d.ts +0 -15
- package/dist/types/decorators/onConnectedInnerHtml.d.ts.map +0 -1
- package/src/decorators/onConnectedInnerHtml.ts +0 -42
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",
|
|
@@ -93,9 +93,9 @@
|
|
|
93
93
|
"webpack-cli": "^5.1.4",
|
|
94
94
|
"webpack-dev-server": "^5.2.0",
|
|
95
95
|
"@dooboostore/core-web": "1.0.10",
|
|
96
|
-
"@dooboostore/core": "1.0.30",
|
|
97
96
|
"@dooboostore/core-node": "1.0.12",
|
|
98
|
-
"@dooboostore/simple-boot": "1.0.54"
|
|
97
|
+
"@dooboostore/simple-boot": "1.0.54",
|
|
98
|
+
"@dooboostore/core": "1.0.30"
|
|
99
99
|
},
|
|
100
100
|
"scripts": {
|
|
101
101
|
"clean": "rm -rf dist",
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { ReflectUtils } from '@dooboostore/core';
|
|
2
2
|
import { ensureInit, getElementConfig } from './elementDefine';
|
|
3
|
+
import { SwcRootType } from '../types';
|
|
3
4
|
|
|
4
|
-
export type ApplyNodePosition = 'beforeBegin' | 'afterBegin' | 'beforeEnd' | 'afterEnd' | 'replace' | 'replaceChildren' | 'innerHtml' | 'innerText';
|
|
5
|
+
export type ApplyNodePosition = 'beforeBegin' | 'afterBegin' | 'beforeEnd' | 'afterEnd' | 'replace' | 'replaceChildren' | 'innerHtml' | 'innerText' | 'remove';
|
|
5
6
|
|
|
6
7
|
export interface ApplyNodeOptions {
|
|
7
8
|
position?: ApplyNodePosition;
|
|
9
|
+
root?: SwcRootType;
|
|
8
10
|
}
|
|
9
11
|
|
|
10
12
|
export interface ApplyNodeMetadata {
|
|
@@ -31,6 +33,8 @@ const normalizeNodes = (res: any, doc: Document): Node[] => {
|
|
|
31
33
|
* @applyNode('#header', { position: 'afterBegin' }) prependItem() { return '<h1>Title</h1>'; } // prepend at start
|
|
32
34
|
* @applyNode('#item', { position: 'replace' }) replaceItem() { return '<div>Replaced</div>'; } // replace element
|
|
33
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
|
|
34
38
|
*
|
|
35
39
|
* Positions:
|
|
36
40
|
* - 'beforeEnd' (default): Append at end of target
|
|
@@ -41,6 +45,13 @@ const normalizeNodes = (res: any, doc: Document): Node[] => {
|
|
|
41
45
|
* - 'replaceChildren': Replace all children of target element
|
|
42
46
|
* - 'innerHtml': Set target's innerHTML
|
|
43
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)
|
|
44
55
|
*/
|
|
45
56
|
export function applyNode(selector: string, options: ApplyNodeOptions = { position: 'beforeEnd' }): MethodDecorator {
|
|
46
57
|
return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
|
|
@@ -61,43 +72,83 @@ export function applyNode(selector: string, options: ApplyNodeOptions = { positi
|
|
|
61
72
|
const currentWin = (this as any)._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as Window);
|
|
62
73
|
const currentDoc = currentWin.document;
|
|
63
74
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
targetEl = this as any;
|
|
67
|
-
} else {
|
|
68
|
-
targetEl = (this.shadowRoot || (this as any)).querySelector(selector);
|
|
69
|
-
}
|
|
75
|
+
const pos = options.position || 'beforeEnd';
|
|
76
|
+
const r = options.root || 'auto';
|
|
70
77
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
|
+
}
|
|
87
112
|
} else {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
+
}
|
|
101
152
|
}
|
|
102
153
|
}
|
|
103
154
|
}
|
|
@@ -125,3 +176,115 @@ export const findAllApplyNodeMetadata = (target: any): Map<string | symbol, Appl
|
|
|
125
176
|
export function applyNodeHost(options: ApplyNodeOptions = { position: 'beforeEnd' }): MethodDecorator {
|
|
126
177
|
return applyNode(':host', options);
|
|
127
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' });
|
|
@@ -143,7 +143,7 @@ export function attribute(selector: string, options: AttributeOptions = {}): Pro
|
|
|
143
143
|
},
|
|
144
144
|
set(this: any, nv: any) {
|
|
145
145
|
const targetType = options.type || designType;
|
|
146
|
-
console.log('---set', propertyKey, targetType, nv, this, this.__swc_syncing_init);
|
|
146
|
+
// console.log('---set', propertyKey, targetType, nv, this, this.__swc_syncing_init);
|
|
147
147
|
|
|
148
148
|
const attrName = options.name || String(propertyKey);
|
|
149
149
|
const conf = getElementConfig(this);
|
|
@@ -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[] = [];
|
|
36
|
+
|
|
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
|
+
}
|
|
32
61
|
|
|
33
|
-
|
|
34
|
-
if (selector === ':host' || !selector) targetEl = this as any;
|
|
35
|
-
else if (selector === ':parentHost') targetEl = hostSet.$parentHost;
|
|
36
|
-
else if (selector === ':appHost') targetEl = hostSet.$appHost;
|
|
37
|
-
else targetEl = (this.shadowRoot || (this as any)).querySelector(selector);
|
|
38
|
-
|
|
39
|
-
if (targetEl) {
|
|
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,31 @@ 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);
|
|
107
130
|
|
|
108
131
|
// Host-specific versions (for :host selector)
|
|
109
132
|
|
|
@@ -111,31 +134,31 @@ export const toggleClassList = createClassListDecorator('toggle');
|
|
|
111
134
|
* @setClassListHost decorator to set classes on :host element.
|
|
112
135
|
* Returns: string | string[]
|
|
113
136
|
*/
|
|
114
|
-
export const setClassListHost = createClassListDecorator('set')
|
|
137
|
+
export const setClassListHost = (options: SwcQueryOptions = {}) => createClassListDecorator('set')(':host', options);
|
|
115
138
|
|
|
116
139
|
/**
|
|
117
140
|
* @updateClassListHost decorator to update specific classes on :host.
|
|
118
141
|
* Returns: Record<string, boolean> (toggle with force) | string | string[] (add)
|
|
119
142
|
*/
|
|
120
|
-
export const updateClassListHost = createClassListDecorator('update')
|
|
143
|
+
export const updateClassListHost = (options: SwcQueryOptions = {}) => createClassListDecorator('update')(':host', options);
|
|
121
144
|
|
|
122
145
|
/**
|
|
123
146
|
* @addClassListHost decorator to add classes to :host element.
|
|
124
147
|
* Returns: string | string[]
|
|
125
148
|
*/
|
|
126
|
-
export const addClassListHost = createClassListDecorator('add')
|
|
149
|
+
export const addClassListHost = (options: SwcQueryOptions = {}) => createClassListDecorator('add')(':host', options);
|
|
127
150
|
|
|
128
151
|
/**
|
|
129
152
|
* @removeClassListHost decorator to remove classes from :host element.
|
|
130
153
|
* Returns: string | string[]
|
|
131
154
|
*/
|
|
132
|
-
export const removeClassListHost = createClassListDecorator('remove')
|
|
155
|
+
export const removeClassListHost = (options: SwcQueryOptions = {}) => createClassListDecorator('remove')(':host', options);
|
|
133
156
|
|
|
134
157
|
/**
|
|
135
158
|
* @toggleClassListHost decorator to toggle classes on :host element.
|
|
136
159
|
* Returns: string | string[]
|
|
137
160
|
*/
|
|
138
|
-
export const toggleClassListHost = createClassListDecorator('toggle')
|
|
161
|
+
export const toggleClassListHost = (options: SwcQueryOptions = {}) => createClassListDecorator('toggle')(':host', options);
|
|
139
162
|
|
|
140
163
|
export const findAllClassListMetadata = (target: any): Map<string | symbol, ClassListMetadata> => {
|
|
141
164
|
const result = new Map<string | symbol, ClassListMetadata>();
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { ReflectUtils } from '@dooboostore/core';
|
|
2
2
|
import { FunctionUtils } from '@dooboostore/core';
|
|
3
|
-
import { getOnConnectedInnerHtmlMetadata } from './onConnectedInnerHtml';
|
|
4
3
|
import { getAddEventListenerMetadata } from './addEventListener';
|
|
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';
|
|
4
|
+
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, getOnConnectedInnerHtmlMetadata } from './lifecycles';
|
|
6
5
|
import { getEmitCustomEventMetadataList } from './emitCustomEvent';
|
|
7
6
|
import { findAllAttributeChangedMetadata } from './changedAttributeHost';
|
|
8
7
|
import { findAllSetAttributeMetadata } from './setAttribute';
|
package/src/decorators/index.ts
CHANGED
|
@@ -10,9 +10,19 @@ export const ON_AFTER_DISCONNECTED_METADATA_KEY = Symbol('simple-web-component:o
|
|
|
10
10
|
export const ON_BEFORE_ADOPTED_METADATA_KEY = Symbol('simple-web-component:on-before-adopted');
|
|
11
11
|
export const ON_AFTER_ADOPTED_METADATA_KEY = Symbol('simple-web-component:on-after-adopted');
|
|
12
12
|
export const ON_ADD_EVENT_LISTENER_METADATA_KEY = Symbol('simple-web-component:on-add-event-listener');
|
|
13
|
+
export const INNER_HTML_METADATA_KEY = Symbol('simple-web-component:inner-html');
|
|
13
14
|
|
|
14
15
|
export const ATTRIBUTE_CHANGED_WILDCARD = '*';
|
|
15
16
|
|
|
17
|
+
export interface InnerHtmlOptions {
|
|
18
|
+
useShadow?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface InnerHtmlMetadata {
|
|
22
|
+
propertyKey: string | symbol;
|
|
23
|
+
options: InnerHtmlOptions;
|
|
24
|
+
}
|
|
25
|
+
|
|
16
26
|
function createLifecycleDecorator(metadataKey: symbol): MethodDecorator {
|
|
17
27
|
return (target: Object, propertyKey: string | symbol) => {
|
|
18
28
|
const constructor = target.constructor;
|
|
@@ -40,6 +50,31 @@ export const onAdopted = onAfterAdopted;
|
|
|
40
50
|
|
|
41
51
|
export const onAddEventListener = createLifecycleDecorator(ON_ADD_EVENT_LISTENER_METADATA_KEY);
|
|
42
52
|
|
|
53
|
+
/**
|
|
54
|
+
* @onConnectedInnerHtml decorator to define the initial HTML content when connected.
|
|
55
|
+
*/
|
|
56
|
+
export function onConnectedInnerHtml(options: InnerHtmlOptions): MethodDecorator;
|
|
57
|
+
export function onConnectedInnerHtml(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
|
|
58
|
+
export function onConnectedInnerHtml(arg1?: InnerHtmlOptions | Object, arg2?: string | symbol, arg3?: PropertyDescriptor): MethodDecorator | void {
|
|
59
|
+
const decorator = (options: InnerHtmlOptions, target: Object, propertyKey: string | symbol) => {
|
|
60
|
+
const constructor = target.constructor;
|
|
61
|
+
let list = ReflectUtils.getMetadata<InnerHtmlMetadata[]>(INNER_HTML_METADATA_KEY, constructor);
|
|
62
|
+
if (!list) {
|
|
63
|
+
list = [];
|
|
64
|
+
ReflectUtils.defineMetadata(INNER_HTML_METADATA_KEY, list, constructor);
|
|
65
|
+
}
|
|
66
|
+
list.push({ propertyKey, options });
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
if (arg2) {
|
|
70
|
+
return decorator({}, arg1!, arg2);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return (target: Object, propertyKey: string | symbol) => {
|
|
74
|
+
decorator((arg1 as InnerHtmlOptions) || {}, target, propertyKey);
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
43
78
|
/**
|
|
44
79
|
* 프로토타입 체인을 순회하며 모든 라이프사이클 메서드를 수집합니다.
|
|
45
80
|
*/
|
|
@@ -47,3 +82,8 @@ export const findAllLifecycleMetadata = <T = (string | symbol)[]>(target: any, m
|
|
|
47
82
|
const results = ReflectUtils.findAllMetadataFlatten(metadataKey, target);
|
|
48
83
|
return results.length > 0 ? (results as unknown as T) : undefined;
|
|
49
84
|
};
|
|
85
|
+
|
|
86
|
+
export const getOnConnectedInnerHtmlMetadata = (target: any): InnerHtmlMetadata[] | undefined => {
|
|
87
|
+
const constructor = target instanceof Function ? target : target.constructor;
|
|
88
|
+
return ReflectUtils.getMetadata(INNER_HTML_METADATA_KEY, constructor);
|
|
89
|
+
};
|
package/src/decorators/query.ts
CHANGED
|
@@ -3,8 +3,6 @@ import { getElementConfig, ensureInit } from './elementDefine';
|
|
|
3
3
|
import { SwcUtils } from '../utils/Utils';
|
|
4
4
|
import { SpecialSelector, SwcQueryOptions } from '../types';
|
|
5
5
|
|
|
6
|
-
export type QueryOptions = { root?: 'light' | 'shadow' | 'all' | 'auto' };
|
|
7
|
-
|
|
8
6
|
export interface QueryMetadata {
|
|
9
7
|
propertyKey: string | symbol;
|
|
10
8
|
selector: string;
|