@dooboostore/simple-web-component 1.0.43 → 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 +312 -63
- package/dist/cjs/SwcAppEngine.js +3 -1
- package/dist/cjs/SwcAppEngine.js.map +2 -2
- package/dist/cjs/decorators/addEventListener.js.map +2 -2
- package/dist/cjs/decorators/applyAttribute.js +66 -43
- package/dist/cjs/decorators/applyAttribute.js.map +2 -2
- package/dist/cjs/decorators/applyClass.js +110 -43
- package/dist/cjs/decorators/applyClass.js.map +3 -3
- package/dist/cjs/decorators/applyNode.js +200 -112
- package/dist/cjs/decorators/applyNode.js.map +2 -2
- package/dist/cjs/decorators/applyProperty.js +49 -45
- package/dist/cjs/decorators/applyProperty.js.map +2 -2
- package/dist/cjs/decorators/applyStyle.js +92 -37
- package/dist/cjs/decorators/applyStyle.js.map +3 -3
- package/dist/cjs/decorators/{changedAttributeThis.js → changedAttribute.js} +6 -6
- package/dist/cjs/decorators/changedAttribute.js.map +7 -0
- package/dist/cjs/decorators/elementDefine.js +81 -31
- package/dist/cjs/decorators/elementDefine.js.map +3 -3
- package/dist/cjs/decorators/emitCustomEvent.js +80 -52
- package/dist/cjs/decorators/emitCustomEvent.js.map +2 -2
- package/dist/cjs/decorators/index.js +1 -1
- package/dist/cjs/decorators/index.js.map +2 -2
- package/dist/cjs/decorators/publishSwcAppMessage.js +5 -5
- package/dist/cjs/decorators/publishSwcAppMessage.js.map +3 -3
- package/dist/cjs/decorators/query.js +133 -147
- package/dist/cjs/decorators/query.js.map +3 -3
- package/dist/cjs/decorators/queryAll.js +143 -132
- package/dist/cjs/decorators/queryAll.js.map +3 -3
- package/dist/cjs/decorators/subscribeSwcAppMessageWhileConnected.js +2 -0
- package/dist/cjs/decorators/subscribeSwcAppMessageWhileConnected.js.map +2 -2
- package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js +2 -0
- package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +2 -2
- package/dist/cjs/elements/SwcAppMixin.js +17 -2
- package/dist/cjs/elements/SwcAppMixin.js.map +2 -2
- package/dist/cjs/examples/RxJSOperatorsExample.js +285 -0
- package/dist/cjs/examples/RxJSOperatorsExample.js.map +7 -0
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/router/ElementRouter.js +4 -0
- package/dist/cjs/router/ElementRouter.js.map +2 -2
- package/dist/cjs/types/window.d.js.map +1 -1
- package/dist/esm/SwcAppEngine.js +3 -1
- package/dist/esm/SwcAppEngine.js.map +2 -2
- package/dist/esm/decorators/addEventListener.js.map +2 -2
- package/dist/esm/decorators/applyAttribute.js +66 -43
- package/dist/esm/decorators/applyAttribute.js.map +2 -2
- package/dist/esm/decorators/applyClass.js +110 -43
- package/dist/esm/decorators/applyClass.js.map +3 -3
- package/dist/esm/decorators/applyNode.js +200 -112
- package/dist/esm/decorators/applyNode.js.map +2 -2
- package/dist/esm/decorators/applyProperty.js +49 -45
- package/dist/esm/decorators/applyProperty.js.map +2 -2
- package/dist/esm/decorators/applyStyle.js +92 -37
- package/dist/esm/decorators/applyStyle.js.map +3 -3
- package/dist/esm/decorators/{changedAttributeThis.js → changedAttribute.js} +3 -3
- package/dist/esm/decorators/changedAttribute.js.map +7 -0
- package/dist/esm/decorators/elementDefine.js +79 -29
- package/dist/esm/decorators/elementDefine.js.map +2 -2
- package/dist/esm/decorators/emitCustomEvent.js +80 -52
- package/dist/esm/decorators/emitCustomEvent.js.map +2 -2
- package/dist/esm/decorators/index.js +1 -1
- package/dist/esm/decorators/index.js.map +1 -1
- package/dist/esm/decorators/publishSwcAppMessage.js +5 -5
- package/dist/esm/decorators/publishSwcAppMessage.js.map +3 -3
- package/dist/esm/decorators/query.js +133 -147
- package/dist/esm/decorators/query.js.map +3 -3
- package/dist/esm/decorators/queryAll.js +143 -132
- package/dist/esm/decorators/queryAll.js.map +3 -3
- package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js +2 -0
- package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js.map +2 -2
- package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js +2 -0
- package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +2 -2
- package/dist/esm/elements/SwcAppMixin.js +18 -3
- package/dist/esm/elements/SwcAppMixin.js.map +2 -2
- package/dist/esm/examples/RxJSOperatorsExample.js +266 -0
- package/dist/esm/examples/RxJSOperatorsExample.js.map +7 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +2 -2
- package/dist/esm/router/ElementRouter.js +4 -0
- package/dist/esm/router/ElementRouter.js.map +2 -2
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +1118 -633
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
- package/dist/types/SwcAppEngine.d.ts.map +1 -1
- package/dist/types/decorators/addEventListener.d.ts +19 -15
- package/dist/types/decorators/addEventListener.d.ts.map +1 -1
- package/dist/types/decorators/applyAttribute.d.ts +45 -26
- package/dist/types/decorators/applyAttribute.d.ts.map +1 -1
- package/dist/types/decorators/applyClass.d.ts +19 -38
- package/dist/types/decorators/applyClass.d.ts.map +1 -1
- package/dist/types/decorators/applyNode.d.ts +175 -32
- package/dist/types/decorators/applyNode.d.ts.map +1 -1
- package/dist/types/decorators/applyProperty.d.ts +38 -25
- package/dist/types/decorators/applyProperty.d.ts.map +1 -1
- package/dist/types/decorators/applyStyle.d.ts +10 -9
- package/dist/types/decorators/applyStyle.d.ts.map +1 -1
- package/dist/types/decorators/{changedAttributeThis.d.ts → changedAttribute.d.ts} +2 -2
- package/dist/types/decorators/changedAttribute.d.ts.map +1 -0
- package/dist/types/decorators/elementDefine.d.ts.map +1 -1
- package/dist/types/decorators/emitCustomEvent.d.ts +6 -12
- package/dist/types/decorators/emitCustomEvent.d.ts.map +1 -1
- package/dist/types/decorators/index.d.ts +1 -1
- package/dist/types/decorators/index.d.ts.map +1 -1
- package/dist/types/decorators/publishSwcAppMessage.d.ts +1 -1
- package/dist/types/decorators/publishSwcAppMessage.d.ts.map +1 -1
- package/dist/types/decorators/query.d.ts +16 -29
- package/dist/types/decorators/query.d.ts.map +1 -1
- package/dist/types/decorators/queryAll.d.ts +16 -23
- package/dist/types/decorators/queryAll.d.ts.map +1 -1
- package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts +1 -0
- package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts.map +1 -1
- package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts +2 -0
- package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts.map +1 -1
- package/dist/types/elements/SwcAppMixin.d.ts +4 -4
- package/dist/types/elements/SwcAppMixin.d.ts.map +1 -1
- package/dist/types/examples/RxJSOperatorsExample.d.ts +94 -0
- package/dist/types/examples/RxJSOperatorsExample.d.ts.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/router/ElementRouter.d.ts.map +1 -1
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +1118 -633
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
- package/package.json +1 -1
- package/src/SwcAppEngine.ts +3 -1
- package/src/decorators/addEventListener.ts +31 -25
- package/src/decorators/applyAttribute.ts +164 -86
- package/src/decorators/applyClass.ts +161 -41
- package/src/decorators/applyNode.ts +408 -108
- package/src/decorators/applyProperty.ts +100 -89
- package/src/decorators/applyStyle.ts +131 -37
- package/src/decorators/{changedAttributeThis.ts → changedAttribute.ts} +1 -1
- package/src/decorators/elementDefine.ts +96 -30
- package/src/decorators/emitCustomEvent.ts +92 -60
- package/src/decorators/index.ts +1 -1
- package/src/decorators/publishSwcAppMessage.ts +1 -1
- package/src/decorators/query.ts +155 -162
- package/src/decorators/queryAll.ts +157 -139
- package/src/decorators/subscribeSwcAppMessageWhileConnected.ts +1 -0
- package/src/decorators/subscribeSwcAppRouteChangeWhileConnected.ts +3 -1
- package/src/elements/SwcAppMixin.ts +43 -24
- package/src/examples/RxJSOperatorsExample.ts +279 -0
- package/src/index.ts +2 -0
- package/src/router/ElementRouter.ts +4 -0
- package/src/types/window.d.ts +3 -0
- package/dist/cjs/decorators/changedAttributeThis.js.map +0 -7
- package/dist/esm/decorators/changedAttributeThis.js.map +0 -7
- package/dist/types/decorators/changedAttributeThis.d.ts.map +0 -1
package/package.json
CHANGED
package/src/SwcAppEngine.ts
CHANGED
|
@@ -78,7 +78,9 @@ export class SwcAppEngine {
|
|
|
78
78
|
|
|
79
79
|
if (this._config.onStartedLazyDefineComponent) {
|
|
80
80
|
// console.log('-------->', this._config.onStartedLazyDefineComponent)
|
|
81
|
-
await Promise.all(this._config.onStartedLazyDefineComponent.map(it =>
|
|
81
|
+
await Promise.all(this._config.onStartedLazyDefineComponent.map(it => {
|
|
82
|
+
it(this._config.window);
|
|
83
|
+
}))
|
|
82
84
|
}
|
|
83
85
|
if (this._config.onEngineStarted) {
|
|
84
86
|
await this._config.onEngineStarted(this.simpleApplication, this.host as unknown as SwcAppInterface);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ReflectUtils } from '@dooboostore/core';
|
|
2
2
|
import { SpecialSelector, SwcQueryOptions, HelperHostSet } from '../types';
|
|
3
3
|
|
|
4
|
-
export interface AddEventListenerBaseOptions extends EventListenerOptions {
|
|
4
|
+
export interface AddEventListenerBaseOptions<TEvent extends Event = Event> extends EventListenerOptions {
|
|
5
5
|
capture?: boolean;
|
|
6
6
|
once?: boolean;
|
|
7
7
|
passive?: boolean;
|
|
@@ -11,27 +11,33 @@ export interface AddEventListenerBaseOptions extends EventListenerOptions {
|
|
|
11
11
|
// removeOnDisconnected?: boolean;
|
|
12
12
|
delegate?: boolean;
|
|
13
13
|
filter?: (target: Event | CustomEvent, meta:{currentThis: any, helper: HelperHostSet}) => boolean;
|
|
14
|
+
// RxJS operator options
|
|
15
|
+
debounceTime?: number;
|
|
16
|
+
throttleTime?: number;
|
|
17
|
+
distinctUntilChanged?: boolean | ((prev: TEvent, curr: TEvent) => boolean);
|
|
14
18
|
}
|
|
15
19
|
|
|
16
|
-
export
|
|
20
|
+
export type EventListenerSelector = string | ((currentThis: any, helper: HelperHostSet) => NodeList | Element | Element[] | null);
|
|
21
|
+
|
|
22
|
+
export interface AddEventListenerMetadata<TEvent extends Event = Event> {
|
|
17
23
|
propertyKey: string | symbol;
|
|
18
|
-
selector:
|
|
24
|
+
selector: EventListenerSelector;
|
|
19
25
|
type: string;
|
|
20
|
-
options: AddEventListenerBaseOptions & SwcQueryOptions & { delegate?: boolean };
|
|
26
|
+
options: AddEventListenerBaseOptions<TEvent> & SwcQueryOptions & { delegate?: boolean };
|
|
21
27
|
}
|
|
22
28
|
|
|
23
29
|
export const ADD_EVENT_LISTENER_METADATA_KEY = Symbol.for('simple-web-component:add-event-listener');
|
|
24
30
|
|
|
25
|
-
export function addEventListener(target: SpecialSelector, type: string, options?: AddEventListenerBaseOptions): MethodDecorator;
|
|
26
|
-
export function addEventListener(selector:
|
|
31
|
+
export function addEventListener<TEvent extends Event = Event>(target: SpecialSelector, type: string, options?: AddEventListenerBaseOptions<TEvent>): MethodDecorator;
|
|
32
|
+
export function addEventListener<TEvent extends Event = Event>(selector: EventListenerSelector, type: string, options?: AddEventListenerBaseOptions<TEvent> & SwcQueryOptions & { delegate?: boolean }): MethodDecorator;
|
|
27
33
|
/**
|
|
28
34
|
* @addEventListener decorator to bind events to elements.
|
|
29
35
|
*/
|
|
30
|
-
export function addEventListener(selectorOrTarget:
|
|
36
|
+
export function addEventListener<TEvent extends Event = Event>(selectorOrTarget: EventListenerSelector, type: string, options: any = {}): MethodDecorator {
|
|
31
37
|
return (targetObj: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
|
|
32
38
|
const constructor = targetObj.constructor;
|
|
33
39
|
|
|
34
|
-
let listeners = ReflectUtils.getMetadata<AddEventListenerMetadata[]>(ADD_EVENT_LISTENER_METADATA_KEY, constructor);
|
|
40
|
+
let listeners = ReflectUtils.getMetadata<AddEventListenerMetadata<TEvent>[]>(ADD_EVENT_LISTENER_METADATA_KEY, constructor);
|
|
35
41
|
if (!listeners) {
|
|
36
42
|
listeners = [];
|
|
37
43
|
ReflectUtils.defineMetadata(ADD_EVENT_LISTENER_METADATA_KEY, listeners, constructor);
|
|
@@ -42,18 +48,18 @@ export function addEventListener(selectorOrTarget: string, type: string, options
|
|
|
42
48
|
}
|
|
43
49
|
|
|
44
50
|
|
|
45
|
-
export function addEventListenerDelegateLightDom(selector:
|
|
46
|
-
return addEventListener(selector, type, {...options??{}, root:'light', delegate: true});
|
|
51
|
+
export function addEventListenerDelegateLightDom<TEvent extends Event = Event>(selector: EventListenerSelector, type: string, options?: Omit<AddEventListenerBaseOptions<TEvent>, 'delegate'>): MethodDecorator {
|
|
52
|
+
return addEventListener<TEvent>(selector, type, {...options??{}, root:'light', delegate: true});
|
|
47
53
|
}
|
|
48
54
|
|
|
49
|
-
export function addEventListenerDelegateShadowDom(selector:
|
|
50
|
-
return addEventListener(selector, type, {...options??{}, root:'shadow', delegate: true});
|
|
55
|
+
export function addEventListenerDelegateShadowDom<TEvent extends Event = Event>(selector: EventListenerSelector, type: string, options?: Omit<AddEventListenerBaseOptions<TEvent>, 'delegate'>): MethodDecorator {
|
|
56
|
+
return addEventListener<TEvent>(selector, type, {...options??{}, root:'shadow', delegate: true});
|
|
51
57
|
}
|
|
52
|
-
export function addEventListenerDelegateAllDom(selector:
|
|
53
|
-
return addEventListener(selector, type, {...options??{}, root:'all', delegate: true});
|
|
58
|
+
export function addEventListenerDelegateAllDom<TEvent extends Event = Event>(selector: EventListenerSelector, type: string, options?: Omit<AddEventListenerBaseOptions<TEvent>, 'delegate'>): MethodDecorator {
|
|
59
|
+
return addEventListener<TEvent>(selector, type, {...options??{}, root:'all', delegate: true});
|
|
54
60
|
}
|
|
55
|
-
export function addEventListenerDelegate(selector:
|
|
56
|
-
return addEventListener(selector, type, {...options??{}, root:'auto', delegate: true});
|
|
61
|
+
export function addEventListenerDelegate<TEvent extends Event = Event>(selector: EventListenerSelector, type: string, options?: Omit<AddEventListenerBaseOptions<TEvent>, 'delegate'>): MethodDecorator {
|
|
62
|
+
return addEventListener<TEvent>(selector, type, {...options??{}, root:'auto', delegate: true});
|
|
57
63
|
}
|
|
58
64
|
|
|
59
65
|
/**
|
|
@@ -66,25 +72,25 @@ export const eventDelegateLightDom = addEventListenerDelegateLightDom;
|
|
|
66
72
|
export const eventDelegateShadowDom = addEventListenerDelegateShadowDom;
|
|
67
73
|
export const eventDelegateAllDom = addEventListenerDelegateAllDom;
|
|
68
74
|
export const eventDelegate = addEventListenerDelegate;
|
|
69
|
-
export function addEventListenerThis(type: string, options?: AddEventListenerBaseOptions & SwcQueryOptions): MethodDecorator {
|
|
70
|
-
return addEventListener('$this', type, options);
|
|
75
|
+
export function addEventListenerThis<TEvent extends Event = Event>(type: string, options?: AddEventListenerBaseOptions<TEvent> & SwcQueryOptions): MethodDecorator {
|
|
76
|
+
return addEventListener<TEvent>('$this', type, options);
|
|
71
77
|
}
|
|
72
78
|
|
|
73
79
|
/**
|
|
74
80
|
* @addEventListenerAppHost decorator - simplified version of @addEventListener for $appHost selector
|
|
75
81
|
*/
|
|
76
|
-
export function addEventListenerAppHost(type: string, options?: AddEventListenerBaseOptions & SwcQueryOptions): MethodDecorator {
|
|
77
|
-
return addEventListener('$appHost', type, options);
|
|
82
|
+
export function addEventListenerAppHost<TEvent extends Event = Event>(type: string, options?: AddEventListenerBaseOptions<TEvent> & SwcQueryOptions): MethodDecorator {
|
|
83
|
+
return addEventListener<TEvent>('$appHost', type, options);
|
|
78
84
|
}
|
|
79
85
|
|
|
80
|
-
export function addEventListenerWindow(type: string, options?: AddEventListenerBaseOptions & SwcQueryOptions): MethodDecorator {
|
|
81
|
-
return addEventListener('$window', type, options);
|
|
86
|
+
export function addEventListenerWindow<TEvent extends Event = Event>(type: string, options?: AddEventListenerBaseOptions<TEvent> & SwcQueryOptions): MethodDecorator {
|
|
87
|
+
return addEventListener<TEvent>('$window', type, options);
|
|
82
88
|
}
|
|
83
|
-
export function addEventListenerDocument(type: string, options?: AddEventListenerBaseOptions & SwcQueryOptions): MethodDecorator {
|
|
84
|
-
return addEventListener('$document', type, options);
|
|
89
|
+
export function addEventListenerDocument<TEvent extends Event = Event>(type: string, options?: AddEventListenerBaseOptions<TEvent> & SwcQueryOptions): MethodDecorator {
|
|
90
|
+
return addEventListener<TEvent>('$document', type, options);
|
|
85
91
|
}
|
|
86
92
|
|
|
87
|
-
export const getAddEventListenerMetadata = (target: any): AddEventListenerMetadata[] | undefined => {
|
|
93
|
+
export const getAddEventListenerMetadata = (target: any): AddEventListenerMetadata<Event>[] | undefined => {
|
|
88
94
|
const constructor = target instanceof Function ? target : target.constructor;
|
|
89
95
|
return ReflectUtils.getMetadata(ADD_EVENT_LISTENER_METADATA_KEY, constructor);
|
|
90
96
|
};
|
|
@@ -40,9 +40,11 @@ export interface AttributeOptions extends SwcQueryOptions {
|
|
|
40
40
|
valueKey?: symbol | string;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
export type AttributeSelector = string | ((currentThis: any, helper: HelperHostSet) => NodeList | Element | Element[] | null);
|
|
44
|
+
|
|
43
45
|
export interface AttributeMetadata {
|
|
44
46
|
propertyKey: string | symbol;
|
|
45
|
-
selector:
|
|
47
|
+
selector: AttributeSelector;
|
|
46
48
|
targetAttributeName: string;
|
|
47
49
|
options: AttributeOptions;
|
|
48
50
|
type: 'property' | 'method';
|
|
@@ -54,6 +56,36 @@ export const ATTRIBUTE_METADATA_KEY = Symbol.for('simple-web-component:attribute
|
|
|
54
56
|
// Utilities
|
|
55
57
|
// ============================================
|
|
56
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Determine if a string is a CSS selector or an attribute name
|
|
61
|
+
*
|
|
62
|
+
* CSS selectors typically:
|
|
63
|
+
* - Start with: #, ., [, :, >, +, ~
|
|
64
|
+
* - Contain special chars: >, +, ~, :, [, ]
|
|
65
|
+
* - Are special keywords: $this, $host, $parentHost, etc.
|
|
66
|
+
*
|
|
67
|
+
* Attribute names are typically:
|
|
68
|
+
* - kebab-case (lowercase with hyphens)
|
|
69
|
+
* - No special selector syntax
|
|
70
|
+
*
|
|
71
|
+
* @param str - String to check
|
|
72
|
+
* @returns true if it's a CSS selector, false if it's an attribute name
|
|
73
|
+
*/
|
|
74
|
+
const isCssSelector = (str: string): boolean => {
|
|
75
|
+
if (!str) return false;
|
|
76
|
+
|
|
77
|
+
// Special keywords
|
|
78
|
+
if (str.startsWith('$')) return true;
|
|
79
|
+
|
|
80
|
+
// CSS selector syntax
|
|
81
|
+
if (/^[#.\[\:>+~]/.test(str)) return true;
|
|
82
|
+
|
|
83
|
+
// Contains CSS combinator or pseudo-selector syntax
|
|
84
|
+
if (/[>+~:\[\]]/.test(str)) return true;
|
|
85
|
+
|
|
86
|
+
return false;
|
|
87
|
+
};
|
|
88
|
+
|
|
57
89
|
const convertValue = (val: string | null, type: any): any => {
|
|
58
90
|
if (val === null || val === undefined) return val;
|
|
59
91
|
if (type === Number) return Number(val);
|
|
@@ -63,7 +95,7 @@ const convertValue = (val: string | null, type: any): any => {
|
|
|
63
95
|
|
|
64
96
|
export {convertValue};
|
|
65
97
|
|
|
66
|
-
export const getAttributeValue = (inst: any, attrName: string, options?: AttributeOptions & { selector?:
|
|
98
|
+
export const getAttributeValue = (inst: any, attrName: string, options?: AttributeOptions & { selector?: AttributeSelector }): any => {
|
|
67
99
|
const conf = getElementConfig(inst);
|
|
68
100
|
const currentWin = inst._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as any);
|
|
69
101
|
|
|
@@ -101,15 +133,42 @@ export const getAttributeValue = (inst: any, attrName: string, options?: Attribu
|
|
|
101
133
|
|
|
102
134
|
/**
|
|
103
135
|
* Resolve target elements based on selector and options
|
|
104
|
-
* Handles special selectors ($this, $host, etc.) and
|
|
136
|
+
* Handles special selectors ($this, $host, etc.), CSS selectors, and function-based selectors
|
|
105
137
|
* Returns HTMLElement[] for attribute operations
|
|
106
138
|
*/
|
|
107
|
-
export const resolveAttributeTargets = (inst: any, selector:
|
|
139
|
+
export const resolveAttributeTargets = (inst: any, selector: AttributeSelector, options: AttributeOptions): HTMLElement[] => {
|
|
108
140
|
const conf = getElementConfig(inst);
|
|
109
141
|
const currentWin = conf.window;
|
|
110
142
|
const r = options.root || 'auto';
|
|
111
143
|
const results: HTMLElement[] = [];
|
|
112
144
|
|
|
145
|
+
// Resolve selector if it's a function
|
|
146
|
+
let resolvedSelector: string | Element | NodeList | Element[] | null = selector as any;
|
|
147
|
+
if (typeof selector === 'function') {
|
|
148
|
+
const hostSet = SwcUtils.getHelperAndHostSet(currentWin, inst);
|
|
149
|
+
resolvedSelector = selector(inst, hostSet);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// If selector function returned elements directly, use them
|
|
153
|
+
if (resolvedSelector instanceof currentWin.Element) {
|
|
154
|
+
results.push(resolvedSelector as HTMLElement);
|
|
155
|
+
return results;
|
|
156
|
+
}
|
|
157
|
+
if (resolvedSelector instanceof currentWin.NodeList) {
|
|
158
|
+
results.push(...(Array.from(resolvedSelector) as HTMLElement[]));
|
|
159
|
+
return results;
|
|
160
|
+
}
|
|
161
|
+
if (Array.isArray(resolvedSelector)) {
|
|
162
|
+
results.push(...(resolvedSelector as HTMLElement[]));
|
|
163
|
+
return results;
|
|
164
|
+
}
|
|
165
|
+
if (resolvedSelector === null) {
|
|
166
|
+
return results;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Handle string selector
|
|
170
|
+
const stringSelector = resolvedSelector as string;
|
|
171
|
+
|
|
113
172
|
const applyRoot = (target: any) => {
|
|
114
173
|
if (!target) return;
|
|
115
174
|
if (r === 'auto') {
|
|
@@ -120,33 +179,33 @@ export const resolveAttributeTargets = (inst: any, selector: string, options: At
|
|
|
120
179
|
}
|
|
121
180
|
};
|
|
122
181
|
|
|
123
|
-
if (
|
|
182
|
+
if (stringSelector === '$this' || !stringSelector) {
|
|
124
183
|
applyRoot(inst);
|
|
125
184
|
} else {
|
|
126
185
|
const hostSet = SwcUtils.getHostSet(inst);
|
|
127
|
-
if (
|
|
128
|
-
else if (
|
|
129
|
-
else if (
|
|
130
|
-
else if (
|
|
131
|
-
else if (
|
|
132
|
-
else if (
|
|
133
|
-
else if (
|
|
134
|
-
else if (
|
|
135
|
-
else if (
|
|
186
|
+
if (stringSelector === '$host') applyRoot(hostSet.$host);
|
|
187
|
+
else if (stringSelector === '$parentHost') applyRoot(hostSet.$parentHost);
|
|
188
|
+
else if (stringSelector === '$appHost') applyRoot(hostSet.$appHost as any);
|
|
189
|
+
else if (stringSelector === '$firstHost') applyRoot(hostSet.$firstHost);
|
|
190
|
+
else if (stringSelector === '$lastHost') applyRoot(hostSet.$lastHost);
|
|
191
|
+
else if (stringSelector === '$firstAppHost') applyRoot(hostSet.$firstAppHost as any);
|
|
192
|
+
else if (stringSelector === '$lastAppHost') applyRoot(hostSet.$lastAppHost as any);
|
|
193
|
+
else if (stringSelector === '$hosts') hostSet.$hosts.forEach(applyRoot);
|
|
194
|
+
else if (stringSelector === '$appHosts') hostSet.$appHosts.forEach(applyRoot);
|
|
136
195
|
else {
|
|
137
196
|
if (r === 'shadow') {
|
|
138
|
-
const found = inst.shadowRoot?.querySelectorAll(
|
|
197
|
+
const found = inst.shadowRoot?.querySelectorAll(stringSelector);
|
|
139
198
|
if (found) results.push(...found);
|
|
140
199
|
} else if (r === 'light') {
|
|
141
|
-
const found = inst.querySelectorAll(
|
|
200
|
+
const found = inst.querySelectorAll(stringSelector);
|
|
142
201
|
if (found) results.push(...found);
|
|
143
202
|
} else if (r === 'all') {
|
|
144
|
-
const sMatch = inst.shadowRoot?.querySelectorAll(
|
|
145
|
-
const lMatch = inst.querySelectorAll(
|
|
203
|
+
const sMatch = inst.shadowRoot?.querySelectorAll(stringSelector);
|
|
204
|
+
const lMatch = inst.querySelectorAll(stringSelector);
|
|
146
205
|
if (sMatch) results.push(...sMatch);
|
|
147
206
|
if (lMatch) results.push(...lMatch);
|
|
148
207
|
} else {
|
|
149
|
-
const found = (inst.shadowRoot || inst).querySelectorAll(
|
|
208
|
+
const found = (inst.shadowRoot || inst).querySelectorAll(stringSelector);
|
|
150
209
|
if (found) results.push(...found);
|
|
151
210
|
}
|
|
152
211
|
}
|
|
@@ -161,11 +220,12 @@ export const resolveAttributeTargets = (inst: any, selector: string, options: At
|
|
|
161
220
|
* - @applyAttribute('selector', 'attrName') - Set attribute with explicit name
|
|
162
221
|
* - @applyAttribute('selector') - Use property name as attribute name
|
|
163
222
|
* - @applyAttribute('selector', { name: 'attrName' }) - Set attribute via options
|
|
223
|
+
* - @applyAttribute((this, helper) => 'selector', 'attrName') - Function-based selector
|
|
164
224
|
* - Return null to remove attribute
|
|
165
225
|
*/
|
|
166
|
-
export function applyAttribute(selector:
|
|
167
|
-
export function applyAttribute(selector:
|
|
168
|
-
export function applyAttribute(selector:
|
|
226
|
+
export function applyAttribute(selector: AttributeSelector, targetAttributeName: string, options?: AttributeOptions): MethodDecorator & PropertyDecorator;
|
|
227
|
+
export function applyAttribute(selector: AttributeSelector, options?: AttributeOptions): MethodDecorator & PropertyDecorator;
|
|
228
|
+
export function applyAttribute(selector: AttributeSelector, targetAttributeNameOrOptions?: string | AttributeOptions, options?: AttributeOptions): MethodDecorator & PropertyDecorator {
|
|
169
229
|
return (target: Object, propertyKey: string | symbol, descriptor?: PropertyDescriptor) => {
|
|
170
230
|
// ensureInit(target as any);
|
|
171
231
|
|
|
@@ -198,7 +258,7 @@ export function applyAttribute(selector: string, targetAttributeNameOrOptions?:
|
|
|
198
258
|
}
|
|
199
259
|
metaList.push({
|
|
200
260
|
propertyKey,
|
|
201
|
-
selector,
|
|
261
|
+
selector: selector as AttributeSelector,
|
|
202
262
|
targetAttributeName,
|
|
203
263
|
options: finalOptions,
|
|
204
264
|
type: metaType
|
|
@@ -307,77 +367,95 @@ export function applyAttribute(selector: string, targetAttributeNameOrOptions?:
|
|
|
307
367
|
// ============================================
|
|
308
368
|
|
|
309
369
|
/**
|
|
310
|
-
* @attribute -
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
* @
|
|
320
|
-
*
|
|
370
|
+
* @attribute - Field decorator for binding element attributes (read/write)
|
|
371
|
+
*
|
|
372
|
+
* Intelligently distinguishes between attribute names and CSS selectors:
|
|
373
|
+
*
|
|
374
|
+
* Usage patterns:
|
|
375
|
+
* - @attribute('product-id') - Attribute name on $this (auto-detected)
|
|
376
|
+
* - @attribute('#user', 'product-id') - Attribute name on selector
|
|
377
|
+
* - @attribute('product-id', options) - Attribute name on $this with options
|
|
378
|
+
* - @attribute('#user', 'product-id', options) - Attribute name on selector with options
|
|
379
|
+
* - @attribute((this, helper) => 'selector', 'product-id') - Function-based selector
|
|
380
|
+
* - @attribute - Bare decorator (uses property name as attribute on $this)
|
|
381
|
+
*
|
|
382
|
+
* Note: This decorator is for FIELDS ONLY. For methods, use @setAttribute.
|
|
321
383
|
*/
|
|
322
|
-
export function
|
|
323
|
-
export function
|
|
324
|
-
export function
|
|
325
|
-
export function
|
|
326
|
-
//
|
|
327
|
-
if (typeof
|
|
328
|
-
|
|
329
|
-
// Called as @attributeThis (target, propertyKey)
|
|
330
|
-
return applyAttribute('$this', undefined as any, {})(targetOrOptions, propertyKeyOrOptions, descriptor);
|
|
384
|
+
export function attribute(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
|
|
385
|
+
export function attribute(attributeName: string, options?: AttributeOptions): PropertyDecorator;
|
|
386
|
+
export function attribute(selector: AttributeSelector, attributeName: string, options?: AttributeOptions): PropertyDecorator;
|
|
387
|
+
export function attribute(selectorOrAttributeOrTarget?: AttributeSelector | Object, attributeNameOrOptions?: any, optionsOrDescriptor?: any): any {
|
|
388
|
+
// Bare decorator: @attribute
|
|
389
|
+
if (optionsOrDescriptor !== undefined && (typeof attributeNameOrOptions === 'string' || typeof attributeNameOrOptions === 'symbol')) {
|
|
390
|
+
return applyAttribute('$this', undefined as any, {})(selectorOrAttributeOrTarget as Object, attributeNameOrOptions, optionsOrDescriptor as PropertyDescriptor);
|
|
331
391
|
}
|
|
332
|
-
|
|
333
|
-
//
|
|
334
|
-
if (typeof
|
|
335
|
-
//
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
392
|
+
|
|
393
|
+
// With string as first parameter
|
|
394
|
+
if (typeof selectorOrAttributeOrTarget === 'string') {
|
|
395
|
+
// Check if first parameter is a CSS selector or attribute name
|
|
396
|
+
const isSelector = isCssSelector(selectorOrAttributeOrTarget);
|
|
397
|
+
|
|
398
|
+
if (isSelector) {
|
|
399
|
+
// First param is a selector: @attribute('#user', 'product-id', options?)
|
|
400
|
+
return applyAttribute(selectorOrAttributeOrTarget, attributeNameOrOptions as any, optionsOrDescriptor as AttributeOptions);
|
|
401
|
+
} else {
|
|
402
|
+
// First param is an attribute name: @attribute('product-id', options?)
|
|
403
|
+
// Treat as attribute name on $this
|
|
404
|
+
const options = (typeof attributeNameOrOptions === 'object' && attributeNameOrOptions !== null)
|
|
405
|
+
? attributeNameOrOptions
|
|
406
|
+
: {};
|
|
407
|
+
return applyAttribute('$this', selectorOrAttributeOrTarget, options);
|
|
408
|
+
}
|
|
343
409
|
}
|
|
410
|
+
|
|
411
|
+
// Without selector (defaults to $this with options)
|
|
412
|
+
return applyAttribute('$this', undefined as any, selectorOrAttributeOrTarget as AttributeOptions);
|
|
344
413
|
}
|
|
345
414
|
|
|
346
415
|
/**
|
|
347
|
-
* @setAttribute -
|
|
416
|
+
* @setAttribute - Method decorator for setting element attributes from method return value
|
|
417
|
+
*
|
|
418
|
+
* Intelligently distinguishes between attribute names and CSS selectors:
|
|
419
|
+
*
|
|
420
|
+
* Usage patterns:
|
|
421
|
+
* - @setAttribute('data-id') - Attribute name on $this (auto-detected)
|
|
422
|
+
* - @setAttribute('#user', 'data-id') - Attribute name on selector
|
|
423
|
+
* - @setAttribute('data-id', options) - Attribute name on $this with options
|
|
424
|
+
* - @setAttribute('#user', 'data-id', options) - Attribute name on selector with options
|
|
425
|
+
* - @setAttribute((this, helper) => 'selector', 'data-id') - Function-based selector
|
|
426
|
+
* - @setAttribute - Bare decorator (uses method name as attribute on $this)
|
|
427
|
+
*
|
|
428
|
+
* Note: This decorator is for METHODS ONLY. For fields, use @attribute.
|
|
429
|
+
*
|
|
430
|
+
* Example:
|
|
431
|
+
* @setAttribute('data-status')
|
|
432
|
+
* updateStatus() {
|
|
433
|
+
* return 'active';
|
|
434
|
+
* }
|
|
348
435
|
*/
|
|
349
|
-
export function setAttribute(selector:
|
|
350
|
-
export function setAttribute(
|
|
351
|
-
export function setAttribute(
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
// Called with parameters
|
|
371
|
-
if (typeof targetOrOptions === 'string') {
|
|
372
|
-
// @setAttributeThis('attrName', options?)
|
|
373
|
-
return applyAttribute('$this', targetOrOptions, propertyKeyOrOptions) as MethodDecorator;
|
|
374
|
-
} else if (targetOrOptions && typeof targetOrOptions === 'object') {
|
|
375
|
-
// @setAttributeThis({ name: 'attrName' })
|
|
376
|
-
return applyAttribute('$this', undefined as any, targetOrOptions) as MethodDecorator;
|
|
377
|
-
} else {
|
|
378
|
-
// @setAttributeThis() or @setAttributeThis
|
|
379
|
-
return applyAttribute('$this', undefined as any, {}) as MethodDecorator;
|
|
436
|
+
export function setAttribute(selector: AttributeSelector, attributeName: string, options?: AttributeOptions): MethodDecorator;
|
|
437
|
+
export function setAttribute(attributeName: string, options?: AttributeOptions): MethodDecorator;
|
|
438
|
+
export function setAttribute(selectorOrAttributeOrOptions?: AttributeSelector | AttributeOptions, attributeNameOrOptions?: any, optionsOrUndefined?: AttributeOptions): MethodDecorator {
|
|
439
|
+
// With string as first parameter
|
|
440
|
+
if (typeof selectorOrAttributeOrOptions === 'string') {
|
|
441
|
+
// Check if first parameter is a CSS selector or attribute name
|
|
442
|
+
const isSelector = isCssSelector(selectorOrAttributeOrOptions);
|
|
443
|
+
|
|
444
|
+
if (isSelector) {
|
|
445
|
+
// First param is a selector: @setAttribute('#user', 'data-id', options?)
|
|
446
|
+
return applyAttribute(selectorOrAttributeOrOptions, attributeNameOrOptions as any, optionsOrUndefined as AttributeOptions) as MethodDecorator;
|
|
447
|
+
} else {
|
|
448
|
+
// First param is an attribute name: @setAttribute('data-id', options?)
|
|
449
|
+
// Treat as attribute name on $this
|
|
450
|
+
const options = (typeof attributeNameOrOptions === 'object' && attributeNameOrOptions !== null)
|
|
451
|
+
? attributeNameOrOptions
|
|
452
|
+
: {};
|
|
453
|
+
return applyAttribute('$this', selectorOrAttributeOrOptions, options) as MethodDecorator;
|
|
454
|
+
}
|
|
380
455
|
}
|
|
456
|
+
|
|
457
|
+
// Without selector (defaults to $this with options)
|
|
458
|
+
return applyAttribute('$this', undefined as any, selectorOrAttributeOrOptions as AttributeOptions) as MethodDecorator;
|
|
381
459
|
}
|
|
382
460
|
|
|
383
461
|
// ============================================
|