@dooboostore/simple-web-component 1.0.44 → 1.0.45
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 +25 -25
- package/dist/cjs/decorators/addEventListener.js.map +2 -2
- package/dist/cjs/decorators/applyAttribute.js +36 -15
- package/dist/cjs/decorators/applyAttribute.js.map +2 -2
- package/dist/cjs/decorators/applyClass.js +53 -22
- package/dist/cjs/decorators/applyClass.js.map +2 -2
- package/dist/cjs/decorators/applyNode.js +51 -23
- package/dist/cjs/decorators/applyNode.js.map +2 -2
- package/dist/cjs/decorators/applyProperty.js +38 -17
- package/dist/cjs/decorators/applyProperty.js.map +2 -2
- package/dist/cjs/decorators/applyStyle.js +53 -22
- package/dist/cjs/decorators/applyStyle.js.map +2 -2
- package/dist/cjs/decorators/elementDefine.js +44 -25
- package/dist/cjs/decorators/elementDefine.js.map +2 -2
- package/dist/cjs/decorators/emitCustomEvent.js +61 -47
- package/dist/cjs/decorators/emitCustomEvent.js.map +2 -2
- package/dist/cjs/decorators/query.js +91 -56
- package/dist/cjs/decorators/query.js.map +2 -2
- package/dist/cjs/decorators/queryAll.js +104 -66
- package/dist/cjs/decorators/queryAll.js.map +2 -2
- package/dist/cjs/types/window.d.js.map +1 -1
- package/dist/esm/decorators/addEventListener.js.map +2 -2
- package/dist/esm/decorators/applyAttribute.js +36 -15
- package/dist/esm/decorators/applyAttribute.js.map +2 -2
- package/dist/esm/decorators/applyClass.js +53 -22
- package/dist/esm/decorators/applyClass.js.map +2 -2
- package/dist/esm/decorators/applyNode.js +51 -23
- package/dist/esm/decorators/applyNode.js.map +2 -2
- package/dist/esm/decorators/applyProperty.js +38 -17
- package/dist/esm/decorators/applyProperty.js.map +2 -2
- package/dist/esm/decorators/applyStyle.js +53 -22
- package/dist/esm/decorators/applyStyle.js.map +2 -2
- package/dist/esm/decorators/elementDefine.js +44 -25
- package/dist/esm/decorators/elementDefine.js.map +2 -2
- package/dist/esm/decorators/emitCustomEvent.js +61 -47
- package/dist/esm/decorators/emitCustomEvent.js.map +2 -2
- package/dist/esm/decorators/query.js +91 -56
- package/dist/esm/decorators/query.js.map +2 -2
- package/dist/esm/decorators/queryAll.js +104 -66
- package/dist/esm/decorators/queryAll.js.map +2 -2
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +531 -293
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +3 -3
- package/dist/types/decorators/addEventListener.d.ts +7 -6
- package/dist/types/decorators/addEventListener.d.ts.map +1 -1
- package/dist/types/decorators/applyAttribute.d.ts +12 -8
- package/dist/types/decorators/applyAttribute.d.ts.map +1 -1
- package/dist/types/decorators/applyClass.d.ts +8 -7
- package/dist/types/decorators/applyClass.d.ts.map +1 -1
- package/dist/types/decorators/applyNode.d.ts +18 -17
- package/dist/types/decorators/applyNode.d.ts.map +1 -1
- package/dist/types/decorators/applyProperty.d.ts +13 -9
- package/dist/types/decorators/applyProperty.d.ts.map +1 -1
- package/dist/types/decorators/applyStyle.d.ts +6 -5
- package/dist/types/decorators/applyStyle.d.ts.map +1 -1
- package/dist/types/decorators/elementDefine.d.ts.map +1 -1
- package/dist/types/decorators/emitCustomEvent.d.ts +3 -2
- package/dist/types/decorators/emitCustomEvent.d.ts.map +1 -1
- package/dist/types/decorators/query.d.ts +15 -5
- package/dist/types/decorators/query.d.ts.map +1 -1
- package/dist/types/decorators/queryAll.d.ts +15 -5
- package/dist/types/decorators/queryAll.d.ts.map +1 -1
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +531 -293
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +3 -3
- package/package.json +3 -3
- package/src/decorators/addEventListener.ts +9 -7
- package/src/decorators/applyAttribute.ts +59 -27
- package/src/decorators/applyClass.ts +78 -32
- package/src/decorators/applyNode.ts +115 -72
- package/src/decorators/applyProperty.ts +62 -30
- package/src/decorators/applyStyle.ts +76 -30
- package/src/decorators/elementDefine.ts +49 -26
- package/src/decorators/emitCustomEvent.ts +63 -39
- package/src/decorators/query.ts +111 -49
- package/src/decorators/queryAll.ts +121 -61
- package/src/types/window.d.ts +3 -0
|
@@ -15,17 +15,86 @@ export interface StyleApplyOptions extends SwcQueryOptions {
|
|
|
15
15
|
valueKey?: symbol | string;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
export type StyleSelector = string | ((currentThis: any, helper: HelperHostSet) => NodeList | Element | Element[] | null);
|
|
19
|
+
|
|
18
20
|
export interface StyleApplyMetadata {
|
|
19
21
|
propertyKey: string | symbol;
|
|
20
|
-
selector:
|
|
22
|
+
selector: StyleSelector;
|
|
21
23
|
action: StyleAction;
|
|
22
24
|
options: StyleApplyOptions;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
export const STYLE_METADATA_KEY = Symbol.for('simple-web-component:style');
|
|
26
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Resolve selector to string or elements
|
|
31
|
+
* Handles function-based selectors and returns elements if applicable
|
|
32
|
+
*/
|
|
33
|
+
const resolveSelector = (selector: StyleSelector, inst: any, win: Window): string | HTMLElement[] => {
|
|
34
|
+
if (typeof selector === 'function') {
|
|
35
|
+
const hostSet = SwcUtils.getHelperAndHostSet(win, inst);
|
|
36
|
+
const result = selector(inst, hostSet);
|
|
37
|
+
|
|
38
|
+
if (result instanceof win.Element) {
|
|
39
|
+
return [result as HTMLElement];
|
|
40
|
+
}
|
|
41
|
+
if (result instanceof win.NodeList) {
|
|
42
|
+
return Array.from(result) as HTMLElement[];
|
|
43
|
+
}
|
|
44
|
+
if (Array.isArray(result)) {
|
|
45
|
+
return result as HTMLElement[];
|
|
46
|
+
}
|
|
47
|
+
if (result === null) {
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
return result as string;
|
|
51
|
+
}
|
|
52
|
+
return selector as string;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get target elements from selector
|
|
57
|
+
*/
|
|
58
|
+
const getTargetElements = (selector: StyleSelector, inst: any, win: Window, root: string): HTMLElement[] => {
|
|
59
|
+
const resolved = resolveSelector(selector, inst, win);
|
|
60
|
+
|
|
61
|
+
if (Array.isArray(resolved)) {
|
|
62
|
+
return resolved;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const stringSelector = resolved as string;
|
|
66
|
+
const targetEls: HTMLElement[] = [];
|
|
67
|
+
const host = inst as unknown as HTMLElement;
|
|
68
|
+
const hostSet = SwcUtils.getHelperAndHostSet(win, inst);
|
|
69
|
+
|
|
70
|
+
const applyRoot = (t: any) => {
|
|
71
|
+
if (!t || !(t instanceof win.HTMLElement)) return;
|
|
72
|
+
targetEls.push(t);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
if (stringSelector === '$this' || !stringSelector) applyRoot(host);
|
|
76
|
+
else if (stringSelector === '$host') applyRoot(hostSet.$host);
|
|
77
|
+
else if (stringSelector === '$parentHost') applyRoot(hostSet.$parentHost);
|
|
78
|
+
else if (stringSelector === '$appHost') applyRoot(hostSet.$appHost);
|
|
79
|
+
else if (stringSelector === '$firstHost') applyRoot(hostSet.$firstHost);
|
|
80
|
+
else if (stringSelector === '$lastHost') applyRoot(hostSet.$lastHost);
|
|
81
|
+
else if (stringSelector === '$firstAppHost') applyRoot(hostSet.$firstAppHost);
|
|
82
|
+
else if (stringSelector === '$lastAppHost') applyRoot(hostSet.$lastAppHost);
|
|
83
|
+
else if (stringSelector === '$hosts') hostSet.$hosts.forEach(applyRoot);
|
|
84
|
+
else if (stringSelector === '$appHosts') hostSet.$appHosts.forEach(applyRoot);
|
|
85
|
+
else {
|
|
86
|
+
const targetRoot = root === 'auto' ? (host.shadowRoot || host) : (root === 'shadow' ? host.shadowRoot : host);
|
|
87
|
+
if (targetRoot) {
|
|
88
|
+
const found = targetRoot.querySelectorAll(stringSelector);
|
|
89
|
+
if (found) targetEls.push(...(Array.from(found) as HTMLElement[]));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return targetEls;
|
|
94
|
+
};
|
|
95
|
+
|
|
27
96
|
function createStyleDecorator(action: StyleAction) {
|
|
28
|
-
return (selector:
|
|
97
|
+
return (selector: StyleSelector, options: StyleApplyOptions = {}): MethodDecorator => {
|
|
29
98
|
return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
|
|
30
99
|
const constructor = target.constructor;
|
|
31
100
|
let metaList = ReflectUtils.getOwnMetadata(STYLE_METADATA_KEY, constructor) as Map<string | symbol, StyleApplyMetadata>;
|
|
@@ -62,30 +131,7 @@ function createStyleDecorator(action: StyleAction) {
|
|
|
62
131
|
const host = this as unknown as HTMLElement;
|
|
63
132
|
const hostSet = { ...SwcUtils.getHelperAndHostSet(win, host), $this: this };
|
|
64
133
|
const r = options.root || 'auto';
|
|
65
|
-
const targetEls
|
|
66
|
-
|
|
67
|
-
const applyRoot = (t: any) => {
|
|
68
|
-
if (!t || !(t instanceof win.HTMLElement)) return;
|
|
69
|
-
targetEls.push(t);
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
if (selector === '$this' || !selector) applyRoot(host);
|
|
73
|
-
else if (selector === '$host') applyRoot(hostSet.$host);
|
|
74
|
-
else if (selector === '$parentHost') applyRoot(hostSet.$parentHost);
|
|
75
|
-
else if (selector === '$appHost') applyRoot(hostSet.$appHost);
|
|
76
|
-
else if (selector === '$firstHost') applyRoot(hostSet.$firstHost);
|
|
77
|
-
else if (selector === '$lastHost') applyRoot(hostSet.$lastHost);
|
|
78
|
-
else if (selector === '$firstAppHost') applyRoot(hostSet.$firstAppHost);
|
|
79
|
-
else if (selector === '$lastAppHost') applyRoot(hostSet.$lastAppHost);
|
|
80
|
-
else if (selector === '$hosts') hostSet.$hosts.forEach(applyRoot);
|
|
81
|
-
else if (selector === '$appHosts') hostSet.$appHosts.forEach(applyRoot);
|
|
82
|
-
else {
|
|
83
|
-
const targetRoot = r === 'auto' ? (host.shadowRoot || host) : (r === 'shadow' ? host.shadowRoot : host);
|
|
84
|
-
if (targetRoot) {
|
|
85
|
-
const found = targetRoot.querySelectorAll(selector);
|
|
86
|
-
if (found) targetEls.push(...(Array.from(found) as HTMLElement[]));
|
|
87
|
-
}
|
|
88
|
-
}
|
|
134
|
+
const targetEls = getTargetElements(selector, this, win, r);
|
|
89
135
|
|
|
90
136
|
targetEls.forEach(targetEl => {
|
|
91
137
|
if (options.filter && !options.filter(targetEl, resolvedValue, {currentThis: this, helper: hostSet})) {
|
|
@@ -138,7 +184,7 @@ function createStyleDecorator(action: StyleAction) {
|
|
|
138
184
|
}
|
|
139
185
|
|
|
140
186
|
export function applyStyle(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
|
|
141
|
-
export function applyStyle(selector:
|
|
187
|
+
export function applyStyle(selector: StyleSelector, action?: StyleAction, options?: StyleApplyOptions): MethodDecorator;
|
|
142
188
|
export function applyStyle(selectorOrTarget?: any, actionOrPropertyKey?: any, optionsOrDescriptor?: any): any {
|
|
143
189
|
// Bare decorator: @applyStyle
|
|
144
190
|
if (optionsOrDescriptor !== undefined && (typeof actionOrPropertyKey === 'string' || typeof actionOrPropertyKey === 'symbol')) {
|
|
@@ -157,7 +203,7 @@ export function applyStyle(selectorOrTarget?: any, actionOrPropertyKey?: any, op
|
|
|
157
203
|
}
|
|
158
204
|
|
|
159
205
|
export function setStyle(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
|
|
160
|
-
export function setStyle(selector:
|
|
206
|
+
export function setStyle(selector: StyleSelector, options?: StyleApplyOptions): MethodDecorator;
|
|
161
207
|
export function setStyle(selectorOrTarget?: any, optionsOrPropertyKey?: any, descriptor?: any): any {
|
|
162
208
|
// Bare decorator: @setStyle
|
|
163
209
|
if (descriptor !== undefined && (typeof optionsOrPropertyKey === 'string' || typeof optionsOrPropertyKey === 'symbol')) {
|
|
@@ -172,7 +218,7 @@ export function setStyle(selectorOrTarget?: any, optionsOrPropertyKey?: any, des
|
|
|
172
218
|
}
|
|
173
219
|
|
|
174
220
|
export function updateStyle(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
|
|
175
|
-
export function updateStyle(selector:
|
|
221
|
+
export function updateStyle(selector: StyleSelector, options?: StyleApplyOptions): MethodDecorator;
|
|
176
222
|
export function updateStyle(selectorOrTarget?: any, optionsOrPropertyKey?: any, descriptor?: any): any {
|
|
177
223
|
// Bare decorator: @updateStyle
|
|
178
224
|
if (descriptor !== undefined && (typeof optionsOrPropertyKey === 'string' || typeof optionsOrPropertyKey === 'symbol')) {
|
|
@@ -187,7 +233,7 @@ export function updateStyle(selectorOrTarget?: any, optionsOrPropertyKey?: any,
|
|
|
187
233
|
}
|
|
188
234
|
|
|
189
235
|
export function removeStyle(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
|
|
190
|
-
export function removeStyle(selector:
|
|
236
|
+
export function removeStyle(selector: StyleSelector, options?: StyleApplyOptions): MethodDecorator;
|
|
191
237
|
export function removeStyle(selectorOrTarget?: any, optionsOrPropertyKey?: any, descriptor?: any): any {
|
|
192
238
|
// Bare decorator: @removeStyle
|
|
193
239
|
if (descriptor !== undefined && (typeof optionsOrPropertyKey === 'string' || typeof optionsOrPropertyKey === 'symbol')) {
|
|
@@ -467,7 +467,9 @@ export const elementDefine =
|
|
|
467
467
|
const nonDelegateListeners: typeof addEventListenerList = [];
|
|
468
468
|
|
|
469
469
|
addEventListenerList.forEach(meta => {
|
|
470
|
-
|
|
470
|
+
// Function-based selectors cannot be used with delegate listeners
|
|
471
|
+
const isStringSelector = typeof meta.selector === 'string';
|
|
472
|
+
if (meta.options.delegate && isStringSelector && meta.selector !== '$window' && meta.selector !== '$document' && meta.selector !== '$host' && meta.selector !== '$appHost' && meta.selector !== '$firstHost' && meta.selector !== '$lastHost' && meta.selector !== '$firstAppHost' && meta.selector !== '$lastAppHost' && meta.selector !== '$hosts' && meta.selector !== '$appHosts' && meta.selector !== '$this' && meta.selector !== '') {
|
|
471
473
|
delegateListeners.push(meta);
|
|
472
474
|
} else {
|
|
473
475
|
nonDelegateListeners.push(meta);
|
|
@@ -537,6 +539,25 @@ export const elementDefine =
|
|
|
537
539
|
const opts = {capture: options.capture, once: options.once, passive: options.passive};
|
|
538
540
|
const bindTargets: EventTarget[] = [];
|
|
539
541
|
const r = options.root || 'auto';
|
|
542
|
+
|
|
543
|
+
// Resolve selector if it's a function
|
|
544
|
+
let resolvedSelector: string | null = null;
|
|
545
|
+
if (typeof selector === 'function') {
|
|
546
|
+
const hostSet = SwcUtils.getHelperAndHostSet(currentWin, this);
|
|
547
|
+
const result = selector(this, hostSet);
|
|
548
|
+
if (typeof result === 'string') {
|
|
549
|
+
resolvedSelector = result;
|
|
550
|
+
} else if (result instanceof currentWin.Element) {
|
|
551
|
+
bindTargets.push(result as EventTarget);
|
|
552
|
+
} else if (result instanceof currentWin.NodeList) {
|
|
553
|
+
bindTargets.push(...Array.from(result as EventTarget[]));
|
|
554
|
+
} else if (Array.isArray(result)) {
|
|
555
|
+
bindTargets.push(...(result as EventTarget[]));
|
|
556
|
+
}
|
|
557
|
+
} else {
|
|
558
|
+
resolvedSelector = selector;
|
|
559
|
+
}
|
|
560
|
+
|
|
540
561
|
const applyRootOption = (target: any) => {
|
|
541
562
|
if (!target) return;
|
|
542
563
|
if (r === 'auto') {
|
|
@@ -547,31 +568,33 @@ export const elementDefine =
|
|
|
547
568
|
}
|
|
548
569
|
};
|
|
549
570
|
|
|
550
|
-
if (
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
+
if (resolvedSelector) {
|
|
572
|
+
if (resolvedSelector === '$window') bindTargets.push(currentWin);
|
|
573
|
+
else if (resolvedSelector === '$document') bindTargets.push(currentWin.document);
|
|
574
|
+
else if (resolvedSelector === '$host') applyRootOption(helperHostSet.$host);
|
|
575
|
+
else if (resolvedSelector === '$parentHost') applyRootOption(helperHostSet.$parentHost);
|
|
576
|
+
else if (resolvedSelector === '$appHost') applyRootOption(helperHostSet.$appHost);
|
|
577
|
+
else if (resolvedSelector === '$firstHost') applyRootOption(helperHostSet.$firstHost);
|
|
578
|
+
else if (resolvedSelector === '$lastHost') applyRootOption(helperHostSet.$lastHost);
|
|
579
|
+
else if (resolvedSelector === '$firstAppHost') applyRootOption(helperHostSet.$firstAppHost);
|
|
580
|
+
else if (resolvedSelector === '$lastAppHost') applyRootOption(helperHostSet.$lastAppHost);
|
|
581
|
+
else if (resolvedSelector === '$hosts') helperHostSet.$hosts.forEach(applyRootOption);
|
|
582
|
+
else if (resolvedSelector === '$appHosts') helperHostSet.$appHosts.forEach(applyRootOption);
|
|
583
|
+
else if (resolvedSelector === '$this' || !resolvedSelector) applyRootOption(this);
|
|
584
|
+
else {
|
|
585
|
+
const searchRoots: (HTMLElement | ShadowRoot)[] = [];
|
|
586
|
+
if (r === 'auto') searchRoots.push(this.shadowRoot || (this as any));
|
|
587
|
+
else if (r === 'light') searchRoots.push(this as any);
|
|
588
|
+
else if (r === 'shadow' && this.shadowRoot) searchRoots.push(this.shadowRoot);
|
|
589
|
+
else if (r === 'all') {
|
|
590
|
+
searchRoots.push(this as any);
|
|
591
|
+
if (this.shadowRoot) searchRoots.push(this.shadowRoot);
|
|
592
|
+
}
|
|
571
593
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
594
|
+
searchRoots.forEach(sr => {
|
|
595
|
+
sr.querySelectorAll(resolvedSelector).forEach(el => bindTargets.push(el));
|
|
596
|
+
});
|
|
597
|
+
}
|
|
575
598
|
}
|
|
576
599
|
|
|
577
600
|
bindTargets.forEach(t => {
|
|
@@ -588,7 +611,7 @@ export const elementDefine =
|
|
|
588
611
|
if (options.preventDefault) event.preventDefault();
|
|
589
612
|
const currentHostSet = SwcUtils.getHostSet(this as any);
|
|
590
613
|
const args = {event, ...currentHostSet, $el: t, $root: t};
|
|
591
|
-
await (this as any)[meta.propertyKey](event, {currentHostSet,
|
|
614
|
+
await (this as any)[meta.propertyKey](event, {currentHostSet, $matchedElement: event.currentTarget}, args);
|
|
592
615
|
};
|
|
593
616
|
|
|
594
617
|
// Create event stream with Observable-based operators
|
|
@@ -3,6 +3,8 @@ import { SpecialSelector, SwcQueryOptions, HelperHostSet } from '../types';
|
|
|
3
3
|
import {ensureInit, getElementConfig} from './elementDefine';
|
|
4
4
|
import {SwcUtils} from '../utils/Utils';
|
|
5
5
|
|
|
6
|
+
export type EmitCustomEventSelector = string | ((currentThis: any, helper: HelperHostSet) => NodeList | Element | Element[] | null);
|
|
7
|
+
|
|
6
8
|
export interface EmitCustomEventBaseOptions {
|
|
7
9
|
bubbles?: boolean;
|
|
8
10
|
composed?: boolean;
|
|
@@ -30,7 +32,7 @@ type Options = (EmitCustomEventBaseOptions & SwcQueryOptions) | (EmitCustomEvent
|
|
|
30
32
|
|
|
31
33
|
export interface EmitCustomEventMetadata {
|
|
32
34
|
propertyKey: string | symbol;
|
|
33
|
-
selector:
|
|
35
|
+
selector: EmitCustomEventSelector;
|
|
34
36
|
type: string;
|
|
35
37
|
options: Options;
|
|
36
38
|
}
|
|
@@ -38,7 +40,7 @@ export interface EmitCustomEventMetadata {
|
|
|
38
40
|
export const EMIT_CUSTOM_EVENT_METADATA_KEY = Symbol.for('simple-web-component:emit-custom-event');
|
|
39
41
|
|
|
40
42
|
export function emitCustomEvent(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
|
|
41
|
-
export function emitCustomEvent(selector:
|
|
43
|
+
export function emitCustomEvent(selector: EmitCustomEventSelector, type: string, options?: Options): MethodDecorator;
|
|
42
44
|
export function emitCustomEvent(type: string, options?: Options): MethodDecorator;
|
|
43
45
|
/**
|
|
44
46
|
* @emitCustomEvent decorator to dispatch custom events to a target.
|
|
@@ -46,6 +48,7 @@ export function emitCustomEvent(type: string, options?: Options): MethodDecorato
|
|
|
46
48
|
* Usage:
|
|
47
49
|
* - @emitCustomEvent('$this', 'event-name', options) - Emit from $this
|
|
48
50
|
* - @emitCustomEvent('$appHost', 'event-name', options) - Emit from $appHost
|
|
51
|
+
* - @emitCustomEvent((this, helper) => '.button', 'event-name', options) - Function-based selector
|
|
49
52
|
* - @emitCustomEvent('event-name', options) - Emit from $this (defaults to $this)
|
|
50
53
|
* - @emitCustomEvent('event-name') - Emit from $this with no options
|
|
51
54
|
*/
|
|
@@ -56,7 +59,7 @@ export function emitCustomEvent(selectorOrTarget: any, typeOrPropertyKey?: any,
|
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
// Case 2: With selector and type - @emitCustomEvent('selector', 'event-name', options)
|
|
59
|
-
if (typeof selectorOrTarget === 'string' && typeof typeOrPropertyKey === 'string') {
|
|
62
|
+
if ((typeof selectorOrTarget === 'string' || typeof selectorOrTarget === 'function') && typeof typeOrPropertyKey === 'string') {
|
|
60
63
|
return createEmitDecorator(selectorOrTarget, typeOrPropertyKey, optionsOrDescriptor as Options);
|
|
61
64
|
}
|
|
62
65
|
|
|
@@ -69,7 +72,7 @@ export function emitCustomEvent(selectorOrTarget: any, typeOrPropertyKey?: any,
|
|
|
69
72
|
throw new Error('Invalid @emitCustomEvent usage');
|
|
70
73
|
}
|
|
71
74
|
|
|
72
|
-
function createEmitDecorator(selector:
|
|
75
|
+
function createEmitDecorator(selector: EmitCustomEventSelector, type: string, options?: Options) {
|
|
73
76
|
return (targetObj: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
|
|
74
77
|
const constructor = targetObj.constructor;
|
|
75
78
|
|
|
@@ -98,47 +101,68 @@ function createEmitDecorator(selector: string, type: string, options?: Options)
|
|
|
98
101
|
cancelable: fullOptions.cancelable
|
|
99
102
|
});
|
|
100
103
|
|
|
101
|
-
const hostSet = SwcUtils.getHostSet(this as any);
|
|
102
104
|
const conf = getElementConfig(this);
|
|
103
105
|
const currentWin = (this as any)._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as Window);
|
|
106
|
+
const hostSet = SwcUtils.getHelperAndHostSet(currentWin, this as any);
|
|
104
107
|
|
|
105
108
|
const eventTargets: EventTarget[] = [];
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
} else if (
|
|
117
|
-
|
|
118
|
-
} else if (
|
|
119
|
-
|
|
120
|
-
} else if (
|
|
121
|
-
|
|
122
|
-
} else if (selector === '$hosts') {
|
|
123
|
-
hostSet.$hosts.forEach(h => eventTargets.push(h));
|
|
124
|
-
} else if (selector === '$appHosts') {
|
|
125
|
-
hostSet.$appHosts.forEach(h => eventTargets.push(h));
|
|
126
|
-
} else if (selector === '$this' || !selector) {
|
|
127
|
-
eventTargets.push(this as any);
|
|
109
|
+
|
|
110
|
+
// Resolve selector if it's a function
|
|
111
|
+
let resolvedSelector: string | Element | NodeList | Element[] | null = selector as any;
|
|
112
|
+
if (typeof selector === 'function') {
|
|
113
|
+
resolvedSelector = selector(this, hostSet);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// If selector function returned elements directly, use them
|
|
117
|
+
if (resolvedSelector instanceof currentWin.Element) {
|
|
118
|
+
eventTargets.push(resolvedSelector as EventTarget);
|
|
119
|
+
} else if (resolvedSelector instanceof currentWin.NodeList) {
|
|
120
|
+
eventTargets.push(...Array.from(resolvedSelector as EventTarget[]));
|
|
121
|
+
} else if (Array.isArray(resolvedSelector)) {
|
|
122
|
+
eventTargets.push(...(resolvedSelector as EventTarget[]));
|
|
123
|
+
} else if (resolvedSelector === null) {
|
|
124
|
+
// No targets
|
|
128
125
|
} else {
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
else if (
|
|
134
|
-
else if (
|
|
135
|
-
|
|
136
|
-
|
|
126
|
+
// Handle string selector
|
|
127
|
+
const stringSelector = resolvedSelector as string;
|
|
128
|
+
|
|
129
|
+
if (stringSelector === '$window') eventTargets.push(currentWin);
|
|
130
|
+
else if (stringSelector === '$document') eventTargets.push(currentWin.document);
|
|
131
|
+
else if (stringSelector === '$host') {
|
|
132
|
+
if (hostSet.$host) eventTargets.push(hostSet.$host);
|
|
133
|
+
} else if (stringSelector === '$parentHost') {
|
|
134
|
+
if (hostSet.$parentHost) eventTargets.push(hostSet.$parentHost);
|
|
135
|
+
} else if (stringSelector === '$appHost') {
|
|
136
|
+
if (hostSet.$appHost) eventTargets.push(hostSet.$appHost);
|
|
137
|
+
} else if (stringSelector === '$firstHost') {
|
|
138
|
+
if (hostSet.$firstHost) eventTargets.push(hostSet.$firstHost);
|
|
139
|
+
} else if (stringSelector === '$lastHost') {
|
|
140
|
+
if (hostSet.$lastHost) eventTargets.push(hostSet.$lastHost);
|
|
141
|
+
} else if (stringSelector === '$firstAppHost') {
|
|
142
|
+
if (hostSet.$firstAppHost) eventTargets.push(hostSet.$firstAppHost);
|
|
143
|
+
} else if (stringSelector === '$lastAppHost') {
|
|
144
|
+
if (hostSet.$lastAppHost) eventTargets.push(hostSet.$lastAppHost);
|
|
145
|
+
} else if (stringSelector === '$hosts') {
|
|
146
|
+
hostSet.$hosts.forEach(h => eventTargets.push(h));
|
|
147
|
+
} else if (stringSelector === '$appHosts') {
|
|
148
|
+
hostSet.$appHosts.forEach(h => eventTargets.push(h));
|
|
149
|
+
} else if (stringSelector === '$this' || !stringSelector) {
|
|
150
|
+
eventTargets.push(this as any);
|
|
151
|
+
} else {
|
|
152
|
+
const r = fullOptions.root || 'auto';
|
|
153
|
+
const searchRoots: (HTMLElement | ShadowRoot)[] = [];
|
|
154
|
+
if (r === 'auto') searchRoots.push(this.shadowRoot || (this as any));
|
|
155
|
+
else if (r === 'light') searchRoots.push(this as any);
|
|
156
|
+
else if (r === 'shadow' && this.shadowRoot) searchRoots.push(this.shadowRoot);
|
|
157
|
+
else if (r === 'all') {
|
|
158
|
+
searchRoots.push(this as any);
|
|
159
|
+
if (this.shadowRoot) searchRoots.push(this.shadowRoot);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
searchRoots.forEach(sr => {
|
|
163
|
+
sr.querySelectorAll(stringSelector).forEach(el => eventTargets.push(el));
|
|
164
|
+
});
|
|
137
165
|
}
|
|
138
|
-
|
|
139
|
-
searchRoots.forEach(sr => {
|
|
140
|
-
sr.querySelectorAll(selector).forEach(el => eventTargets.push(el));
|
|
141
|
-
});
|
|
142
166
|
}
|
|
143
167
|
|
|
144
168
|
eventTargets.forEach(t => {
|
package/src/decorators/query.ts
CHANGED
|
@@ -1,29 +1,44 @@
|
|
|
1
1
|
import { ReflectUtils } from '@dooboostore/core';
|
|
2
2
|
import { getElementConfig, ensureInit } from './elementDefine';
|
|
3
3
|
import { SwcUtils } from '../utils/Utils';
|
|
4
|
-
import {
|
|
4
|
+
import { SwcQueryOptions, HelperHostSet } from '../types';
|
|
5
|
+
|
|
6
|
+
export interface QueryOptions extends SwcQueryOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Filter function to determine whether to include the element.
|
|
9
|
+
* If it returns false, the element is skipped.
|
|
10
|
+
*/
|
|
11
|
+
filter?: (target: HTMLElement, meta: { currentThis: any, helper: HelperHostSet }) => boolean;
|
|
12
|
+
}
|
|
5
13
|
|
|
6
14
|
export interface QueryMetadata {
|
|
7
15
|
propertyKey: string | symbol;
|
|
8
|
-
selector: string;
|
|
9
|
-
options:
|
|
16
|
+
selector: string | ((currentThis: any, helper: HelperHostSet) => Node | NodeList | Element | Element[] | null);
|
|
17
|
+
options: QueryOptions ;
|
|
10
18
|
}
|
|
11
19
|
|
|
12
20
|
export const QUERY_METADATA_KEY = Symbol.for('simple-web-component:query');
|
|
13
21
|
|
|
14
22
|
export function query(target: Object, propertyKey: string | symbol, descriptor?: PropertyDescriptor): PropertyDescriptor | void;
|
|
15
|
-
export function query(selector: string, options?:
|
|
16
|
-
export function query(options?:
|
|
23
|
+
export function query(selector: string | ((currentThis: any, helper: HelperHostSet) => Node | NodeList | Element | Element[] | null), options?: QueryOptions): PropertyDecorator;
|
|
24
|
+
export function query(options?: QueryOptions): PropertyDecorator;
|
|
17
25
|
/**
|
|
18
26
|
* @query decorator to inject a single element into a class property.
|
|
27
|
+
*
|
|
28
|
+
* Supports both string selectors and function-based selectors:
|
|
29
|
+
* - String selector: @query('#my-element')
|
|
30
|
+
* - Function selector: @query((currentThis, helper) => currentThis.shadowRoot?.querySelector('.item'))
|
|
31
|
+
*
|
|
32
|
+
* Supports filtering:
|
|
33
|
+
* - @query('#my-element', { filter: (target, meta) => target.hasAttribute('active') })
|
|
19
34
|
*/
|
|
20
|
-
export function query(selectorOrTarget?: string | Object, optionsOrPropertyKey?:
|
|
35
|
+
export function query(selectorOrTarget?: string | ((currentThis: any, helper: HelperHostSet) => Node | NodeList | Element | Element[] | null) | Object, optionsOrPropertyKey?: QueryOptions | string | symbol, descriptor?: PropertyDescriptor): any {
|
|
21
36
|
// Bare decorator: @query
|
|
22
37
|
if (descriptor !== undefined && (typeof optionsOrPropertyKey === 'string' || typeof optionsOrPropertyKey === 'symbol')) {
|
|
23
38
|
throw new Error(`@query decorator cannot be used on methods. (Method: ${String(optionsOrPropertyKey)})`);
|
|
24
39
|
}
|
|
25
40
|
// With selector
|
|
26
|
-
if (typeof selectorOrTarget === 'string') {
|
|
41
|
+
if (typeof selectorOrTarget === 'string' || typeof selectorOrTarget === 'function') {
|
|
27
42
|
return (targetObj: Object, propertyKey: string | symbol, descriptor?: never): void => {
|
|
28
43
|
if (descriptor !== undefined) {
|
|
29
44
|
throw new Error(`@query decorator cannot be used on methods. (Method: ${String(propertyKey)})`);
|
|
@@ -35,67 +50,114 @@ export function query(selectorOrTarget?: string | Object, optionsOrPropertyKey?:
|
|
|
35
50
|
queries = [];
|
|
36
51
|
ReflectUtils.defineMetadata(QUERY_METADATA_KEY, queries, constructor);
|
|
37
52
|
}
|
|
38
|
-
queries.push({ propertyKey, selector: selectorOrTarget, options: optionsOrPropertyKey as
|
|
53
|
+
queries.push({ propertyKey, selector: selectorOrTarget as any, options: optionsOrPropertyKey as QueryOptions || {} });
|
|
39
54
|
|
|
40
55
|
Object.defineProperty(targetObj, propertyKey, {
|
|
41
56
|
get(this: HTMLElement) {
|
|
42
57
|
ensureInit(this);
|
|
43
|
-
const selector = selectorOrTarget;
|
|
44
|
-
|
|
45
|
-
const r = (optionsOrPropertyKey as SwcQueryOptions)?.root || 'auto';
|
|
46
|
-
const applyRoot = (t: any) => {
|
|
47
|
-
if (!t || !(t instanceof HTMLElement)) return t;
|
|
48
|
-
if (r === 'auto') return t.shadowRoot || t;
|
|
49
|
-
if (r === 'shadow') return t.shadowRoot;
|
|
50
|
-
if (r === 'light') return t;
|
|
51
|
-
if (r === 'all') return t.shadowRoot || t;
|
|
52
|
-
return t;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
// --- Special Selectors: HostSet ---
|
|
56
|
-
const hostSet = SwcUtils.getHostSet(this);
|
|
57
|
-
if (selector === '$this') return applyRoot(this);
|
|
58
|
-
if (selector === '$host') return applyRoot(hostSet.$host);
|
|
59
|
-
if (selector === '$parentHost') return applyRoot(hostSet.$parentHost);
|
|
60
|
-
if (selector === '$appHost') return applyRoot(hostSet.$appHost);
|
|
61
|
-
if (selector === '$firstHost') return applyRoot(hostSet.$firstHost);
|
|
62
|
-
if (selector === '$lastHost') return applyRoot(hostSet.$lastHost);
|
|
63
|
-
if (selector === '$firstAppHost') return applyRoot(hostSet.$firstAppHost);
|
|
64
|
-
if (selector === '$lastAppHost') return applyRoot(hostSet.$lastAppHost);
|
|
65
|
-
|
|
66
|
-
// --- Special Selectors: Env ---
|
|
67
58
|
const config = getElementConfig(this);
|
|
68
59
|
const win = config?.window || window;
|
|
69
|
-
|
|
70
|
-
|
|
60
|
+
const hostSet = SwcUtils.getHelperAndHostSet(win, this);
|
|
61
|
+
|
|
62
|
+
// Resolve selector - can be string or function
|
|
63
|
+
let resolvedSelector: string;
|
|
64
|
+
let resolvedElement: HTMLElement | null = null;
|
|
65
|
+
|
|
66
|
+
if (typeof selectorOrTarget === 'function') {
|
|
67
|
+
const result = (selectorOrTarget as any)(this, hostSet);
|
|
68
|
+
// If function returns a Node/Element, return it directly
|
|
69
|
+
if (result instanceof win.Node || result instanceof win.Element) {
|
|
70
|
+
resolvedElement = result instanceof win.HTMLElement ? (result as HTMLElement) : null;
|
|
71
|
+
}
|
|
72
|
+
// If function returns NodeList or Element[], return first element
|
|
73
|
+
else if (result instanceof win.NodeList || Array.isArray(result)) {
|
|
74
|
+
resolvedElement = result.length > 0 && result[0] instanceof win.HTMLElement ? (result[0] as HTMLElement) : null;
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
resolvedSelector = selectorOrTarget;
|
|
71
78
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
79
|
+
const r = (optionsOrPropertyKey as QueryOptions)?.root || 'auto';
|
|
80
|
+
const applyRoot = (t: any) => {
|
|
81
|
+
if (!t || !(t instanceof HTMLElement)) return t;
|
|
82
|
+
if (r === 'auto') return t.shadowRoot || t;
|
|
83
|
+
if (r === 'shadow') return t.shadowRoot;
|
|
84
|
+
if (r === 'light') return t;
|
|
85
|
+
if (r === 'all') return t.shadowRoot || t;
|
|
86
|
+
return t;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// --- Special Selectors: HostSet ---
|
|
90
|
+
if (resolvedSelector === '$this') resolvedElement = applyRoot(this);
|
|
91
|
+
else if (resolvedSelector === '$host') resolvedElement = applyRoot(hostSet.$host);
|
|
92
|
+
else if (resolvedSelector === '$parentHost') resolvedElement = applyRoot(hostSet.$parentHost);
|
|
93
|
+
else if (resolvedSelector === '$appHost') resolvedElement = applyRoot(hostSet.$appHost);
|
|
94
|
+
else if (resolvedSelector === '$firstHost') resolvedElement = applyRoot(hostSet.$firstHost);
|
|
95
|
+
else if (resolvedSelector === '$lastHost') resolvedElement = applyRoot(hostSet.$lastHost);
|
|
96
|
+
else if (resolvedSelector === '$firstAppHost') resolvedElement = applyRoot(hostSet.$firstAppHost);
|
|
97
|
+
else if (resolvedSelector === '$lastAppHost') resolvedElement = applyRoot(hostSet.$lastAppHost);
|
|
98
|
+
// --- Special Selectors: Env ---
|
|
99
|
+
else if (resolvedSelector === '$window') return win;
|
|
100
|
+
else if (resolvedSelector === '$document') return win.document;
|
|
101
|
+
// --- Standard Selectors ---
|
|
102
|
+
else {
|
|
103
|
+
if (r === 'shadow') resolvedElement = this.shadowRoot ? (this.shadowRoot.querySelector(resolvedSelector) as HTMLElement | null) : null;
|
|
104
|
+
else if (r === 'light') resolvedElement = this.querySelector(resolvedSelector) as HTMLElement | null;
|
|
105
|
+
else if (r === 'all') {
|
|
106
|
+
const shadowMatch = this.shadowRoot ? (this.shadowRoot.querySelector(resolvedSelector) as HTMLElement | null) : null;
|
|
107
|
+
resolvedElement = shadowMatch || (this.querySelector(resolvedSelector) as HTMLElement | null);
|
|
108
|
+
}
|
|
109
|
+
else resolvedElement = ((this.shadowRoot || this).querySelector(resolvedSelector) as HTMLElement | null);
|
|
110
|
+
}
|
|
78
111
|
}
|
|
79
|
-
|
|
112
|
+
|
|
113
|
+
// Apply filter if provided
|
|
114
|
+
if (resolvedElement instanceof win.HTMLElement && (optionsOrPropertyKey as QueryOptions)?.filter) {
|
|
115
|
+
const shouldInclude = (optionsOrPropertyKey as QueryOptions).filter!(resolvedElement, { currentThis: this, helper: hostSet });
|
|
116
|
+
if (!shouldInclude) {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return resolvedElement;
|
|
80
122
|
},
|
|
81
123
|
set(this: HTMLElement, nv: any) {
|
|
82
124
|
ensureInit(this);
|
|
83
125
|
if (nv === null || nv === undefined) {
|
|
84
|
-
const
|
|
85
|
-
|
|
126
|
+
const config = getElementConfig(this);
|
|
127
|
+
const win = config?.window || window;
|
|
128
|
+
const hostSet = SwcUtils.getHelperAndHostSet(win, this);
|
|
129
|
+
|
|
130
|
+
// Resolve selector - can be string or function
|
|
131
|
+
if (typeof selectorOrTarget === 'function') {
|
|
132
|
+
// Get the element from function and remove it
|
|
133
|
+
const result = (selectorOrTarget as any)(this, hostSet);
|
|
134
|
+
if (result instanceof win.Element) {
|
|
135
|
+
(result as Element).remove();
|
|
136
|
+
} else if (result instanceof win.NodeList || Array.isArray(result)) {
|
|
137
|
+
const el = result.length > 0 ? result[0] : null;
|
|
138
|
+
if (el instanceof win.Element) {
|
|
139
|
+
(el as Element).remove();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const resolvedSelector = selectorOrTarget;
|
|
146
|
+
|
|
147
|
+
if (resolvedSelector.startsWith('$') && resolvedSelector !== '$this') return;
|
|
86
148
|
|
|
87
|
-
const r = (optionsOrPropertyKey as
|
|
149
|
+
const r = (optionsOrPropertyKey as QueryOptions)?.root || 'auto';
|
|
88
150
|
const targets: Element[] = [];
|
|
89
151
|
|
|
90
152
|
if (r === 'shadow') {
|
|
91
|
-
if (this.shadowRoot?.querySelector(
|
|
153
|
+
if (this.shadowRoot?.querySelector(resolvedSelector)) targets.push(this.shadowRoot.querySelector(resolvedSelector)!);
|
|
92
154
|
} else if (r === 'light') {
|
|
93
|
-
if (this.querySelector(
|
|
155
|
+
if (this.querySelector(resolvedSelector)) targets.push(this.querySelector(resolvedSelector)!);
|
|
94
156
|
} else if (r === 'all') {
|
|
95
|
-
if (this.shadowRoot?.querySelector(
|
|
96
|
-
if (this.querySelector(
|
|
157
|
+
if (this.shadowRoot?.querySelector(resolvedSelector)) targets.push(this.shadowRoot.querySelector(resolvedSelector)!);
|
|
158
|
+
if (this.querySelector(resolvedSelector)) targets.push(this.querySelector(resolvedSelector)!);
|
|
97
159
|
} else {
|
|
98
|
-
const el = (this.shadowRoot || this).querySelector(
|
|
160
|
+
const el = (this.shadowRoot || this).querySelector(resolvedSelector);
|
|
99
161
|
if (el) targets.push(el);
|
|
100
162
|
}
|
|
101
163
|
|