@dooboostore/simple-web-component 1.0.19 → 1.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2759 -201
- package/dist/cjs/decorators/addEventListener.js +8 -4
- package/dist/cjs/decorators/addEventListener.js.map +2 -2
- package/dist/cjs/decorators/{appendChild.js → applyNode.js} +26 -18
- package/dist/cjs/decorators/applyNode.js.map +7 -0
- package/dist/cjs/decorators/attribute.js +162 -0
- package/dist/cjs/decorators/attribute.js.map +7 -0
- package/dist/cjs/decorators/{changedAttribute.js → changedAttributeHost.js} +11 -11
- package/dist/cjs/decorators/changedAttributeHost.js.map +7 -0
- package/dist/cjs/decorators/classList.js +15 -5
- package/dist/cjs/decorators/classList.js.map +2 -2
- package/dist/cjs/decorators/elementDefine.js +124 -46
- package/dist/cjs/decorators/elementDefine.js.map +3 -3
- package/dist/cjs/decorators/emitCustomEvent.js +8 -7
- package/dist/cjs/decorators/emitCustomEvent.js.map +2 -2
- package/dist/cjs/decorators/index.js +3 -3
- package/dist/cjs/decorators/index.js.map +2 -2
- package/dist/cjs/decorators/lifecycles.js +8 -4
- package/dist/cjs/decorators/lifecycles.js.map +2 -2
- package/dist/cjs/decorators/onConnectedInnerHtml.js +4 -4
- package/dist/cjs/decorators/onConnectedInnerHtml.js.map +2 -2
- package/dist/cjs/decorators/query.js +9 -5
- package/dist/cjs/decorators/query.js.map +2 -2
- package/dist/cjs/decorators/queryAll.js +9 -5
- package/dist/cjs/decorators/queryAll.js.map +2 -2
- package/dist/cjs/decorators/setAttribute.js +51 -21
- package/dist/cjs/decorators/setAttribute.js.map +2 -2
- package/dist/cjs/decorators/style.js +4 -4
- package/dist/cjs/decorators/style.js.map +2 -2
- package/dist/cjs/elements/SwcAppEngine.js +8 -8
- package/dist/cjs/elements/SwcAppEngine.js.map +3 -3
- package/dist/cjs/elements/SwcAppMixin.js +28 -1
- package/dist/cjs/elements/SwcAppMixin.js.map +2 -2
- package/dist/cjs/elements/SwcAsync.js +6 -6
- package/dist/cjs/elements/SwcAsync.js.map +2 -2
- package/dist/cjs/elements/SwcChoose.js +6 -6
- package/dist/cjs/elements/SwcChoose.js.map +2 -2
- package/dist/cjs/elements/SwcIf.js +6 -6
- package/dist/cjs/elements/SwcIf.js.map +2 -2
- package/dist/cjs/elements/SwcLoop.js +6 -6
- package/dist/cjs/elements/SwcLoop.js.map +2 -2
- package/dist/cjs/elements/register.js +19 -18
- package/dist/cjs/elements/register.js.map +2 -2
- package/dist/cjs/index.js +6 -17
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/router/ElementRouter.js +7 -7
- package/dist/cjs/router/ElementRouter.js.map +2 -2
- package/dist/cjs/types.js.map +2 -2
- package/dist/esm/decorators/addEventListener.js +5 -1
- package/dist/esm/decorators/addEventListener.js.map +2 -2
- package/dist/esm/decorators/{appendChild.js → applyNode.js} +23 -15
- package/dist/esm/decorators/applyNode.js.map +7 -0
- package/dist/esm/decorators/attribute.js +143 -0
- package/dist/esm/decorators/attribute.js.map +7 -0
- package/dist/esm/decorators/{changedAttribute.js → changedAttributeHost.js} +4 -4
- package/dist/esm/decorators/changedAttributeHost.js.map +7 -0
- package/dist/esm/decorators/classList.js +12 -2
- package/dist/esm/decorators/classList.js.map +2 -2
- package/dist/esm/decorators/elementDefine.js +119 -41
- package/dist/esm/decorators/elementDefine.js.map +2 -2
- package/dist/esm/decorators/emitCustomEvent.js +5 -4
- package/dist/esm/decorators/emitCustomEvent.js.map +2 -2
- package/dist/esm/decorators/index.js +3 -3
- package/dist/esm/decorators/index.js.map +1 -1
- package/dist/esm/decorators/lifecycles.js +5 -1
- package/dist/esm/decorators/lifecycles.js.map +2 -2
- package/dist/esm/decorators/onConnectedInnerHtml.js +1 -1
- package/dist/esm/decorators/onConnectedInnerHtml.js.map +1 -1
- package/dist/esm/decorators/query.js +6 -2
- package/dist/esm/decorators/query.js.map +2 -2
- package/dist/esm/decorators/queryAll.js +6 -2
- package/dist/esm/decorators/queryAll.js.map +2 -2
- package/dist/esm/decorators/setAttribute.js +47 -17
- package/dist/esm/decorators/setAttribute.js.map +2 -2
- package/dist/esm/decorators/style.js +1 -1
- package/dist/esm/decorators/style.js.map +1 -1
- package/dist/esm/elements/SwcAppEngine.js +4 -4
- package/dist/esm/elements/SwcAppEngine.js.map +2 -2
- package/dist/esm/elements/SwcAppMixin.js +28 -1
- package/dist/esm/elements/SwcAppMixin.js.map +2 -2
- package/dist/esm/elements/SwcAsync.js +3 -3
- package/dist/esm/elements/SwcAsync.js.map +2 -2
- package/dist/esm/elements/SwcChoose.js +3 -3
- package/dist/esm/elements/SwcChoose.js.map +2 -2
- package/dist/esm/elements/SwcIf.js +3 -3
- package/dist/esm/elements/SwcIf.js.map +2 -2
- package/dist/esm/elements/SwcLoop.js +3 -3
- package/dist/esm/elements/SwcLoop.js.map +2 -2
- package/dist/esm/elements/register.js +7 -6
- package/dist/esm/elements/register.js.map +2 -2
- package/dist/esm/index.js +6 -17
- package/dist/esm/index.js.map +2 -2
- package/dist/esm/router/ElementRouter.js +2 -2
- package/dist/esm/router/ElementRouter.js.map +1 -1
- package/dist/esm/types.js.map +2 -2
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +5444 -3317
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
- package/dist/types/decorators/addEventListener.d.ts +6 -0
- package/dist/types/decorators/addEventListener.d.ts.map +1 -1
- package/dist/types/decorators/applyNode.d.ts +38 -0
- package/dist/types/decorators/applyNode.d.ts.map +1 -0
- package/dist/types/decorators/attribute.d.ts +29 -0
- package/dist/types/decorators/attribute.d.ts.map +1 -0
- package/dist/types/decorators/{changedAttribute.d.ts → changedAttributeHost.d.ts} +6 -2
- package/dist/types/decorators/changedAttributeHost.d.ts.map +1 -0
- package/dist/types/decorators/classList.d.ts +25 -0
- package/dist/types/decorators/classList.d.ts.map +1 -1
- package/dist/types/decorators/elementDefine.d.ts.map +1 -1
- package/dist/types/decorators/emitCustomEvent.d.ts +14 -2
- package/dist/types/decorators/emitCustomEvent.d.ts.map +1 -1
- package/dist/types/decorators/index.d.ts +3 -3
- package/dist/types/decorators/index.d.ts.map +1 -1
- package/dist/types/decorators/lifecycles.d.ts +2 -0
- package/dist/types/decorators/lifecycles.d.ts.map +1 -1
- package/dist/types/decorators/query.d.ts +6 -0
- package/dist/types/decorators/query.d.ts.map +1 -1
- package/dist/types/decorators/queryAll.d.ts +6 -0
- package/dist/types/decorators/queryAll.d.ts.map +1 -1
- package/dist/types/decorators/setAttribute.d.ts +8 -0
- package/dist/types/decorators/setAttribute.d.ts.map +1 -1
- package/dist/types/elements/SwcAppEngine.d.ts +5 -4
- package/dist/types/elements/SwcAppEngine.d.ts.map +1 -1
- package/dist/types/elements/SwcAppMixin.d.ts +1 -1
- package/dist/types/elements/SwcAppMixin.d.ts.map +1 -1
- package/dist/types/elements/register.d.ts +1 -1
- package/dist/types/elements/register.d.ts.map +1 -1
- package/dist/types/index.d.ts +3 -14
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/router/ElementRouter.d.ts +1 -1
- package/dist/types/router/ElementRouter.d.ts.map +1 -1
- package/dist/types/types.d.ts +3 -1
- package/dist/types/types.d.ts.map +1 -1
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +5444 -3317
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
- package/package.json +10 -5
- package/src/decorators/addEventListener.ts +10 -1
- package/src/decorators/applyNode.ts +127 -0
- package/src/decorators/attribute.ts +192 -0
- package/src/decorators/{changedAttribute.ts → changedAttributeHost.ts} +6 -2
- package/src/decorators/classList.ts +33 -1
- package/src/decorators/elementDefine.ts +148 -47
- package/src/decorators/emitCustomEvent.ts +14 -6
- package/src/decorators/index.ts +3 -3
- package/src/decorators/lifecycles.ts +4 -2
- package/src/decorators/onConnectedInnerHtml.ts +1 -1
- package/src/decorators/query.ts +10 -1
- package/src/decorators/queryAll.ts +10 -1
- package/src/decorators/setAttribute.ts +57 -17
- package/src/decorators/style.ts +1 -1
- package/src/elements/SwcAppEngine.ts +10 -8
- package/src/elements/SwcAppMixin.ts +34 -2
- package/src/elements/SwcAsync.ts +3 -3
- package/src/elements/SwcChoose.ts +3 -3
- package/src/elements/SwcIf.ts +3 -3
- package/src/elements/SwcLoop.ts +3 -3
- package/src/elements/register.ts +8 -6
- package/src/index.ts +8 -16
- package/src/router/ElementRouter.ts +2 -2
- package/src/types.ts +3 -1
- package/dist/cjs/decorators/appendChild.js.map +0 -7
- package/dist/cjs/decorators/changedAttribute.js.map +0 -7
- package/dist/cjs/decorators/replaceChildren.js +0 -79
- package/dist/cjs/decorators/replaceChildren.js.map +0 -7
- package/dist/esm/decorators/appendChild.js.map +0 -7
- package/dist/esm/decorators/changedAttribute.js.map +0 -7
- package/dist/esm/decorators/replaceChildren.js +0 -60
- package/dist/esm/decorators/replaceChildren.js.map +0 -7
- package/dist/types/decorators/appendChild.d.ts +0 -17
- package/dist/types/decorators/appendChild.d.ts.map +0 -1
- package/dist/types/decorators/changedAttribute.d.ts.map +0 -1
- package/dist/types/decorators/replaceChildren.d.ts +0 -9
- package/dist/types/decorators/replaceChildren.d.ts.map +0 -1
- package/src/decorators/appendChild.ts +0 -86
- package/src/decorators/replaceChildren.ts +0 -64
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dooboostore/simple-web-component",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.22",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -54,6 +54,11 @@
|
|
|
54
54
|
"import": "./dist/esm/index.js",
|
|
55
55
|
"require": "./dist/cjs/index.js"
|
|
56
56
|
},
|
|
57
|
+
"./bundle-entry": {
|
|
58
|
+
"types": "./dist/types/bundle-entry.d.ts",
|
|
59
|
+
"import": "./dist/esm/bundle-entry.js",
|
|
60
|
+
"require": "./dist/cjs/bundle-entry.js"
|
|
61
|
+
},
|
|
57
62
|
"./*": {
|
|
58
63
|
"types": "./dist/types/*.d.ts",
|
|
59
64
|
"import": "./dist/esm/*.js",
|
|
@@ -87,10 +92,10 @@
|
|
|
87
92
|
"webpack": "^5.93.0",
|
|
88
93
|
"webpack-cli": "^5.1.4",
|
|
89
94
|
"webpack-dev-server": "^5.2.0",
|
|
90
|
-
"@dooboostore/core": "1.0.
|
|
91
|
-
"@dooboostore/core
|
|
92
|
-
"@dooboostore/core-
|
|
93
|
-
"@dooboostore/simple-boot": "1.0.
|
|
95
|
+
"@dooboostore/core-web": "1.0.10",
|
|
96
|
+
"@dooboostore/core": "1.0.30",
|
|
97
|
+
"@dooboostore/core-node": "1.0.12",
|
|
98
|
+
"@dooboostore/simple-boot": "1.0.54"
|
|
94
99
|
},
|
|
95
100
|
"scripts": {
|
|
96
101
|
"clean": "rm -rf dist",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ReflectUtils } from '@dooboostore/core
|
|
1
|
+
import { ReflectUtils } from '@dooboostore/core';
|
|
2
2
|
import { SpecialSelector, SwcQueryOptions } from '../types';
|
|
3
3
|
|
|
4
4
|
export interface AddEventListenerBaseOptions extends EventListenerOptions {
|
|
@@ -44,3 +44,12 @@ export const getAddEventListenerMetadata = (target: any): AddEventListenerMetada
|
|
|
44
44
|
const constructor = target instanceof Function ? target : target.constructor;
|
|
45
45
|
return ReflectUtils.getMetadata(ADD_EVENT_LISTENER_METADATA_KEY, constructor);
|
|
46
46
|
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @addEventListenerHost decorator - simplified version of @addEventListener for :host selector
|
|
50
|
+
* Usage: @addEventListenerHost('click')
|
|
51
|
+
* Usage: @addEventListenerHost('click', { stopPropagation: true })
|
|
52
|
+
*/
|
|
53
|
+
export function addEventListenerHost(type: string, options?: AddEventListenerBaseOptions & SwcQueryOptions): MethodDecorator {
|
|
54
|
+
return addEventListener(':host', type, options);
|
|
55
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { ReflectUtils } from '@dooboostore/core';
|
|
2
|
+
import { ensureInit, getElementConfig } from './elementDefine';
|
|
3
|
+
|
|
4
|
+
export type ApplyNodePosition = 'beforeBegin' | 'afterBegin' | 'beforeEnd' | 'afterEnd' | 'replace' | 'replaceChildren' | 'innerHtml' | 'innerText';
|
|
5
|
+
|
|
6
|
+
export interface ApplyNodeOptions {
|
|
7
|
+
position?: ApplyNodePosition;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ApplyNodeMetadata {
|
|
11
|
+
propertyKey: string | symbol;
|
|
12
|
+
selector: string;
|
|
13
|
+
options: ApplyNodeOptions;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const APPLY_NODE_METADATA_KEY = Symbol('simple-web-component:apply-node');
|
|
17
|
+
|
|
18
|
+
const normalizeNodes = (res: any, doc: Document): Node[] => {
|
|
19
|
+
const items = Array.isArray(res) ? res : [res];
|
|
20
|
+
return items.map(it => {
|
|
21
|
+
if (it instanceof Node) return it;
|
|
22
|
+
return doc.createTextNode(it !== undefined && it !== null ? String(it) : '');
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @applyNode decorator to surgically add/replace nodes to a target element.
|
|
28
|
+
*
|
|
29
|
+
* Usage examples:
|
|
30
|
+
* @applyNode('#list') addItem() { return '<li>New Item</li>'; } // append at end
|
|
31
|
+
* @applyNode('#header', { position: 'afterBegin' }) prependItem() { return '<h1>Title</h1>'; } // prepend at start
|
|
32
|
+
* @applyNode('#item', { position: 'replace' }) replaceItem() { return '<div>Replaced</div>'; } // replace element
|
|
33
|
+
* @applyNode('#list', { position: 'replaceChildren' }) updateList() { return [item1, item2]; } // replace all children
|
|
34
|
+
*
|
|
35
|
+
* Positions:
|
|
36
|
+
* - 'beforeEnd' (default): Append at end of target
|
|
37
|
+
* - 'afterBegin': Prepend at start of target
|
|
38
|
+
* - 'beforeBegin': Insert before target
|
|
39
|
+
* - 'afterEnd': Insert after target
|
|
40
|
+
* - 'replace': Replace the entire target element
|
|
41
|
+
* - 'replaceChildren': Replace all children of target element
|
|
42
|
+
* - 'innerHtml': Set target's innerHTML
|
|
43
|
+
* - 'innerText': Set target's innerText
|
|
44
|
+
*/
|
|
45
|
+
export function applyNode(selector: string, options: ApplyNodeOptions = { position: 'beforeEnd' }): MethodDecorator {
|
|
46
|
+
return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
|
|
47
|
+
const constructor = target.constructor;
|
|
48
|
+
let metaList = ReflectUtils.getOwnMetadata(APPLY_NODE_METADATA_KEY, constructor) as Map<string | symbol, ApplyNodeMetadata>;
|
|
49
|
+
if (!metaList) {
|
|
50
|
+
metaList = new Map<string | symbol, ApplyNodeMetadata>();
|
|
51
|
+
ReflectUtils.defineMetadata(APPLY_NODE_METADATA_KEY, metaList, constructor);
|
|
52
|
+
}
|
|
53
|
+
metaList.set(propertyKey, { propertyKey, selector, options });
|
|
54
|
+
|
|
55
|
+
const original = descriptor.value;
|
|
56
|
+
descriptor.value = async function (...args: any[]) {
|
|
57
|
+
ensureInit(this);
|
|
58
|
+
const res = await original.apply(this, args);
|
|
59
|
+
if (res !== undefined) {
|
|
60
|
+
const conf = getElementConfig(this);
|
|
61
|
+
const currentWin = (this as any)._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as Window);
|
|
62
|
+
const currentDoc = currentWin.document;
|
|
63
|
+
|
|
64
|
+
let targetEl: HTMLElement | null = null;
|
|
65
|
+
if (selector === ':host' || !selector) {
|
|
66
|
+
targetEl = this as any;
|
|
67
|
+
} else {
|
|
68
|
+
targetEl = (this.shadowRoot || (this as any)).querySelector(selector);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (targetEl) {
|
|
72
|
+
const nodes = normalizeNodes(res, currentDoc);
|
|
73
|
+
const pos = options.position || 'beforeEnd';
|
|
74
|
+
|
|
75
|
+
if (pos === 'replace') {
|
|
76
|
+
// Replace the entire target element with new nodes
|
|
77
|
+
targetEl.replaceWith(...nodes);
|
|
78
|
+
} else if (pos === 'replaceChildren') {
|
|
79
|
+
// Replace all children of target element
|
|
80
|
+
targetEl.replaceChildren(...nodes);
|
|
81
|
+
} else if (pos === 'innerHtml') {
|
|
82
|
+
// Set innerHTML
|
|
83
|
+
targetEl.innerHTML = res !== undefined && res !== null ? String(res) : '';
|
|
84
|
+
} else if (pos === 'innerText') {
|
|
85
|
+
// Set innerText
|
|
86
|
+
targetEl.innerText = res !== undefined && res !== null ? String(res) : '';
|
|
87
|
+
} else {
|
|
88
|
+
/*
|
|
89
|
+
<!-- beforebegin -->
|
|
90
|
+
<p>
|
|
91
|
+
<!-- afterbegin -->
|
|
92
|
+
foo
|
|
93
|
+
<!-- beforeend -->
|
|
94
|
+
</p>
|
|
95
|
+
<!-- afterend -->
|
|
96
|
+
*/
|
|
97
|
+
if (pos === 'beforeEnd') targetEl.append(...nodes);
|
|
98
|
+
else if (pos === 'afterBegin') targetEl.prepend(...nodes);
|
|
99
|
+
else if (pos === 'beforeBegin') targetEl.before(...nodes);
|
|
100
|
+
else if (pos === 'afterEnd') targetEl.after(...nodes);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return res;
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export const findAllApplyNodeMetadata = (target: any): Map<string | symbol, ApplyNodeMetadata> => {
|
|
110
|
+
const result = new Map<string | symbol, ApplyNodeMetadata>();
|
|
111
|
+
const maps = ReflectUtils.findAllMetadata<Map<string | symbol, ApplyNodeMetadata>>(APPLY_NODE_METADATA_KEY, target);
|
|
112
|
+
maps.forEach(map => {
|
|
113
|
+
if (map instanceof Map) {
|
|
114
|
+
map.forEach((v, k) => result.set(k, v));
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
return result;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* @applyNodeHost decorator - simplified version of @applyNode for :host selector
|
|
122
|
+
* Usage: @applyNodeHost() addItem() { return '<li>New Item</li>'; }
|
|
123
|
+
* Usage: @applyNodeHost({ position: 'afterBegin' }) prependItem() { return '<h1>Title</h1>'; }
|
|
124
|
+
*/
|
|
125
|
+
export function applyNodeHost(options: ApplyNodeOptions = { position: 'beforeEnd' }): MethodDecorator {
|
|
126
|
+
return applyNode(':host', options);
|
|
127
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { ReflectUtils } from '@dooboostore/core';
|
|
2
|
+
import { ensureInit, getElementConfig } from './elementDefine';
|
|
3
|
+
import { SwcUtils } from '../utils/Utils';
|
|
4
|
+
import { SpecialSelector, SwcQueryOptions } from '../types';
|
|
5
|
+
|
|
6
|
+
export interface AttributeOptions extends SwcQueryOptions {
|
|
7
|
+
name?: string;
|
|
8
|
+
connectedInitialize?: boolean;
|
|
9
|
+
type?: typeof Number | typeof Boolean | typeof String;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface AttributeMetadata {
|
|
13
|
+
propertyKey: string | symbol;
|
|
14
|
+
selector: string;
|
|
15
|
+
options: AttributeOptions;
|
|
16
|
+
privateKey: symbol; // Added to bypass getter during initialization
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const ATTRIBUTE_METADATA_KEY = Symbol('simple-web-component:attribute');
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Helper to perform type conversion from string to target type
|
|
23
|
+
*/
|
|
24
|
+
const convertValue = (val: string | null, type: any): any => {
|
|
25
|
+
if (val === null || val === undefined) return val;
|
|
26
|
+
if (type === Number) return Number(val);
|
|
27
|
+
if (type === Boolean) return val === 'false' || val === '0' ? false : true;
|
|
28
|
+
return val;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Helper to resolve target elements based on selector and root options
|
|
33
|
+
*/
|
|
34
|
+
export const resolveTargetEls = (inst: any, selector: string, options: AttributeOptions, currentWin: any): HTMLElement[] => {
|
|
35
|
+
const r = options.root || 'auto';
|
|
36
|
+
const results: HTMLElement[] = [];
|
|
37
|
+
|
|
38
|
+
const applyRoot = (target: any) => {
|
|
39
|
+
if (!target) return;
|
|
40
|
+
if (r === 'auto') {
|
|
41
|
+
// Attributes belong to the ELEMENT, not the ShadowRoot.
|
|
42
|
+
// So for :host and direct attribute sync, we mostly want the element itself.
|
|
43
|
+
results.push(target);
|
|
44
|
+
} else {
|
|
45
|
+
if (r === 'light' || r === 'all') results.push(target);
|
|
46
|
+
if ((r === 'shadow' || r === 'all') && target.shadowRoot) results.push(target.shadowRoot);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
if (selector === ':host' || !selector) {
|
|
51
|
+
applyRoot(inst);
|
|
52
|
+
} else if (selector === ':window') {
|
|
53
|
+
results.push(currentWin);
|
|
54
|
+
} else if (selector === ':document') {
|
|
55
|
+
results.push(currentWin.document);
|
|
56
|
+
} else {
|
|
57
|
+
const hostSet = SwcUtils.getHostSet(inst);
|
|
58
|
+
if (selector === ':parentHost') applyRoot(hostSet.$parentHost);
|
|
59
|
+
else if (selector === ':appHost') applyRoot(hostSet.$appHost as any);
|
|
60
|
+
else if (selector === ':firstHost') applyRoot(hostSet.$firstHost);
|
|
61
|
+
else if (selector === ':lastHost') applyRoot(hostSet.$lastHost);
|
|
62
|
+
else if (selector === ':firstAppHost') applyRoot(hostSet.$firstAppHost as any);
|
|
63
|
+
else if (selector === ':lastAppHost') applyRoot(hostSet.$lastAppHost as any);
|
|
64
|
+
else {
|
|
65
|
+
if (r === 'shadow') {
|
|
66
|
+
const found = inst.shadowRoot?.querySelectorAll(selector);
|
|
67
|
+
if (found) results.push(...found);
|
|
68
|
+
} else if (r === 'light') {
|
|
69
|
+
const found = inst.querySelectorAll(selector);
|
|
70
|
+
if (found) results.push(...found);
|
|
71
|
+
} else if (r === 'all') {
|
|
72
|
+
const sMatch = inst.shadowRoot?.querySelectorAll(selector);
|
|
73
|
+
const lMatch = inst.querySelectorAll(selector);
|
|
74
|
+
if (sMatch) results.push(...sMatch);
|
|
75
|
+
if (lMatch) results.push(...lMatch);
|
|
76
|
+
} else {
|
|
77
|
+
const found = (inst.shadowRoot || inst).querySelectorAll(selector);
|
|
78
|
+
if (found) results.push(...found);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return results;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @attribute decorator to sync a field value with an element's attribute.
|
|
87
|
+
*/
|
|
88
|
+
export function attribute(selector: string, options: AttributeOptions = {}): PropertyDecorator {
|
|
89
|
+
return (target: Object, propertyKey: string | symbol) => {
|
|
90
|
+
const constructor = target.constructor;
|
|
91
|
+
const privateKey = Symbol(String(propertyKey));
|
|
92
|
+
|
|
93
|
+
const designType = (Reflect as any).getMetadata('design:type', target, propertyKey);
|
|
94
|
+
|
|
95
|
+
let metaList = ReflectUtils.getOwnMetadata(ATTRIBUTE_METADATA_KEY, constructor) as AttributeMetadata[];
|
|
96
|
+
if (!metaList) {
|
|
97
|
+
metaList = [];
|
|
98
|
+
ReflectUtils.defineMetadata(ATTRIBUTE_METADATA_KEY, metaList, constructor);
|
|
99
|
+
}
|
|
100
|
+
metaList.push({ propertyKey, selector, options, privateKey });
|
|
101
|
+
|
|
102
|
+
// Helper function to apply setAttribute to targets
|
|
103
|
+
const applySetAttribute = (inst: any, targets: HTMLElement[], attrName: string, nv: any) => {
|
|
104
|
+
targets.forEach(it => {
|
|
105
|
+
console.log('----->', it)
|
|
106
|
+
if (it && typeof (it as any).setAttribute === 'function') {
|
|
107
|
+
if (nv === null) {
|
|
108
|
+
(it as any).removeAttribute(attrName);
|
|
109
|
+
} else {
|
|
110
|
+
(it as any).setAttribute(attrName, String(nv));
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
inst[privateKey] = nv;
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
Object.defineProperty(target, propertyKey, {
|
|
119
|
+
get(this: any) {
|
|
120
|
+
const attrName = options.name || String(propertyKey);
|
|
121
|
+
const conf = getElementConfig(this);
|
|
122
|
+
const currentWin = this._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as any);
|
|
123
|
+
const targetType = options.type || designType;
|
|
124
|
+
|
|
125
|
+
console.log('type-->', propertyKey, targetType);
|
|
126
|
+
// During early init phase, if syncing memory to DOM, return memory.
|
|
127
|
+
if (this.__swc_syncing_init || (options.connectedInitialize && !this.__swc_connected)) {
|
|
128
|
+
return convertValue(this[privateKey], targetType);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const targets = resolveTargetEls(this, selector, options, currentWin);
|
|
132
|
+
const primaryTarget = targets[0];
|
|
133
|
+
|
|
134
|
+
if (primaryTarget && typeof (primaryTarget as any).hasAttribute === 'function') {
|
|
135
|
+
if ((primaryTarget as any).hasAttribute(attrName)) {
|
|
136
|
+
const domVal = (primaryTarget as any).getAttribute(attrName);
|
|
137
|
+
return convertValue(domVal, targetType);
|
|
138
|
+
}
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return convertValue(this[privateKey], targetType);
|
|
143
|
+
},
|
|
144
|
+
set(this: any, nv: any) {
|
|
145
|
+
const targetType = options.type || designType;
|
|
146
|
+
console.log('---set', propertyKey, targetType, nv, this, this.__swc_syncing_init);
|
|
147
|
+
|
|
148
|
+
const attrName = options.name || String(propertyKey);
|
|
149
|
+
const conf = getElementConfig(this);
|
|
150
|
+
const currentWin = this._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as any);
|
|
151
|
+
|
|
152
|
+
// During initialization/syncing phase
|
|
153
|
+
if (this.__swc_syncing_init) {
|
|
154
|
+
// If connectedInitialize is enabled, force setAttribute (JS -> DOM)
|
|
155
|
+
if (options.connectedInitialize === true) {
|
|
156
|
+
const targets = resolveTargetEls(this, selector, options, currentWin);
|
|
157
|
+
applySetAttribute(this, targets, attrName, nv);
|
|
158
|
+
} else {
|
|
159
|
+
// Otherwise just update memory
|
|
160
|
+
this[privateKey] = nv;
|
|
161
|
+
}
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Before connected, save to memory only
|
|
166
|
+
if (!this.__swc_connected) {
|
|
167
|
+
this[privateKey] = nv;
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// After connected, normal setAttribute
|
|
172
|
+
const targets = resolveTargetEls(this, selector, options, currentWin);
|
|
173
|
+
applySetAttribute(this, targets, attrName, nv);
|
|
174
|
+
},
|
|
175
|
+
enumerable: true,
|
|
176
|
+
configurable: true
|
|
177
|
+
});
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export const findAllAttributeMetadata = (target: any): AttributeMetadata[] => {
|
|
182
|
+
return ReflectUtils.findAllMetadata<AttributeMetadata[]>(ATTRIBUTE_METADATA_KEY, target).flat();
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* @hostAttribute decorator - simplified version of @attribute for :host selector
|
|
187
|
+
* Usage: @hostAttribute('data-product-id')
|
|
188
|
+
* Usage: @hostAttribute('disabled', { type: Boolean })
|
|
189
|
+
*/
|
|
190
|
+
export function attributeHost(attrName: string, options: AttributeOptions = {}): PropertyDecorator {
|
|
191
|
+
return attribute(':host', { ...options, name: attrName });
|
|
192
|
+
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import { ReflectUtils } from '@dooboostore/core
|
|
1
|
+
import { ReflectUtils } from '@dooboostore/core';
|
|
2
2
|
|
|
3
3
|
export const ON_ATTRIBUTE_CHANGED_METADATA_KEY = Symbol('simple-web-component:on-attribute-changed');
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* @changedAttributeHost decorator - fires when any attribute on :host changes
|
|
7
|
+
* Usage: @changedAttributeHost('data-product-id')
|
|
8
|
+
*/
|
|
9
|
+
export function changedAttributeHost(attributeName?: string): MethodDecorator {
|
|
6
10
|
return (target: Object, propertyKey: string | symbol) => {
|
|
7
11
|
const constructor = target.constructor;
|
|
8
12
|
let meta = ReflectUtils.getOwnMetadata(ON_ATTRIBUTE_CHANGED_METADATA_KEY, constructor) as Map<string, (string | symbol)[]>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ReflectUtils } from '@dooboostore/core
|
|
1
|
+
import { ReflectUtils } from '@dooboostore/core';
|
|
2
2
|
import { ensureInit } from './elementDefine';
|
|
3
3
|
import { SwcUtils } from '../utils/Utils';
|
|
4
4
|
|
|
@@ -105,6 +105,38 @@ export const removeClassList = createClassListDecorator('remove');
|
|
|
105
105
|
*/
|
|
106
106
|
export const toggleClassList = createClassListDecorator('toggle');
|
|
107
107
|
|
|
108
|
+
// Host-specific versions (for :host selector)
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @setClassListHost decorator to set classes on :host element.
|
|
112
|
+
* Returns: string | string[]
|
|
113
|
+
*/
|
|
114
|
+
export const setClassListHost = createClassListDecorator('set').bind(null, ':host');
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* @updateClassListHost decorator to update specific classes on :host.
|
|
118
|
+
* Returns: Record<string, boolean> (toggle with force) | string | string[] (add)
|
|
119
|
+
*/
|
|
120
|
+
export const updateClassListHost = createClassListDecorator('update').bind(null, ':host');
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @addClassListHost decorator to add classes to :host element.
|
|
124
|
+
* Returns: string | string[]
|
|
125
|
+
*/
|
|
126
|
+
export const addClassListHost = createClassListDecorator('add').bind(null, ':host');
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* @removeClassListHost decorator to remove classes from :host element.
|
|
130
|
+
* Returns: string | string[]
|
|
131
|
+
*/
|
|
132
|
+
export const removeClassListHost = createClassListDecorator('remove').bind(null, ':host');
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* @toggleClassListHost decorator to toggle classes on :host element.
|
|
136
|
+
* Returns: string | string[]
|
|
137
|
+
*/
|
|
138
|
+
export const toggleClassListHost = createClassListDecorator('toggle').bind(null, ':host');
|
|
139
|
+
|
|
108
140
|
export const findAllClassListMetadata = (target: any): Map<string | symbol, ClassListMetadata> => {
|
|
109
141
|
const result = new Map<string | symbol, ClassListMetadata>();
|
|
110
142
|
const maps = ReflectUtils.findAllMetadata<Map<string | symbol, ClassListMetadata>>(CLASS_LIST_METADATA_KEY, target);
|